diff --git a/.agents/skills/add-column-type/SKILL.md b/.agents/skills/add-column-type/SKILL.md index d46f1d0ec7d..7abf91ebfaa 100644 --- a/.agents/skills/add-column-type/SKILL.md +++ b/.agents/skills/add-column-type/SKILL.md @@ -50,7 +50,7 @@ Decide what a cell literally holds in `user_table_rows.data` (JSONB). This drive ## Step 2: Add the icon -Create `packages/emcn/src/icons/type-{name}.tsx`, copying the geometry conventions of its siblings exactly: +Create `packages/emcn-legacy/src/icons/type-{name}.tsx`, copying the geometry conventions of its siblings exactly: ```tsx import type { SVGProps } from 'react' @@ -82,7 +82,7 @@ export function Type{Pascal}(props: SVGProps) { - `viewBox='-1.75 -1.5 24 24'` is the **`type-*` family** value, not the set-wide default. Match the family. - Center the glyph on the viewBox's optical center (**y = 10.5**, **x = 10.25**) — every sibling does, and a few tenths off is visible at `size-[14px]`. -- Export alphabetically **by component name** in `packages/emcn/src/icons/index.ts`. +- Export alphabetically **by component name** in `packages/emcn-legacy/src/icons/index.ts`. ## Step 3: Write the type file @@ -118,7 +118,7 @@ Prefer set-based SQL. When the transform genuinely needs JS (`currency`'s separa - **Import cycles.** `column-types/select.ts` imports `lib/table/select-values.ts`, so `select-values.ts` must **not** import the registry — that closes a cycle and fails at module init. Inside a type's own helper module the string literal is the implementation, not a config leak. - **The client-safe boundary.** `registry.ts` and everything it imports must stay free of `@sim/db`, `drizzle-orm`, and `next/server` — the tables grid imports it directly. A React icon is fine (it's a component *reference*, never called server-side). Only `registry.server.ts` may touch drizzle. -- **Don't re-export the registry from `@/lib/table`.** Dozens of server modules import that barrel; routing this through it pulls `@sim/emcn/icons` into all of them. Deep-import `@/lib/table/column-types`. +- **Don't re-export the registry from `@/lib/table`.** Dozens of server modules import that barrel; routing this through it pulls `@sim/emcn-legacy/icons` into all of them. Deep-import `@/lib/table/column-types`. - **`import.ts`'s `coerceValue` is a SECOND write path and is not opt-in.** Importing into a column of your type always hits it, and its `default` arm silently `String(value)`s — so a missing `case` stores text in a column whose `jsonbCast` is numeric, and then every filter and sort on that column errors in Postgres. Add a `case`, even though the switch compiles without one. (It is deliberately separate from the registry's `coerce`: an import wants an unparseable value to survive as its raw string so the row error can name it.) - **CSV inference** is an ordered heuristic in `import.ts`, deliberately not registry-driven. A new type is not inferred from a CSV unless you extend `inferColumnType` — usually you should not, since inference cannot supply configuration (an option set, a currency code). diff --git a/.agents/skills/add-enrichment/SKILL.md b/.agents/skills/add-enrichment/SKILL.md index 8ac7f58a95c..50ba6afad61 100644 --- a/.agents/skills/add-enrichment/SKILL.md +++ b/.agents/skills/add-enrichment/SKILL.md @@ -65,7 +65,7 @@ Why it matters: the cascade runner only bills (and only reads `output.cost.total Create `apps/sim/enrichments/{id}/{id}.ts` and a barrel `index.ts`. Mirror the entries registered in `enrichments/registry.ts`. ```typescript -import { SomeIcon } from '@sim/emcn/icons' +import { SomeIcon } from '@sim/emcn-legacy/icons' import { filterUndefined } from '@sim/utils/object' import { normalizeDomain, splitName, str, toolProvider } from '@/enrichments/providers' import type { EnrichmentConfig } from '@/enrichments/types' @@ -111,7 +111,7 @@ export { myEnrichment } from './my-enrichment' ``` Rules: -- Keep the file **client-safe**: import only `@sim/emcn/icons`, `@sim/utils/*`, `@/enrichments/providers`, and the types. **Never import `@/tools`** here — the runner does the tool call. +- Keep the file **client-safe**: import only `@sim/emcn-legacy/icons`, `@sim/utils/*`, `@/enrichments/providers`, and the types. **Never import `@/tools`** here — the runner does the tool call. - `buildParams` returns `null` when inputs are insufficient (provider skipped). `mapOutput` returns `null`/empty for a miss (falls through). Use `filterUndefined` when assembling optional tool params; coerce numbers explicitly (don't pass `''` to number outputs). - Output `id`s are the keys `mapOutput` returns; output `name`s are the default column names (the user can rename them in the config). diff --git a/.agents/skills/design-taste-frontend/SKILL.md b/.agents/skills/design-taste-frontend/SKILL.md index 303a2ad1af0..346f1b3597d 100644 --- a/.agents/skills/design-taste-frontend/SKILL.md +++ b/.agents/skills/design-taste-frontend/SKILL.md @@ -4,7 +4,7 @@ source: https://github.com/leonxlnx/taste-skill — skills/taste-skill/SKILL.md description: Anti-slop frontend skill for landing pages, portfolios, and redesigns. The agent reads the brief, infers the right design direction, and ships interfaces that do not look templated. Real design systems when applicable, audit-first on redesigns, strict pre-flight check. --- -> **In this repo:** Tailwind 4 (CSS-first config in `apps/sim/app/_styles/globals.css`); animation via `import { motion } from 'framer-motion'` (not `motion/react`); icons from `@sim/emcn/icons`; colors through the CSS-variable tokens in `.claude/rules/sim-styling.md` (no hardcoded `text-gray-*`/hex/`zinc` utilities, no paired `dark:` utilities). This note overrides any conflicting guidance or code sample anywhere in this file. Fonts are fixed (Season body, Inter); never introduce new families, and never use Martian Mono on landing (`apps/sim/app/(landing)/CLAUDE.md`). Font weight is only `font-normal`/`font-medium`/`font-semibold`. Elevation uses the `shadow-subtle|medium|overlay|card` tokens. Type size uses named tokens, never `text-[Npx]`. Every labeled field inside a `ChipModalBody` is a `ChipModalField`. Use `bunx`, never `npx`. Do not add GSAP, Lenis, Three, or shadcn. On landing pages, motion is CSS first; an animation library stays out of the initial bundle and loads below the fold through `next/dynamic` (`apps/sim/app/(landing)/CLAUDE.md`). Landing copy and SEO follow `.claude/rules/constitution.md` and `.claude/rules/landing-seo-geo.md`. +> **In this repo:** Tailwind 4 (CSS-first config in `apps/sim/app/_styles/globals.css`); animation via `import { motion } from 'framer-motion'` (not `motion/react`); icons from `@sim/emcn-legacy/icons`; colors through the CSS-variable tokens in `.claude/rules/sim-styling.md` (no hardcoded `text-gray-*`/hex/`zinc` utilities, no paired `dark:` utilities). This note overrides any conflicting guidance or code sample anywhere in this file. Fonts are fixed (Season body, Inter); never introduce new families, and never use Martian Mono on landing (`apps/sim/app/(landing)/CLAUDE.md`). Font weight is only `font-normal`/`font-medium`/`font-semibold`. Elevation uses the `shadow-subtle|medium|overlay|card` tokens. Type size uses named tokens, never `text-[Npx]`. Every labeled field inside a `ChipModalBody` is a `ChipModalField`. Use `bunx`, never `npx`. Do not add GSAP, Lenis, Three, or shadcn. On landing pages, motion is CSS first; an animation library stays out of the initial bundle and loads below the fold through `next/dynamic` (`apps/sim/app/(landing)/CLAUDE.md`). Landing copy and SEO follow `.claude/rules/constitution.md` and `.claude/rules/landing-seo-geo.md`. # tasteskill: Anti-Slop Frontend Skill @@ -141,7 +141,7 @@ Unless the design read picks a real design system (Section 2.A), these are the d * **NEVER** use `useState` to track continuous values driven by user input (mouse position, scroll progress, pointer physics, magnetic hover). Use Motion's `useMotionValue` / `useTransform` / `useScroll`. `useState` re-renders the React tree on every change and collapses on mobile. ### 3.C Icons -* **Icons:** in this repo, `@sim/emcn/icons` only — one family per tree, `strokeWidth` standardized. Outside this repo, pick one maintained library and standardize on it. +* **Icons:** in this repo, `@sim/emcn-legacy/icons` only — one family per tree, `strokeWidth` standardized. Outside this repo, pick one maintained library and standardize on it. ### 3.D Emoji Policy Discouraged by default in code, markup, and visible text. Replace symbols with icon-library glyphs. **Override:** allow emojis only when the user explicitly asks for a playful / chat-style / social-native vibe - and even then use them sparingly with intent. diff --git a/.agents/skills/emcn-design-review/SKILL.md b/.agents/skills/emcn-design-review/SKILL.md index 8fa95e83a5e..0b46195b00b 100644 --- a/.agents/skills/emcn-design-review/SKILL.md +++ b/.agents/skills/emcn-design-review/SKILL.md @@ -14,11 +14,11 @@ User arguments: $ARGUMENTS ## Context -The existing Sim app uses `packages/emcn`, its Radix primitives, CVA variants, and CSS tokens. For `apps/sim/platform/**`, use [implement-platform](../implement-platform/SKILL.md). For mixed scopes, review each file under its owning system and preserve the requested `fix` mode for both. +The existing Sim app uses `packages/emcn-legacy`, its Radix primitives, CVA variants, and CSS tokens. For `apps/sim/platform/**`, use [implement-platform](../implement-platform/SKILL.md). For mixed scopes, review each file under its owning system and preserve the requested `fix` mode for both. ## Steps -1. Read the emcn public barrel at `packages/emcn/src/index.ts` (re-exports components, Calendar, Table*, and icons) to know what's available; for the full icon set read `packages/emcn/src/icons/index.ts` +1. Read the emcn public barrel at `packages/emcn-legacy/src/index.ts` (re-exports components, Calendar, Table*, and icons) to know what's available; for the full icon set read `packages/emcn-legacy/src/icons/index.ts` 2. Read `apps/sim/app/_styles/globals.css` for CSS variable tokens 3. Analyze the specified scope against every rule below 4. If fix=true, apply the fixes. If fix=false, propose the fixes without applying. @@ -27,8 +27,8 @@ The existing Sim app uses `packages/emcn`, its Radix primitives, CVA variants, a ## Imports -- Components, `cn`, and tokens from the `@sim/emcn` barrel, never component subpaths -- Icons from `@sim/emcn/icons` +- Components, `cn`, and tokens from the `@sim/emcn-legacy` barrel, never component subpaths +- Icons from `@sim/emcn-legacy/icons` ## Design Tokens @@ -52,7 +52,7 @@ Use `ChipConfirmModal` (title "Delete/Remove {ItemType}", `confirm={{ label, onC ## Toast -`toast.success()`, `toast.error()`, `toast()` from `@sim/emcn`. Never custom notification UI. +`toast.success()`, `toast.error()`, `toast()` from `@sim/emcn-legacy`. Never custom notification UI. ## Badges diff --git a/.agents/skills/implement-platform/SKILL.md b/.agents/skills/implement-platform/SKILL.md index 001f7dd2d29..1136097ea48 100644 --- a/.agents/skills/implement-platform/SKILL.md +++ b/.agents/skills/implement-platform/SKILL.md @@ -10,8 +10,8 @@ Start in the Sim checkout containing the requested product work. Read the [Platf 1. **Establish scope on the real route.** Identify the product entry, interaction, phase, and affected consumers. When rebuilding an existing workflow, trace the old navigation target, its access gate, and the actions reachable by that viewer. Use that evidence to decide which controls belong on the new page before consulting the broader API or provider catalog. Phase 1 owns foundations and the library. Phase 2 owns working UI and transient interaction state, with examples supplied through the server fixture flag. Phase 3 connects real data and operations. Reuse the same renderer in the browser and Sim Desktop. Read the installed Next guides for the file structure or framework behavior you are changing. For organization Settings, inventory the old sidebar in order, its viewer/deployment gates and every action reachable from each section. Map old header buttons to the row or section they act on. Verify the same destination and drilldown on the fixture and authenticated routes; keep real writes outside fixture sessions. 2. **Resolve design intent.** For Paper-backed work, use `$sim-paper-design` to locate the live Shared or Platform master and the product states that use it. Exclude Marcus. Preserve the key and theme roles. Treat artboard sizes as reference measurements. For code-first changes, follow the latest explicit product direction and inspect the rendered route. Identify any source you could not verify. Update the Paper canvas when the request includes Paper changes. -3. **Choose or change the owner.** Start with the behavior. An action, navigation row, value picker, or disclosure has an existing keyboard and pointer contract. Different interactions may share visual roles while retaining different semantics. Use the existing family and named props for a change in size, intent, icon, or content. Toolbar choices use ChoiceMenu, as Home's period does; Select/SelectField belong to forms and settings. Compare the rendered trigger, not just its variant name. Put unique anatomy and its CSS together in `_components//.tsx` and `.module.css`. Match an existing semantic rhythm, such as Home's ActivityRow, for a custom composition. Keep page files free of styling. Only EMCN owns the appearance of its controls. Use Base UI there for complex keyboard, floating, and dismissal behavior. -4. **Trace the full change.** On a second independent feature use, promote the original implementation and migrate both callers. For consolidation, compare semantics, map every consumer to its replacement, then remove the obsolete implementation, export, variant styles, and unused registrations. For deletion, also check menus, preferences, fixture data, workbench references, and tests that existed only for the removed feature. Preserve unrelated consumers and historical Paper evidence. Before adding a shared visual variant, name at least two independent real consumers. A single feature composes the existing primitives in its local owner; a label, icon, data value or responsive arrangement does not justify another variant. Keep the public API small enough to understand at the call site. Edit the source or compiler for generated foundations and recipes. +3. **Choose or change the owner.** Shared controls and foundations belong to `packages/emcn`; Platform-specific compositions belong to `packages/emcn-platform`. Auth and Docs compose the same Shared primitives through their own packages. Use public family subpaths, colocated CSS Modules and the single scoped style entry for each surface. Keep `@sim/emcn-legacy` outside the modern package graph. Start with the behavior. An action, navigation row, value picker, or disclosure has an existing keyboard and pointer contract. Different interactions may share visual roles while retaining different semantics. Use the existing family and named props for a change in size, intent, icon, or content. Toolbar choices use ChoiceMenu, as Home's period does; Select/SelectField belong to labeled forms. Immediate preferences, row roles and toolbar filters use compact text triggers without borders or chevrons. Compare the rendered trigger, not just its variant name. Put unique anatomy and its CSS together in `_components//.tsx` and `.module.css`. Match an existing semantic rhythm, such as Home's ActivityRow, for a custom composition. Keep page files free of styling. Only EMCN owns the appearance of its controls. Use Base UI there for complex keyboard, floating, and dismissal behavior. +4. **Trace the full change.** On a second independent feature use, promote the original implementation and migrate both callers. For consolidation, compare semantics, map every consumer to its replacement, then remove the obsolete implementation, export, variant styles, and unused registrations. For deletion, also check menus, preferences, fixture data, workbench references, and tests that existed only for the removed feature. Preserve unrelated consumers and historical Paper evidence. Before adding a shared visual variant, name at least two independent real consumers. A single feature composes the existing primitives in its local owner; a label, icon, data value or responsive arrangement does not justify another variant. Keep the public API small enough to understand at the call site. Edit the source or compiler for generated foundations and recipes. Before moving files across packages or renaming widely, merge the base branch and tell its owner, so parallel work lands before the move rather than against it. 5. **Verify where people use it.** Run the design audit and applicable checks from the README. Render the changed product route with empty, full, stress, and fixture-off data as relevant. Check both themes, widths between artboards, long content, text scaling, keyboard, and pointer states. Compare shared controls in their actual consumers. Check the actual scroll edge and the open popup when space is tight. For shell, panel, or desktop work, exercise the real Electron renderer. For substantial implementations and consolidations, use an independent agent during design or implementation and for a final review of the changed owners and routes. Reuse the single review server at localhost:3125. Check its process working directory and branch before starting a server or moving work. Separate task worktrees do not update that preview until reconciled into its checkout. Provide the working route for visual review. 6. **Keep non-UI code in one place.** When work touches both the zone and `apps/sim/platform/embedded`, converge first rather than porting: only markup may differ. Follow "Converging a domain" in `apps/sim/platform/AGENTS.md`; `bun run check:platform-convergence` fails a new parallel file. 7. **Keep decisions durable.** Follow the contract’s maintenance guidance when an approved correction changes a shared rule. Record feature-specific decisions with their feature. For sustained work, keep a task checkpoint with the code revision, verified states, evidence, and outstanding work. Include the branch or PR, checkpoint path, and localhost route in a handoff. On resumption, compare the checkpoint with the current branch, working tree, and relevant live sources before acting. diff --git a/.agents/skills/make-interfaces-feel-better/SKILL.md b/.agents/skills/make-interfaces-feel-better/SKILL.md index dfb709f427a..167ea44aa15 100644 --- a/.agents/skills/make-interfaces-feel-better/SKILL.md +++ b/.agents/skills/make-interfaces-feel-better/SKILL.md @@ -65,7 +65,7 @@ Add a subtle 1px low-opacity outline to images; see surfaces.md. In this repo, u ### 12. Scale on Press -A subtle scale-down (about 0.96-0.97) on press gives tactile feedback. In this repo a press affordance belongs in the emcn `Button`/`Chip` chrome (`packages/emcn`), not in consumer classes — neither component implements one today, so propose it there rather than adding per-call-site transforms. +A subtle scale-down (about 0.96-0.97) on press gives tactile feedback. In this repo a press affordance belongs in the emcn `Button`/`Chip` chrome (`packages/emcn-legacy`), not in consumer classes — neither component implements one today, so propose it there rather than adding per-call-site transforms. ### 13. Skip Animation on Page Load @@ -119,7 +119,7 @@ Present changes as markdown tables with **Before** and **After** columns, one ta #### Scale on press | Before | After | | --- | --- | -| `Chip` has no press affordance | Proposed in `packages/emcn/src/components/chip/chip.tsx` (`chipVariants`): `active:scale-[0.96] transition-transform` | +| `Chip` has no press affordance | Proposed in `packages/emcn-legacy/src/components/chip/chip.tsx` (`chipVariants`): `active:scale-[0.96] transition-transform` | | `scale(0.9)` on press | Raised to `scale(0.96)` — anything below `0.95` feels exaggerated | Rows should cite the specific file and the specific property that changed when it isn't obvious from the snippet. If a principle was reviewed but nothing needed to change, omit that table entirely — empty tables add noise. diff --git a/.agents/skills/validate-integration/SKILL.md b/.agents/skills/validate-integration/SKILL.md index afc070e00b5..5c24cb4e49f 100644 --- a/.agents/skills/validate-integration/SKILL.md +++ b/.agents/skills/validate-integration/SKILL.md @@ -460,7 +460,7 @@ The integration's page must carry a `{/* MANUAL-CONTENT-START:intro */}` section ``. If it is missing, write one using the template in add-integration → Step 8, and check an existing intro against what the block actually ships (no removed or unshipped operations). -If an icon changed, `apps/sim/components/icons.tsx` is the source of truth and `apps/docs/components/icons.tsx` is its generated mirror — they must end up byte-identical for that component. +If an icon changed, `apps/sim/components/icons.tsx` is the source of truth and `apps/docs/components/icons/icons.tsx` is its generated mirror — they must end up byte-identical for that component. ### Validation Output diff --git a/.claude/rules/emcn-components.md b/.claude/rules/emcn-components.md index 28a6db5abd5..dc493ed7b9a 100644 --- a/.claude/rules/emcn-components.md +++ b/.claude/rules/emcn-components.md @@ -1,61 +1,16 @@ --- -description: EMCN component library patterns +description: Modern shared EMCN components and surface packages paths: - "packages/emcn/**" + - "packages/emcn-auth/**" + - "packages/emcn-docs/**" + - "packages/emcn-platform/**" --- -# EMCN Components +# Modern EMCN -This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`. +Read `packages/emcn/AGENTS.md` and `packages/emcn/README.md`. The modern system derives from the new Platform UI. Shared primitives and foundations live in the EMCN package; Auth, Docs and Platform own only their specific compositions. `@sim/emcn-legacy` serves unreplaced routes and cannot enter the new package graph. -Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from the `@sim/emcn/icons` subpath, and CSS modules from their file path. Never deep-import other component subpaths. The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, date field→`ChipDatePicker`). `ChipSwitch` is a segmented choice between options, not a replacement for `Switch`: a boolean on/off toggle stays `Switch`. For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover). +Import the public family (`@sim/emcn/button`, `@sim/emcn-auth/shell`) rather than an aggregate or a private source file. Keep each component's CSS and private helpers in its family folder. Use Base UI for complex interaction behavior, shared semantic roles for paint and geometry, and props for supported states. Keep data, permissions, routing and fixtures in the applications. -## Chip chrome — single source of truth - -Never hand-roll the chip pill from raw class strings (they go stale). Compose from the canonical sources: - -- **Surface, typography + content tokens:** `chip/chrome.ts` — `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells), and the row-state pair `chipHoverSurfaceClass` / `chipActiveSurfaceClass` (hover vs. selected — mutually exclusive, so a selected row holds its surface through hover; every hand-rolled row imports these rather than restating the literals). All are re-exported from the `@sim/emcn` barrel — no subpath import needed. -- **Pill geometry:** `chip/chip.tsx` — `chipVariants` (30px tall, `rounded-lg`, `px-2`, icon↔text `gap-1.5`). Every pill-shaped trigger (`ChipDropdown`, `ChipSelect`, `ChipSwitch`) reuses it for visual parity. - -Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border` border (`chip/chrome.ts` still spells it through the legacy alias `--border-1`; new code writes `--border`). - -`MENU_STYLES` in `dropdown-menu/styles.ts` owns the shared dropdown, picker-list, and popover chrome. Its default menu rows are 28px at `text-small`; chip pills remain 30px at `text-sm`. Menus reuse the chip gap, row radius, and search-field surface and typography, with a 12px outer radius, 4px padding, and `shadow-medium`. Compose these tokens instead of overriding chrome at call sites. Within the package, shared initialization-time tokens use private imports to avoid public-barrel cycles; consumers import `MENU_STYLES` from `@sim/emcn`. - -## Component catalogue - -- **`Chip` / `ChipLink`** — the pill button (` @@ -105,9 +106,10 @@ function NavigationItem({ node, pathname, onNavigate }: NavigationItemProps) { className={cn(rowClass, 'hover:bg-[var(--docs-hover)] active:bg-[var(--docs-pressed)]')} > {label} - diff --git a/apps/docs/components/docs/page-actions.tsx b/apps/docs/components/docs/page-actions/page-actions.tsx similarity index 54% rename from apps/docs/components/docs/page-actions.tsx rename to apps/docs/components/docs/page-actions/page-actions.tsx index 27caf47cef7..ead3e0e93f7 100644 --- a/apps/docs/components/docs/page-actions.tsx +++ b/apps/docs/components/docs/page-actions/page-actions.tsx @@ -1,11 +1,11 @@ 'use client' import { useRef, useState } from 'react' -import * as Dropdown from '@radix-ui/react-dropdown-menu' -import { useCopyToClipboard } from '@sim/emcn' -import { Check, ChevronDown, Duplicate, SquareArrowUpRight } from '@sim/emcn/icons' -import { cn } from '@/components/docs/classnames' -import { docsControlClass, docsMenuClass, docsMenuItemClass } from '@/components/docs/primitives' +import { Menu } from '@base-ui/react/menu' +import { useClipboard } from '@sim/emcn/feedback/use-clipboard' +import { Icon } from '@sim/emcn/icon' +import { cn } from '@sim/emcn/lib/cn' +import { docsControlClass, docsMenuClass, docsMenuItemClass } from '@sim/emcn-docs/chrome' import { getMarkdownPath } from '@/lib/urls' interface PageActionsProps { @@ -13,7 +13,7 @@ interface PageActionsProps { } export function PageActions({ url }: PageActionsProps) { - const { copied, copy } = useCopyToClipboard() + const { copied, copy } = useClipboard() const [status, setStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle') const prepared = useRef(null) const markdownUrl = getMarkdownPath(url) @@ -47,44 +47,45 @@ export function PageActions({ url }: PageActionsProps) { } return (
- - - {showCopied ? : null} + + + {showCopied ? : null} {showCopied ? 'Copied' : 'Copy page'} - - - - - { - event.preventDefault() - void copyPage() - }} - className={docsMenuItemClass} - > - - {status === 'loading' - ? 'Copying…' - : status === 'ready' - ? 'Copy prepared Markdown' - : showCopied - ? 'Copied' - : 'Copy Markdown'} - - - - + + + + + + { + void copyPage() + }} + className={docsMenuItemClass} + > + + {status === 'loading' + ? 'Copying…' + : status === 'ready' + ? 'Copy prepared Markdown' + : showCopied + ? 'Copied' + : 'Copy Markdown'} + + + View Markdown - - - - - + + + + +
- - + + Menu - +
@@ -45,6 +47,7 @@ export function DocsPageFrame({ children, headings, api = false }: DocsPageFrame
{!api && (