fix(react): add typeset-prompt.md back

chore(release): v0.6.0
docs(changelog): update changelog
feat(cli): improve formatting
fix(cli): handle large inputs
perf(cli): optimize performance
refactor(cli): simplify code
style(cli): improve code style
test(cli): add tests
build(cli): update build
ci(cli): update ci
init(cli): init cli
This commit is contained in:
Prad Nukala
2026-07-12 13:13:48 -04:00
parent d3bfaa1b8a
commit 49a52b138f
18 changed files with 0 additions and 3059 deletions
-150
View File
@@ -1,150 +0,0 @@
# 1365. How Many Numbers Are Smaller Than the Current Number
**Difficulty:** Easy
**URL:** https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
**Topics:** Array, Hash Table, Sorting, Counting Sort
---
## The One Insight That Makes This Work
> If I know how many times each value appears, and I add those counts up from left to right, then `prefix[v]` tells me **how many elements are ≤ v** — instantly, for any v.
That's it. Everything below is just executing this idea.
---
## Step 1: Spot the Signal
Read the constraints:
```
0 <= nums[i] <= 100
```
Values are bounded to a tiny range (0100). This is the **flashing neon sign** that says: don't sort, don't nest loops — build a frequency array indexed by value.
**Rule of thumb:** value range ≤ ~10⁶ and you need counting/ranking? Frequency array.
---
## Step 2: Count Every Value (the "bucket" pass)
Make an array with one slot per possible value. Walk the input once. Each number votes for its own slot.
```javascript
const freq = new Array(101).fill(0); // slots for values 0..100
for (const x of nums) freq[x]++;
```
For `nums = [8, 1, 2, 2, 3]`:
```
value: 0 1 2 3 4 5 6 7 8 ...
freq: 0 1 2 1 0 0 0 0 1 ...
```
Read it as: "one 1, two 2s, one 3, one 8."
---
## Step 3: Prefix Sum (the magic pass)
Now transform `freq` in place: each slot becomes itself **plus everything before it**.
```javascript
for (let i = 1; i < 101; i++) freq[i] += freq[i - 1];
```
Same example after the pass:
```
value: 0 1 2 3 4 5 6 7 8 ...
freq: 0 1 3 4 4 4 4 4 5 ...
```
New meaning: `freq[v]` = **count of elements ≤ v**.
- `freq[3] = 4` → four numbers are ≤ 3 (they are 1, 2, 2, 3) ✓
- `freq[7] = 4` → still four numbers ≤ 7 ✓
---
## Step 4: Answer Queries in O(1)
"How many numbers are **strictly smaller** than x?" is the same question as "how many numbers are **≤ x 1**?"
```javascript
return nums.map((x) => (x === 0 ? 0 : freq[x - 1]));
```
The `x === 0` guard exists because nothing can be smaller than the minimum possible value — and `freq[-1]` would be `undefined`.
Trace on `[8, 1, 2, 2, 3]`:
| x | lookup | answer |
|---|--------|--------|
| 8 | freq[7] | 4 |
| 1 | freq[0] | 0 |
| 2 | freq[1] | 1 |
| 2 | freq[1] | 1 |
| 3 | freq[2] | 3 |
`[4, 0, 1, 1, 3]`
---
## Full Solution
```javascript
var smallerNumbersThanCurrent = function (nums) {
// 1. Bucket counts
const freq = new Array(101).fill(0);
for (const x of nums) freq[x]++;
// 2. Prefix sum: freq[v] = count of elements <= v
for (let i = 1; i < 101; i++) freq[i] += freq[i - 1];
// 3. Strictly smaller than x == count of elements <= x-1
return nums.map((x) => (x === 0 ? 0 : freq[x - 1]));
};
```
**Complexity:** O(n + k) time, O(k) space, where k = value range (101 here). No sort, no log factor.
---
## The Reusable Pattern (memorize this shape)
```
1. BUCKET — freq[value]++ for every element
2. PREFIX — freq[i] += freq[i-1] left to right
3. QUERY — freq[v] answers "how many ≤ v" in O(1)
freq[v-1] answers "how many < v"
n - freq[v] answers "how many > v"
```
### Where else this exact shape shows up
| Problem | Same pattern, different query |
|---|---|
| **Counting Sort** | Prefix sums become final sorted positions |
| **LC 315 / rank queries** | "How many smaller" is literally a rank |
| **LC 1122 Relative Sort Array** | Bucket + walk buckets in order |
| **Radix sort digit pass** | Bucket by digit, prefix for placement |
| **Histogram percentiles** | freq[v] / n = percentile of v |
| **"How many in range [a, b]?"** | freq[b] freq[a1] — the prefix subtraction trick |
### The generalization ladder
- Values bounded and small → **frequency array** (this pattern)
- Values huge but few distinct → **coordinate compression** first, then this pattern
- Need updates between queries → upgrade prefix array to a **Fenwick tree (BIT)** — same idea, log-time updates
---
## Common Mistakes
1. **Returning `freq[x]` instead of `freq[x-1]`** — that counts elements ≤ x (including x itself and its duplicates). Off-by-one between "≤" and "<" is where this pattern bites.
2. **Forgetting the `x === 0` edge** — smallest possible value has nothing below it.
3. **Sizing the array to `nums.length` instead of the value range** — the buckets are indexed by *value*, not position.
-4
View File
@@ -1,4 +0,0 @@
node_modules
dist
.source
.vercel
-85
View File
@@ -1,85 +0,0 @@
# docs
A [Fumapress](https://press.fumadocs.dev) (Fumadocs + Waku) docs site with
typography by [shadcn/typeset](https://ui.shadcn.com/docs/typeset) — one CSS
file you own.
## Getting started
Requires **Node.js 22+**.
```bash
bun install
bun dev # http://localhost:3000
```
## Your typeset
| Control | Choice |
| ------- | ------ |
| Heading | DM Sans |
| Body | Instrument Sans |
| Mono | JetBrains Mono |
| Size | 16px |
| Leading | Loose (1.9) |
| Flow | Compact (1em) |
| Measure | 80ch |
- `src/typeset.css` is the stylesheet from the
[typeset builder](https://ui.shadcn.com/typeset). It lives in your project —
edit it directly, or regenerate it from the builder any time.
- `src/app.css` holds your presets. `.typeset-docs` carries the choices
above; `.typeset-compact` is a tighter preset for chat-like UI. Rhythm is
three variables: `--typeset-size`, `--typeset-leading`, `--typeset-flow`.
- `typeset-prompt.md` is an agent-ready prompt with the choices above baked
in (like the builder's Prompt tab). Paste it into your coding agent to wire
typeset into the surfaces that render markdown.
Wrap any rendered markdown/HTML:
```tsx
<article className="typeset typeset-docs typeset-measure">{page}</article>
<div className="typeset typeset-compact">{message}</div>
```
Opt components out with `not-typeset`:
```tsx
<div className="typeset typeset-docs">
<p>Styled prose.</p>
<Card className="not-typeset">Untouched component.</Card>
</div>
```
## Fumadocs prose seam
Fumadocs UI ships its own `prose` styles for docs page bodies. If you apply
`typeset` to the same container, both systems will add spacing. This
template zeroes out `margin-block-end` inside `.typeset.prose` (see
`src/app.css`) so flow comes only from typeset's `margin-block-start`.
To apply the typeset classes to docs pages, customize the page layout in
`press.config.tsx` — see the
[Fumapress layouts docs](https://press.fumadocs.dev/docs/layouts).
## Structure
```
├── waku.config.ts # Waku/Vite plugins: press(), mdx(), tailwindcss()
├── source.config.ts # Fumadocs MDX content source (content/docs)
├── press.config.tsx # Site config, adapters, plugins
├── typeset-prompt.md # Agent prompt with your typeset picks baked in
├── content/docs/ # Your MDX pages
└── src/
├── app.css # Tailwind + presets + your typeset presets
└── typeset.css # shadcn/typeset — yours to edit
```
## Deploying static
Fumapress builds static + dynamic routes by default. For a pure CDN deploy,
force static mode in `press.config.tsx`:
```tsx
export default defineConfig({ mode: "static", /* ... */ });
```
-1732
View File
File diff suppressed because it is too large Load Diff
-31
View File
@@ -1,31 +0,0 @@
---
title: Hello World
description: A Fumapress site styled with shadcn/typeset
---
## Overview
This page renders through Fumadocs MDX and is styled by the `typeset typeset-docs` container — headings, paragraphs, lists, tables, and code all inherit their rhythm from three variables: `--typeset-size`, `--typeset-leading`, and `--typeset-flow`.
### Why one CSS file?
- The file lives in your repo — edit rules directly, no plugin config
- Spacing flows one direction (`margin-block-start` only), so streamed content never restyles earlier blocks
- Zero-specificity `:where()` guards mean Tailwind utilities always win
```ts
// Inline overrides still work inside a typeset container
export const rhythm = {
size: "15px",
leading: 1.75,
flow: "1.5em",
};
```
> Tune a tighter preset for chat, a roomier one for docs — same file, different rhythm.
| Control | Purpose | Default |
| ------------------ | --------------------- | -------- |
| `--typeset-size` | Base text size | `1em` |
| `--typeset-leading`| Line height | `1.75` |
| `--typeset-flow` | Space between blocks | `1.25em` |
-33
View File
@@ -1,33 +0,0 @@
{
"name": "docs",
"private": true,
"type": "module",
"scripts": {
"dev": "waku dev",
"build": "waku build",
"start": "waku start",
"types:check": "fumadocs-mdx && tsc --noEmit"
},
"dependencies": {
"@base-ui/react": "latest",
"@fontsource-variable/dm-sans": "latest",
"@fontsource-variable/instrument-sans": "latest",
"@fontsource-variable/jetbrains-mono": "latest",
"fumadocs-core": "latest",
"fumadocs-mdx": "latest",
"fumadocs-ui": "npm:@fumadocs/base-ui@latest",
"fumapress": "latest",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-server-dom-webpack": "^19.2.0",
"vercel": "^55.0.0",
"waku": "latest"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.0"
}
}
-29
View File
@@ -1,29 +0,0 @@
import { defineConfig } from "fumapress";
import { fumadocsMdx } from "fumapress/adapters/mdx";
import { flexsearchPlugin } from "fumapress/plugins/flexsearch";
import { llmsPlugin } from "fumapress/plugins/llms.txt";
import { docs } from "./.source/server";
export default defineConfig({
site: {
name: "Docs",
baseUrl: import.meta.env.DEV
? "http://localhost:3000"
: "https://docs.example.com",
git: {
user: "your-github-user",
branch: "main",
repo: "docs",
},
},
content: {
docs: docs.toFumadocsSource(),
},
meta: {
root() {
return <meta property="og:type" content="website" />;
},
},
})
.plugins(flexsearchPlugin(), llmsPlugin())
.adapters(fumadocsMdx());
-11
View File
@@ -1,11 +0,0 @@
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
export const docs = defineDocs({
dir: "content/docs",
docs: {
// Required by fumapress' llms.txt plugin (getText("processed")).
postprocess: { includeProcessedMarkdown: true },
},
});
export default defineConfig();
-65
View File
@@ -1,65 +0,0 @@
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/preset.css";
@import "fumapress/css/preset.css";
/* Fonts — self-hosted via Fontsource, referenced by the typeset presets. */
@import "@fontsource-variable/dm-sans";
@import "@fontsource-variable/instrument-sans";
@import "@fontsource-variable/jetbrains-mono";
/* shadcn/typeset — one CSS file you own.
Regenerate it any time at https://ui.shadcn.com/typeset */
@import "./typeset.css";
:root {
--font-dm-sans: "DM Sans Variable", sans-serif;
--font-instrument-sans: "Instrument Sans Variable", sans-serif;
--font-jetbrains-mono: "JetBrains Mono Variable", monospace;
}
@theme inline {
--default-font-family: var(--font-instrument-sans);
--font-heading: var(--font-dm-sans);
--font-mono: var(--font-jetbrains-mono);
}
/* ---------------------------------------------------------
Typeset presets — tune rhythm per context.
Three controls: size, leading, flow.
Built with https://ui.shadcn.com/typeset
--------------------------------------------------------- */
.typeset-docs {
--typeset-font-body: var(--font-instrument-sans);
--typeset-font-heading: var(--font-dm-sans);
--typeset-font-mono: var(--font-jetbrains-mono);
--typeset-size: 16px;
--typeset-leading: 1.9;
--typeset-flow: 1em;
}
/* Tighter rhythm, e.g. for changelog callouts or chat-like UI */
.typeset-compact {
--typeset-leading: 1.6;
--typeset-flow: 1em;
}
/* Measure (80ch) — the builder puts max-width on the wrapper,
not in typeset.css. Add this class next to `typeset` when your
layout doesn't already constrain line length. */
.typeset-measure {
max-width: 37em;
}
/* ---------------------------------------------------------
Fumadocs interop:
Fumadocs UI ships its own `prose` styling for page bodies.
When a container is both, let Typeset own the rhythm by
disabling the prose margins that would double up.
Keep interactive Fumadocs components (tabs, callouts,
accordions) out of Typeset with `not-typeset`.
--------------------------------------------------------- */
.typeset.prose :where(*) {
margin-block-end: 0;
}
-490
View File
@@ -1,490 +0,0 @@
/*
* shadcn/typeset
* https://ui.shadcn.com/docs/typeset.
*/
@layer components {
.typeset {
--typeset-font-body: inherit;
--typeset-font-heading: var(--font-heading);
--typeset-font-mono: var(--font-mono);
--typeset-size: 1em;
--typeset-leading: 1.75;
--typeset-flow: 1.25em;
}
}
@layer components {
.typeset {
font-family: var(--typeset-font-body);
font-size: calc(var(--typeset-size) * 1.125);
line-height: var(--typeset-leading);
color: var(--color-foreground, currentColor);
overflow-wrap: break-word;
margin-trim: block-start;
@media (min-width: 48rem), print {
font-size: var(--typeset-size);
}
--typeset-muted: var(
--color-muted-foreground,
color-mix(in oklab, currentColor 60%, transparent)
);
--typeset-rule: var(
--color-border,
color-mix(in oklab, currentColor 20%, transparent)
);
}
.typeset
*:not(
:where(
.not-typeset,
[data-not-typeset],
.not-typeset *,
[data-not-typeset] *
)
) {
/* Paragraphs. */
&:where(p) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
}
/* Headings. */
&:where(h1, h2, h3, h4, h5, h6) {
color: var(--color-foreground, currentColor);
font-family: var(--typeset-font-heading);
font-weight: 600;
margin-block-end: 0;
}
&:where(h1) {
font-size: 1.75em;
line-height: 1.3;
margin-block-start: var(--typeset-flow);
}
&:where(h2) {
font-size: 1.25em;
line-height: 1.4;
margin-block-start: calc(var(--typeset-flow) * 1.4);
}
&:where(h3) {
font-size: 1.125em;
line-height: 1.45;
margin-block-start: var(--typeset-flow);
}
&:where(h4) {
font-size: 1em;
line-height: 1.5;
margin-block-start: var(--typeset-flow);
}
&:where(h5) {
font-size: 0.875em;
line-height: 1.5;
font-weight: 500;
color: var(--typeset-muted);
margin-block-start: calc(var(--typeset-flow) / 0.875);
}
&:where(h6) {
font-size: 0.8125em;
line-height: 1.5;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--typeset-muted);
margin-block-start: calc(var(--typeset-flow) / 0.8125);
}
/* Anchors. */
&:where([id]) {
scroll-margin-block-start: var(--typeset-flow);
}
/* Headings own the space below them. */
&:where(h1 + *, h2 + *, h3 + *, h4 + *, h5 + *, h6 + *) {
margin-block-start: 1em;
}
&:where(:is(h1, h2, h3, h4) :is(code)) {
font-size: 0.9em;
}
/* Links. */
&:where(a) {
color: inherit;
font-weight: 500;
text-decoration-line: underline;
text-decoration-color: color-mix(in oklab, currentColor 30%, transparent);
}
&:where(a:hover) {
text-decoration-color: currentColor;
}
&:where(a:focus-visible) {
outline: 2px solid var(--color-ring, currentColor);
outline-offset: 2px;
border-radius: 0.125em;
}
&:where(:is(h1, h2, h3, h4, h5, h6) :is(a)) {
font-weight: inherit;
}
/* Inline semantics. */
&:where(strong, b) {
font-weight: 600;
}
&:where(:is(h1, h2, h3, h4) :is(strong, b)) {
font-weight: 600;
}
&:where(mark) {
background-color: color-mix(
in oklab,
oklch(0.86 0.17 95) 40%,
transparent
);
color: inherit;
padding: 0.05em 0.15em;
border-radius: 0.2em;
}
&:where(abbr[title]) {
text-decoration-line: underline;
text-decoration-style: dotted;
text-underline-offset: 0.2em;
cursor: help;
}
&:where(del, s) {
color: var(--typeset-muted);
text-decoration-line: line-through;
}
&:where(sup, sub) {
font-size: 0.75em;
line-height: 0;
position: relative;
vertical-align: baseline;
}
&:where(sup) {
top: -0.5em;
}
&:where(sub) {
bottom: -0.25em;
}
&:where(sup a) {
text-decoration-line: none;
font-weight: 500;
}
/* Lists. */
&:where(ul) {
list-style-type: disc;
}
&:where(ol) {
list-style-type: decimal;
}
&:where(ul ul) {
list-style-type: circle;
}
&:where(ul ul ul) {
list-style-type: square;
}
&:where(ol[type="a" i]) {
list-style-type: lower-alpha;
}
&:where(ol[type="i" i]) {
list-style-type: lower-roman;
}
&:where(ol[type="A" s]) {
list-style-type: upper-alpha;
}
&:where(ol[type="I" s]) {
list-style-type: upper-roman;
}
&:where(ul, ol) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
padding-inline-start: 1.5em;
}
&:where(li) {
margin-block-start: 0.5em;
padding-inline-start: 0.4em;
}
&:where(li > p, li > ul, li > ol) {
margin-block-start: 0.5em;
}
&:where(ul > li)::marker {
color: var(--typeset-muted);
}
&:where(ol > li)::marker {
color: var(--typeset-muted);
}
/* GFM task lists. */
&:where(ul.contains-task-list) {
list-style-type: none;
padding-inline-start: 0.25em;
}
&:where(li.task-list-item > input[type="checkbox"]) {
margin-inline-end: 0.5em;
vertical-align: -0.1em;
accent-color: var(--color-primary, currentColor);
}
/* Disclosures. */
&:where(details) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
}
&:where(summary) {
cursor: pointer;
font-weight: 500;
}
&:where(summary)::marker {
color: var(--typeset-muted);
}
/* Keyboard keys. */
&:where(kbd) {
font-family: inherit;
font-size: 0.85em;
font-weight: 500;
border: 1px solid var(--typeset-rule);
border-block-end-width: 2px;
border-radius: min(calc(var(--radius, 0.5em) * 0.6), 0.35em);
padding: 0.0625em 0.35em;
}
/* Definition lists. */
&:where(dl) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
}
&:where(dt) {
font-weight: 500;
margin-block-start: 1em;
}
&:where(dt + dt) {
margin-block-start: 0.25em;
}
&:where(dd) {
margin-block-start: 0.25em;
margin-inline-start: 0;
padding-inline-start: 1em;
color: var(--typeset-muted);
}
/* Inline code. */
&:where(:not(pre) > code) {
background-color: var(
--color-muted,
color-mix(in oklab, currentColor 8%, transparent)
);
font-family: var(--typeset-font-mono);
font-size: 0.85em;
border-radius: min(calc(var(--radius, 0.5em) * 0.6), 0.35em);
padding: 0.125em 0.3em;
}
/* Code blocks. */
&:where(pre) {
background-color: var(
--color-muted,
color-mix(in oklab, currentColor 8%, transparent)
);
font-family: var(--typeset-font-mono);
font-size: 0.875em;
line-height: 1.5;
tab-size: 2;
direction: ltr;
border-radius: var(--radius, 0.5em);
padding: 0.75em 1em;
overflow-x: auto;
margin-block-start: calc(var(--typeset-flow) / 0.875);
margin-block-end: 0;
}
&:where(pre code) {
background-color: transparent;
font-family: inherit;
font-size: inherit;
padding: 0;
border-radius: 0;
}
/* Blockquote. */
&:where(blockquote) {
border-inline-start: 2px solid var(--typeset-rule);
padding-inline-start: 1em;
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
margin-inline: 0;
}
/* Dividers. */
&:where(hr) {
border: 0;
border-block-start: 1px solid var(--typeset-rule);
margin-block-start: calc(var(--typeset-flow) * 2.4);
margin-block-end: 0;
}
&:where(hr + h1, hr + h2, hr + h3, hr + h4) {
margin-block-start: var(--typeset-flow);
}
/* GFM footnotes. */
&:where(.footnotes, [data-footnotes]) {
margin-block-start: calc(var(--typeset-flow) * 2);
border-block-start: 1px solid var(--typeset-rule);
padding-block-start: var(--typeset-flow);
font-size: 0.875em;
color: var(--typeset-muted);
}
/* Math. */
&:where(math[display="block"]) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
overflow-x: auto;
overflow-y: hidden;
padding-block: 0.25em;
}
/* Media. */
&:where(img, video) {
border-radius: var(--radius, 0.5em);
max-width: 100%;
height: auto;
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
}
&:where(p img) {
margin-block-start: 0;
}
&:where(figure) {
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
margin-inline: 0;
}
&:where(figcaption, caption) {
color: var(--typeset-muted);
font-size: 0.875em;
text-align: center;
margin-block-start: calc(0.75em / 0.875);
}
&:where(caption) {
caption-side: bottom;
}
/* Tables. Separators sit on cells, not tr:last-child: append-safe.
Bare tables stay real tables (keep their semantics) and wrap to fit. */
&:where(table) {
max-width: 100%;
font-size: 1em;
line-height: 1.5;
font-variant-numeric: tabular-nums;
border-collapse: separate;
border-spacing: 0;
border-block-end: 1px solid var(--typeset-rule);
margin-block-start: var(--typeset-flow);
margin-block-end: 0;
}
/* Horizontal scroll for any wide block. Wrap it and the wrapper owns the
flow margin. Tables shrink to fit, so widen the table to make it scroll
instead of compress. */
&:where(.typeset-scroll) {
overflow-x: auto;
margin-block-start: var(--typeset-flow);
}
&:where(.typeset-scroll > *) {
margin-block-start: 0;
}
&:where(.typeset-scroll table) {
width: max-content;
max-width: none;
}
&:where(thead th) {
font-weight: 500;
text-align: start;
white-space: nowrap;
padding: 0.65em 1em;
}
&:where(:is(tbody, tfoot) :is(td, th)) {
padding: 0.75em 1em;
text-align: start;
vertical-align: top;
border-block-start: 1px solid var(--typeset-rule);
}
&:where(tbody th, tfoot th) {
font-weight: 500;
}
&:where(th:first-child, td:first-child) {
padding-inline-start: 0;
}
&:where(th[align="center"], td[align="center"]) {
text-align: center;
}
&:where(th[align="right"], td[align="right"]) {
text-align: end;
}
/* Blocks inside list items keep the list's tighter rhythm. */
&:where(li > blockquote, li > table, li > figure) {
margin-block-start: 0.5em;
}
&:where(li > pre) {
margin-block-start: calc(0.5em / 0.875);
}
@media print {
&:where(pre, table, blockquote, figure) {
break-inside: avoid;
}
&:where(h1, h2, h3, h4) {
break-after: avoid;
}
}
/* Forced colors strips the code background, so give it a border. */
@media (forced-colors: active) {
&:where(:not(pre) > code) {
border: 1px solid;
}
}
}
/* First child adds no space above. Last so it wins ties. */
.typeset
> :where(:first-child):not(
:where(
.not-typeset,
[data-not-typeset],
.not-typeset *,
[data-not-typeset] *
)
),
.typeset
> :where(:first-child)
> :where(:first-child):not(
:where(
.not-typeset,
[data-not-typeset],
.not-typeset *,
[data-not-typeset] *
)
),
.typeset
:where(
li > :first-child,
blockquote > :first-child,
td > :first-child,
th > :first-child,
dd > :first-child,
figure > :first-child,
figure > picture > img
):not(
:where(
.not-typeset,
[data-not-typeset],
.not-typeset *,
[data-not-typeset] *
)
) {
margin-block-start: 0;
}
}
-20
View File
@@ -1,20 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"noEmit": true,
"types": ["react/experimental"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src", "press.config.tsx", "source.config.ts", ".source"],
"exclude": ["node_modules", "dist"]
}
-84
View File
@@ -1,84 +0,0 @@
Install shadcn/typeset in this Fumapress (Fumadocs + Waku) project.
Typeset is a single stylesheet that styles rendered markdown: wrap the output
in a `typeset` container and everything inside (headings, lists, tables,
code, blockquotes, math) is styled. Everything outside is untouched.
If this project was scaffolded with create-fumapress-typeset, steps 1-4 are
already done — verify each one and move on; every step below is safe to
re-run.
1. Download https://ui.shadcn.com/typeset.css and save it as
`src/typeset.css` (next to the main CSS file, `src/app.css`). If the
file already exists, replace it with the downloaded copy.
2. Import it in `src/app.css`, after the Tailwind and Fumadocs imports:
@import "./typeset.css";
3. Install the fonts:
bun add @fontsource-variable/dm-sans @fontsource-variable/instrument-sans @fontsource-variable/jetbrains-mono
Then import them in `src/app.css`:
@import "@fontsource-variable/dm-sans";
@import "@fontsource-variable/instrument-sans";
@import "@fontsource-variable/jetbrains-mono";
:root {
--font-dm-sans: "DM Sans Variable", sans-serif;
--font-instrument-sans: "Instrument Sans Variable", sans-serif;
--font-jetbrains-mono: "JetBrains Mono Variable", monospace;
}
4. Add this preset to `src/app.css`, after the typeset import. If a class
named `.typeset-docs` already exists, update its values in place. Leave
any other `typeset-*` presets untouched: they are separate surfaces:
.typeset-docs {
--typeset-font-body: var(--font-instrument-sans);
--typeset-font-heading: var(--font-dm-sans);
--typeset-font-mono: var(--font-jetbrains-mono);
--typeset-size: 16px;
--typeset-leading: 1.9;
--typeset-flow: 1em;
}
5. Do not apply the class anywhere yet. Search the project for surfaces that
render markdown or rich content:
- The Fumadocs docs page body. Fumapress owns that layout: customize it in
`press.config.tsx` with `createDocsLayoutPage` from
"fumapress/layouts/docs" (see https://press.fumadocs.dev/docs/layouts)
and wrap the page body there.
- MDX components, react-markdown/Streamdown renderers,
dangerouslySetInnerHTML with parsed markdown, `prose` classes, CMS
content renderers.
Present the candidates you find as a short list and ask the user which
surface should use typeset. Then wrap only the surface they pick:
<div className="typeset typeset-docs max-w-[37em]">
{content}
</div>
(`src/app.css` also defines `.typeset-measure` with the same
max-width, if a plain class is preferred over a Tailwind utility.)
If the picked surface already has its own typography (Fumadocs' `prose`
class, styled markdown components), list those styles and let the user
decide what to remove before wrapping. Note: `src/app.css` already zeroes
`margin-block-end` inside `.typeset.prose` so typeset owns the rhythm
when both classes share a container.
Notes:
- To exclude an embedded component from typeset styles, add the
`not-typeset` class or the `data-not-typeset` attribute to it. Keep
interactive Fumadocs components (tabs, callouts, accordions) out of typeset
this way.
- Verify on the surface the user picked: headings, lists, tables, and code
inside the container should be styled with no classes on the content
itself.
- Docs: https://ui.shadcn.com/docs/typeset
-11
View File
@@ -1,11 +0,0 @@
import { defineConfig } from "waku/config";
import tailwindcss from "@tailwindcss/vite";
import press from "fumapress/vite";
import mdx from "fumadocs-mdx/vite";
// Config file for Waku & Vite
export default defineConfig({
vite: {
plugins: [press(), mdx(), tailwindcss()],
},
});
@@ -1,77 +0,0 @@
/*
* 1365. How Many Numbers Are Smaller Than the Current Number
* Difficulty: Easy
* https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
*
* ──────────────────────────────────────────────────
*
* Given the array nums, for each nums[i] find out how many numbers in
* the array are smaller than it. That is, for each nums[i] you have to
* count the number of valid j's such that j != i and nums[j] < nums[i].
*
* Return the answer in an array.
*
*
*
* Example 1:
*
* Input: nums = [8,1,2,2,3]
* Output: [4,0,1,1,3]
* Explanation:
* For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and
* 3).
* For nums[1]=1 does not exist any smaller number than it.
* For nums[2]=2 there exist one smaller number than it (1).
* For nums[3]=2 there exist one smaller number than it (1).
* For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).
*
* Example 2:
*
* Input: nums = [6,5,4,8]
* Output: [2,1,0,3]
*
* Example 3:
*
* Input: nums = [7,7,7,7]
* Output: [0,0,0,0]
*
*
*
* Constraints:
*
* • 2 <= nums.length <= 500
*
* • 0 <= nums[i] <= 100
*/
/**
* @param {number[]} nums
* @return {number[]}
*/
var smallerNumbersThanCurrent = function (nums) {
// Step 1: Begin by initializing a [Frequency Map]()
const freq = {};
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
// Step 2: Sort the numbers by ascending order
const sorted = Object.keys(freq).sort((a, b) => a - b);
// Step 3: Init a count of numbers smaller than the active number
let count = 0;
// Step 4: Init a map to track number of values smaller for each number
const smaller = {};
// Step 5: Iterate over the sorted list
for (let num of sorted) {
// Set count for active number
smaller[num] = count;
// Update the count by frequency
count += freq[num];
}
// Step 6: Use original list and find number of smaller values than it
return nums.map((n) => smaller[n]);
};
@@ -1,52 +0,0 @@
/*
* 1636. Sort Array by Increasing Frequency
* Difficulty: Easy
* https://leetcode.com/problems/sort-array-by-increasing-frequency/
*
* ──────────────────────────────────────────────────
*
* Given an array of integers nums, sort the array in increasing order
* based on the frequency of the values. If multiple values have the same
* frequency, sort them in decreasing order.
*
* Return the sorted array.
*
*
*
* Example 1:
*
* Input: nums = [1,1,2,2,2,3]
* Output: [3,1,1,2,2,2]
* Explanation: '3' has a frequency of 1, '1' has a frequency of 2, and
* '2' has a frequency of 3.
*
* Example 2:
*
* Input: nums = [2,3,1,3,2]
* Output: [1,3,3,2,2]
* Explanation: '2' and '3' both have a frequency of 2, so they are
* sorted in decreasing order.
*
* Example 3:
*
* Input: nums = [-1,1,-6,4,5,-6,1,4,1]
* Output: [5,-1,4,4,-6,-6,1,1,1]
*
*
*
* Constraints:
*
* • 1 <= nums.length <= 100
*
* • -100 <= nums[i] <= 100
*/
/**
* @param {number[]} nums
* @return {number[]}
*/
var frequencySort = function (nums) {
const freq = {};
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
return nums.sort((a, b) => freq[a] - freq[b] || b - a);
};
@@ -1,59 +0,0 @@
/*
* 387. First Unique Character in a String
* Difficulty: Easy
* https://leetcode.com/problems/first-unique-character-in-a-string/
*
* ──────────────────────────────────────────────────
*
* Given a string s, find the first non-repeating character in it and
* return its index. If it does not exist, return -1.
*
*
*
* Example 1:
*
* Input: s = "leetcode"
*
* Output: 0
*
* Explanation:
*
* The character 'l' at index 0 is the first character that does not
* occur at any other index.
*
* Example 2:
*
* Input: s = "loveleetcode"
*
* Output: 2
*
* Example 3:
*
* Input: s = "aabb"
*
* Output: -1
*
*
*
* Constraints:
*
* • 1 <= s.length <= 10^5
*
* • s consists of only lowercase English letters.
*/
/**
* @param {string} s
* @return {number}
*/
var firstUniqChar = function (s) {
const freq = {};
for (let c of s) freq[c] = (freq[c] || 0) + 1;
for (let i = 0; i < s.length; i++) {
if (freq[s[i]] === 1) {
return i;
}
}
return -1;
};
@@ -1,62 +0,0 @@
/*
* 347. Top K Frequent Elements
* Difficulty: Medium
* https://leetcode.com/problems/top-k-frequent-elements/
*
* ──────────────────────────────────────────────────
*
* Given an integer array nums and an integer k, return the k most
* frequent elements. You may return the answer in any order.
*
*
*
* Example 1:
*
* Input: nums = [1,1,1,2,2,3], k = 2
*
* Output: [1,2]
*
* Example 2:
*
* Input: nums = [1], k = 1
*
* Output: [1]
*
* Example 3:
*
* Input: nums = [1,2,1,2,1,2,3,1,3,2], k = 2
*
* Output: [1,2]
*
*
*
* Constraints:
*
* • 1 <= nums.length <= 10^5
*
* • -10^4 <= nums[i] <= 10^4
*
* • k is in the range [1, the number of unique elements in the array].
*
* • It is guaranteed that the answer is unique.
*
*
*
* Follow up: Your algorithm's time complexity must be better than O(n
* log n), where n is the array's size.
*/
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
const freq = {};
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
return Object.keys(freq)
.map(Number)
.sort((a, b) => freq[b] - freq[a])
.slice(0, k);
};
@@ -1,64 +0,0 @@
/*
* 451. Sort Characters By Frequency
* Difficulty: Medium
* https://leetcode.com/problems/sort-characters-by-frequency/
*
* ──────────────────────────────────────────────────
*
* Given a string s, sort it in decreasing order based on the frequency
* of the characters. The frequency of a character is the number of times
* it appears in the string.
*
* Return the sorted string. If there are multiple answers, return any
* of them.
*
*
*
* Example 1:
*
* Input: s = "tree"
* Output: "eert"
* Explanation: 'e' appears twice while 'r' and 't' both appear once.
* So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also
* a valid answer.
*
* Example 2:
*
* Input: s = "cccaaa"
* Output: "aaaccc"
* Explanation: Both 'c' and 'a' appear three times, so both "cccaaa"
* and "aaaccc" are valid answers.
* Note that "cacaca" is incorrect, as the same characters must be
* together.
*
* Example 3:
*
* Input: s = "Aabb"
* Output: "bbAa"
* Explanation: "bbaA" is also a valid answer, but "Aabb" is incorrect.
* Note that 'A' and 'a' are treated as two different characters.
*
*
*
* Constraints:
*
* • 1 <= s.length <= 5 * 10^5
*
* • s consists of uppercase and lowercase English letters and digits.
*/
/**
* @param {string} s
* @return {string}
*/
var frequencySort = function (s) {
// count the frequency of each character
const freq = {};
for (let c of s) freq[c] = (freq[c] || 0) + 1;
// sort the characters by frequency
return s
.split("")
.sort((a, b) => freq[b] - freq[a] || a.localeCompare(b))
.join("");
};