@agent-native/core 0.77.4 → 0.77.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +19 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +35 -0
- package/corpus/core/src/agent/run-store.ts +2 -0
- package/corpus/core/src/client/changelog/Changelog.tsx +22 -10
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +405 -35
- package/corpus/templates/clips/app/i18n/ar-SA.ts +14 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +14 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +14 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +14 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +14 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +14 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +14 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +14 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +14 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +14 -0
- package/corpus/templates/clips/app/root.tsx +2 -2
- package/corpus/templates/clips/app/routes/_app.extensions.$id.tsx +4 -1
- package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +4 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +12 -5
- package/corpus/templates/clips/changelog/2026-06-25-localized-clips-settings-changelog-and-extension-sidebar-lab.md +6 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +4 -2
- package/corpus/templates/clips/desktop/src/styles.css +15 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +31 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +2 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +2 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/changelog/Changelog.d.ts +7 -2
- package/dist/client/changelog/Changelog.d.ts.map +1 -1
- package/dist/client/changelog/Changelog.js +9 -7
- package/dist/client/changelog/Changelog.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +339 -11
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Changelog.js","sourceRoot":"","sources":["../../../src/client/changelog/Changelog.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAuB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EACL,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEjC,iFAAiF;AAEjF,SAAS,kBAAkB,CAAC,KAAqB;IAC/C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,4EAA4E;QAC5E,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE;gBACpE,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,MAAM;gBACb,GAAG,EAAE,SAAS;aACf,CAAC,CAAC;YACH,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,MAAM,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC;AACrB,CAAC;AAED,iFAAiF;AACjF,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAE5E,MAAM,2BAA2B,GAAG;IAClC,EAAE,EAAE,CAAC,KAA+C,EAAE,EAAE,CAAC,CACvD,gBACM,KAAK,EACT,SAAS,EAAC,4FAA4F,GACtG,CACH;IACD,EAAE,EAAE,CAAC,KAA6C,EAAE,EAAE,CAAC,CACrD,gBACM,KAAK,EACT,SAAS,EAAC,yFAAyF,GACnG,CACH;IACD,EAAE,EAAE,CAAC,KAA6C,EAAE,EAAE,CAAC,CACrD,gBACM,KAAK,EACT,SAAS,EAAC,4FAA4F,GACtG,CACH;IACD,EAAE,EAAE,CAAC,KAA0C,EAAE,EAAE,CAAC,CAClD,gBAAQ,KAAK,EAAE,SAAS,EAAC,iBAAiB,GAAG,CAC9C;IACD,CAAC,EAAE,CAAC,KAAiD,EAAE,EAAE,CAAC,CACxD,eAAO,KAAK,EAAE,SAAS,EAAC,8CAA8C,GAAG,CAC1E;IACD,CAAC,EAAE,CAAC,KAAoD,EAAE,EAAE,CAAC,CAC3D,eACM,KAAK,EACT,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,0CAA0C,GACpD,CACH;IACD,IAAI,EAAE,CAAC,KAAwC,EAAE,EAAE,CAAC,CAClD,kBACM,KAAK,EACT,SAAS,EAAC,sDAAsD,GAChE,CACH;CACF,CAAC;AAEF,SAAS,aAAa,CAAC,EAAE,QAAQ,EAAwB;IACvD,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,MAAM,aAAa,GAAG,cAAc,EAAE,OAAO,CAAC;IAC9C,MAAM,GAAG,GAAG,WAAW,CAAC;IAExB,IAAI,CAAC,KAAK,IAAI,CAAC,aAAa,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,4EAA4E;QAC5E,uEAAuE;QACvE,OAAO,CACL,cAAK,SAAS,EAAC,6CAA6C,YACzD,QAAQ,GACL,CACP,CAAC;IACJ,CAAC;IACD,OAAO,CACL,KAAC,aAAa,IACZ,aAAa,EAAE,CAAC,GAAG,CAAC,EACpB,UAAU,EAAE,2BAA2B,EACvC,YAAY,EAAE,oBAAoB,YAEjC,QAAQ,GACK,CACjB,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,SAAS,cAAc,CAAC,MAAc;IACpC,OAAO,qBAAqB,MAAM,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,QAA4B;IAE5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC1D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC;YACH,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,0EAA0E;IAC1E,sEAAsE;IACtE,wDAAwD;IACxD,MAAM,MAAM,GACV,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,QAAQ,CAAC;IAEnE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,iFAAiF;AAEjF,SAAS,gBAAgB,CAAC,EACxB,OAAO,EACP,SAAS,GAIV;IACC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,YAAG,SAAS,EAAC,+BAA+B,YAAE,SAAS,GAAK,CAAC;IACtE,CAAC;IACD,OAAO,CACL,cAAK,SAAS,EAAC,WAAW,YACvB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACtB,8BACE,aAAI,SAAS,EAAC,4CAA4C,YACvD,kBAAkB,CAAC,KAAK,CAAC,GACvB,EACL,KAAC,aAAa,IAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAI,KAJ3B,KAAK,CAAC,EAAE,CAKZ,CACX,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAaD,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,KAAK,GAAG,YAAY,GACC;IACrB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEpE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,KAAK,GAAG,CAAC,CAAgB,EAAE,EAAE;YACjC,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACvB,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,YAAY,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5C,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9D,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAEzB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO,CACL,cACE,SAAS,EAAC,oEAAoE,EAC9E,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE;YACjB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,aAAa;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACxD,CAAC,YAED,eACE,IAAI,EAAC,QAAQ,gBACF,MAAM,gBACL,KAAK,EACjB,SAAS,EAAC,kIAAkI,aAE5I,eAAK,SAAS,EAAC,sEAAsE,aACnF,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,WAAW,IAAC,SAAS,EAAC,+BAA+B,GAAG,EACzD,aAAI,SAAS,EAAC,uBAAuB,YAAE,KAAK,GAAM,IAC9C,EACN,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,gBACvB,OAAO,EAClB,SAAS,EAAC,qGAAqG,YAE/G,KAAC,KAAK,IAAC,SAAS,EAAC,SAAS,GAAG,GACtB,IACL,EACN,cAAK,SAAS,EAAC,2BAA2B,YACxC,KAAC,gBAAgB,IACf,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,qCAAqC,GAC/C,GACE,IACF,GACF,CACP,CAAC;AACJ,CAAC;AAcD,MAAM,UAAU,qBAAqB,CAAC,EACpC,QAAQ,EACR,KAAK,GAAG,CAAC,EACT,KAAK,GAAG,YAAY,EACpB,SAAS,GACkB;IAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAE9C,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,SAAS,CACV,aAED,eAAK,SAAS,EAAC,0DAA0D,aACvE,KAAC,WAAW,IAAC,SAAS,EAAC,+BAA+B,GAAG,EACzD,aAAI,SAAS,EAAC,uBAAuB,YAAE,KAAK,GAAM,IAC9C,EACN,eAAK,SAAS,EAAC,WAAW,aACxB,KAAC,gBAAgB,IAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,iBAAiB,GAAG,EAC/D,OAAO,IAAI,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAClC,SAAS,EAAC,uEAAuE,iCAG1E,CACV,IACG,EACN,KAAC,eAAe,IACd,IAAI,EAAE,UAAU,EAChB,YAAY,EAAE,aAAa,EAC3B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,GACZ,IACE,CACP,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,CAAC","sourcesContent":["/**\n * Changelog UI — renders an app's CHANGELOG.md as an in-app \"What's new\"\n * surface. Core owns all of this; a template just passes its own\n * `CHANGELOG.md?raw` content in (Vite inlines it at build time, so this works\n * on every host with no runtime file access or server route).\n *\n * Surfaces:\n * - <ChangelogDialog> a self-contained modal listing every release.\n * - <ChangelogSettingsCard> a settings-page card with the latest updates.\n * - useChangelogSeen() tracks the last release a user has seen (so the\n * command menu can show an \"unseen\" dot).\n *\n * The command menu's built-in `changelog` prop (see CommandMenu.tsx) wires the\n * dialog automatically — most templates never touch these directly.\n */\n\nimport { IconX, IconHistory } from \"@tabler/icons-react\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nimport { parseChangelog, type ChangelogEntry } from \"../../changelog/parse.js\";\nimport {\n markdownModule,\n remarkGfmFn,\n useMarkdownReady,\n markdownUrlTransform,\n} from \"../chat/markdown-renderer.js\";\nimport { cn } from \"../utils.js\";\n\n// ─── Date formatting ──────────────────────────────────────────────────────────\n\nfunction formatEntryHeading(entry: ChangelogEntry): string {\n if (entry.date) {\n // Parse as a plain calendar date (avoid TZ shifting YYYY-MM-DD back a day).\n const [y, m, d] = entry.date.split(\"-\").map(Number);\n if (y && m && d) {\n const formatted = new Date(y, m - 1, d).toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n return entry.version ? `${entry.version} · ${formatted}` : formatted;\n }\n }\n return entry.title;\n}\n\n// ─── Markdown body ────────────────────────────────────────────────────────────\n// A small, self-contained renderer for a release body. Avoids depending on the\n// typography plugin (`prose`) being generated in the host template by applying\n// explicit utility classes that Tailwind scans from core's compiled output.\n\nconst changelogMarkdownComponents = {\n h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => (\n <h3\n {...props}\n className=\"mb-1.5 mt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground first:mt-0\"\n />\n ),\n ul: (props: React.HTMLAttributes<HTMLUListElement>) => (\n <ul\n {...props}\n className=\"mb-2 ml-1 list-disc space-y-1 pl-4 text-sm text-foreground marker:text-muted-foreground\"\n />\n ),\n ol: (props: React.HTMLAttributes<HTMLOListElement>) => (\n <ol\n {...props}\n className=\"mb-2 ml-1 list-decimal space-y-1 pl-4 text-sm text-foreground marker:text-muted-foreground\"\n />\n ),\n li: (props: React.HTMLAttributes<HTMLLIElement>) => (\n <li {...props} className=\"leading-relaxed\" />\n ),\n p: (props: React.HTMLAttributes<HTMLParagraphElement>) => (\n <p {...props} className=\"mb-2 text-sm leading-relaxed text-foreground\" />\n ),\n a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (\n <a\n {...props}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium underline underline-offset-2\"\n />\n ),\n code: (props: React.HTMLAttributes<HTMLElement>) => (\n <code\n {...props}\n className=\"rounded bg-muted px-1 py-0.5 font-mono text-[0.85em]\"\n />\n ),\n};\n\nfunction ChangelogBody({ markdown }: { markdown: string }) {\n const ready = useMarkdownReady();\n const ReactMarkdown = markdownModule?.default;\n const gfm = remarkGfmFn;\n\n if (!ready || !ReactMarkdown || !gfm) {\n // The react-markdown chunk loads on module eval; this is typically only one\n // frame. Show readable plain text rather than nothing in the meantime.\n return (\n <div className=\"whitespace-pre-wrap text-sm text-foreground\">\n {markdown}\n </div>\n );\n }\n return (\n <ReactMarkdown\n remarkPlugins={[gfm]}\n components={changelogMarkdownComponents}\n urlTransform={markdownUrlTransform}\n >\n {markdown}\n </ReactMarkdown>\n );\n}\n\n// ─── Unseen tracking ──────────────────────────────────────────────────────────\n\nfunction seenStorageKey(appKey: string): string {\n return `an:changelog-seen:${appKey}`;\n}\n\n/**\n * Tracks the latest release a user has already seen (per browser, via\n * localStorage). Returns whether there's an unseen release and a `markSeen`\n * callback to clear the indicator once the changelog is opened.\n */\nexport function useChangelogSeen(\n appKey: string,\n latestId: string | undefined,\n): { unseen: boolean; markSeen: () => void } {\n const [seenId, setSeenId] = useState<string | null>(null);\n const [hydrated, setHydrated] = useState(false);\n\n useEffect(() => {\n try {\n setSeenId(window.localStorage.getItem(seenStorageKey(appKey)));\n } catch {\n // Private mode / disabled storage — treat as \"nothing seen yet\".\n }\n setHydrated(true);\n }, [appKey]);\n\n const markSeen = React.useCallback(() => {\n if (!latestId) return;\n setSeenId(latestId);\n try {\n window.localStorage.setItem(seenStorageKey(appKey), latestId);\n } catch {\n // Ignore storage failures; the dot just won't persist.\n }\n }, [appKey, latestId]);\n\n // Don't flag \"unseen\" until hydrated, and never on a first-ever visit (no\n // stored value) — only once the user has seen *something* and a newer\n // release appears. This avoids nagging brand-new users.\n const unseen =\n hydrated && !!latestId && seenId !== null && seenId !== latestId;\n\n return { unseen, markSeen };\n}\n\n// ─── Shared markup ────────────────────────────────────────────────────────────\n\nfunction ChangelogEntries({\n entries,\n emptyText,\n}: {\n entries: ChangelogEntry[];\n emptyText: string;\n}) {\n if (entries.length === 0) {\n return <p className=\"text-sm text-muted-foreground\">{emptyText}</p>;\n }\n return (\n <div className=\"space-y-6\">\n {entries.map((entry) => (\n <section key={entry.id}>\n <h4 className=\"mb-2 text-sm font-semibold text-foreground\">\n {formatEntryHeading(entry)}\n </h4>\n <ChangelogBody markdown={entry.body} />\n </section>\n ))}\n </div>\n );\n}\n\n// ─── Dialog ───────────────────────────────────────────────────────────────────\n\nexport interface ChangelogDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Raw CHANGELOG.md contents (e.g. `import md from \"../CHANGELOG.md?raw\"`). */\n markdown: string;\n /** Dialog heading. Default: \"What's new\". */\n title?: string;\n}\n\nexport function ChangelogDialog({\n open,\n onOpenChange,\n markdown,\n title = \"What's new\",\n}: ChangelogDialogProps) {\n const entries = useMemo(() => parseChangelog(markdown), [markdown]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onOpenChange(false);\n }\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onOpenChange]);\n\n if (!open) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-start justify-center bg-black/50 p-4\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) onOpenChange(false);\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n className=\"mt-[8vh] flex max-h-[80vh] w-full max-w-xl flex-col rounded-lg border border-border bg-popover text-popover-foreground shadow-lg\"\n >\n <div className=\"flex items-center justify-between border-b border-border px-5 py-3.5\">\n <div className=\"flex items-center gap-2\">\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n </div>\n <button\n type=\"button\"\n onClick={() => onOpenChange(false)}\n aria-label=\"Close\"\n className=\"rounded-sm p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground\"\n >\n <IconX className=\"h-4 w-4\" />\n </button>\n </div>\n <div className=\"overflow-y-auto px-5 py-4\">\n <ChangelogEntries\n entries={entries}\n emptyText=\"No updates have been published yet.\"\n />\n </div>\n </div>\n </div>\n );\n}\n\n// ─── Settings card ────────────────────────────────────────────────────────────\n\nexport interface ChangelogSettingsCardProps {\n /** Raw CHANGELOG.md contents (e.g. `import md from \"../CHANGELOG.md?raw\"`). */\n markdown: string;\n /** How many recent releases to show inline before \"View all\". Default: 2. */\n limit?: number;\n /** Card heading. Default: \"What's new\". */\n title?: string;\n className?: string;\n}\n\nexport function ChangelogSettingsCard({\n markdown,\n limit = 2,\n title = \"What's new\",\n className,\n}: ChangelogSettingsCardProps) {\n const entries = useMemo(() => parseChangelog(markdown), [markdown]);\n const [dialogOpen, setDialogOpen] = useState(false);\n\n if (entries.length === 0) return null;\n\n const shown = entries.slice(0, limit);\n const hasMore = entries.length > shown.length;\n\n return (\n <div\n className={cn(\n \"rounded-lg border border-border bg-card text-card-foreground\",\n className,\n )}\n >\n <div className=\"flex items-center gap-2 border-b border-border px-5 py-4\">\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n </div>\n <div className=\"px-5 py-4\">\n <ChangelogEntries entries={shown} emptyText=\"No updates yet.\" />\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setDialogOpen(true)}\n className=\"mt-4 text-sm font-medium text-foreground underline underline-offset-2\"\n >\n View all updates\n </button>\n )}\n </div>\n <ChangelogDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n markdown={markdown}\n title={title}\n />\n </div>\n );\n}\n\nexport { parseChangelog };\nexport type { ChangelogEntry };\n"]}
|
|
1
|
+
{"version":3,"file":"Changelog.js","sourceRoot":"","sources":["../../../src/client/changelog/Changelog.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Changelog UI — renders an app's CHANGELOG.md as an in-app \"What's new\"\n * surface. Core owns all of this; a template just passes its own\n * `CHANGELOG.md?raw` content in (Vite inlines it at build time, so this works\n * on every host with no runtime file access or server route).\n *\n * Surfaces:\n * - <ChangelogDialog> a self-contained modal listing every release.\n * - <ChangelogSettingsCard> a settings-page card with the latest updates.\n * - useChangelogSeen() tracks the last release a user has seen (so the\n * command menu can show an \"unseen\" dot).\n *\n * The command menu's built-in `changelog` prop (see CommandMenu.tsx) wires the\n * dialog automatically — most templates never touch these directly.\n */\n\nimport { IconX, IconHistory } from \"@tabler/icons-react\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nimport { parseChangelog, type ChangelogEntry } from \"../../changelog/parse.js\";\nimport {\n markdownModule,\n remarkGfmFn,\n useMarkdownReady,\n markdownUrlTransform,\n} from \"../chat/markdown-renderer.js\";\nimport { DEFAULT_LOCALE, useOptionalLocale, type LocaleCode } from \"../i18n.js\";\nimport { cn } from \"../utils.js\";\n\n// ─── Date formatting ──────────────────────────────────────────────────────────\n\nfunction formatEntryHeading(entry: ChangelogEntry, locale: LocaleCode): string {\n if (entry.date) {\n // Parse as a plain calendar date (avoid TZ shifting YYYY-MM-DD back a day).\n const [y, m, d] = entry.date.split(\"-\").map(Number);\n if (y && m && d) {\n const formatted = new Date(y, m - 1, d).toLocaleDateString(locale, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n return entry.version ? `${entry.version} · ${formatted}` : formatted;\n }\n }\n return entry.title;\n}\n\n// ─── Markdown body ────────────────────────────────────────────────────────────\n// A small, self-contained renderer for a release body. Avoids depending on the\n// typography plugin (`prose`) being generated in the host template by applying\n// explicit utility classes that Tailwind scans from core's compiled output.\n\nconst changelogMarkdownComponents = {\n h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => (\n <h3\n {...props}\n className=\"mb-1.5 mt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground first:mt-0\"\n />\n ),\n ul: (props: React.HTMLAttributes<HTMLUListElement>) => (\n <ul\n {...props}\n className=\"mb-2 ml-1 list-disc space-y-1 pl-4 text-sm text-foreground marker:text-muted-foreground\"\n />\n ),\n ol: (props: React.HTMLAttributes<HTMLOListElement>) => (\n <ol\n {...props}\n className=\"mb-2 ml-1 list-decimal space-y-1 pl-4 text-sm text-foreground marker:text-muted-foreground\"\n />\n ),\n li: (props: React.HTMLAttributes<HTMLLIElement>) => (\n <li {...props} className=\"leading-relaxed\" />\n ),\n p: (props: React.HTMLAttributes<HTMLParagraphElement>) => (\n <p {...props} className=\"mb-2 text-sm leading-relaxed text-foreground\" />\n ),\n a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (\n <a\n {...props}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium underline underline-offset-2\"\n />\n ),\n code: (props: React.HTMLAttributes<HTMLElement>) => (\n <code\n {...props}\n className=\"rounded bg-muted px-1 py-0.5 font-mono text-[0.85em]\"\n />\n ),\n};\n\nfunction ChangelogBody({ markdown }: { markdown: string }) {\n const ready = useMarkdownReady();\n const ReactMarkdown = markdownModule?.default;\n const gfm = remarkGfmFn;\n\n if (!ready || !ReactMarkdown || !gfm) {\n // The react-markdown chunk loads on module eval; this is typically only one\n // frame. Show readable plain text rather than nothing in the meantime.\n return (\n <div className=\"whitespace-pre-wrap text-sm text-foreground\">\n {markdown}\n </div>\n );\n }\n return (\n <ReactMarkdown\n remarkPlugins={[gfm]}\n components={changelogMarkdownComponents}\n urlTransform={markdownUrlTransform}\n >\n {markdown}\n </ReactMarkdown>\n );\n}\n\n// ─── Unseen tracking ──────────────────────────────────────────────────────────\n\nfunction seenStorageKey(appKey: string): string {\n return `an:changelog-seen:${appKey}`;\n}\n\n/**\n * Tracks the latest release a user has already seen (per browser, via\n * localStorage). Returns whether there's an unseen release and a `markSeen`\n * callback to clear the indicator once the changelog is opened.\n */\nexport function useChangelogSeen(\n appKey: string,\n latestId: string | undefined,\n): { unseen: boolean; markSeen: () => void } {\n const [seenId, setSeenId] = useState<string | null>(null);\n const [hydrated, setHydrated] = useState(false);\n\n useEffect(() => {\n try {\n setSeenId(window.localStorage.getItem(seenStorageKey(appKey)));\n } catch {\n // Private mode / disabled storage — treat as \"nothing seen yet\".\n }\n setHydrated(true);\n }, [appKey]);\n\n const markSeen = React.useCallback(() => {\n if (!latestId) return;\n setSeenId(latestId);\n try {\n window.localStorage.setItem(seenStorageKey(appKey), latestId);\n } catch {\n // Ignore storage failures; the dot just won't persist.\n }\n }, [appKey, latestId]);\n\n // Don't flag \"unseen\" until hydrated, and never on a first-ever visit (no\n // stored value) — only once the user has seen *something* and a newer\n // release appears. This avoids nagging brand-new users.\n const unseen =\n hydrated && !!latestId && seenId !== null && seenId !== latestId;\n\n return { unseen, markSeen };\n}\n\n// ─── Shared markup ────────────────────────────────────────────────────────────\n\nfunction ChangelogEntries({\n entries,\n emptyText,\n}: {\n entries: ChangelogEntry[];\n emptyText: string;\n}) {\n const locale = useOptionalLocale()?.locale ?? DEFAULT_LOCALE;\n\n if (entries.length === 0) {\n return <p className=\"text-sm text-muted-foreground\">{emptyText}</p>;\n }\n return (\n <div className=\"space-y-6\">\n {entries.map((entry) => (\n <section key={entry.id}>\n <h4 className=\"mb-2 text-sm font-semibold text-foreground\">\n {formatEntryHeading(entry, locale)}\n </h4>\n <ChangelogBody markdown={entry.body} />\n </section>\n ))}\n </div>\n );\n}\n\n// ─── Dialog ───────────────────────────────────────────────────────────────────\n\nexport interface ChangelogDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Raw CHANGELOG.md contents (e.g. `import md from \"../CHANGELOG.md?raw\"`). */\n markdown: string;\n /** Dialog heading. Default: \"What's new\". */\n title?: string;\n closeLabel?: string;\n emptyText?: string;\n}\n\nexport function ChangelogDialog({\n open,\n onOpenChange,\n markdown,\n title = \"What's new\",\n closeLabel = \"Close\",\n emptyText = \"No updates have been published yet.\",\n}: ChangelogDialogProps) {\n const entries = useMemo(() => parseChangelog(markdown), [markdown]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onOpenChange(false);\n }\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, onOpenChange]);\n\n if (!open) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-start justify-center bg-black/50 p-4\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) onOpenChange(false);\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n className=\"mt-[8vh] flex max-h-[80vh] w-full max-w-xl flex-col rounded-lg border border-border bg-popover text-popover-foreground shadow-lg\"\n >\n <div className=\"flex items-center justify-between border-b border-border px-5 py-3.5\">\n <div className=\"flex items-center gap-2\">\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n </div>\n <button\n type=\"button\"\n onClick={() => onOpenChange(false)}\n aria-label={closeLabel}\n className=\"rounded-sm p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground\"\n >\n <IconX className=\"h-4 w-4\" />\n </button>\n </div>\n <div className=\"overflow-y-auto px-5 py-4\">\n <ChangelogEntries entries={entries} emptyText={emptyText} />\n </div>\n </div>\n </div>\n );\n}\n\n// ─── Settings card ────────────────────────────────────────────────────────────\n\nexport interface ChangelogSettingsCardProps {\n /** Raw CHANGELOG.md contents (e.g. `import md from \"../CHANGELOG.md?raw\"`). */\n markdown: string;\n /** How many recent releases to show inline before \"View all\". Default: 2. */\n limit?: number;\n /** Card heading. Default: \"What's new\". */\n title?: string;\n closeLabel?: string;\n emptyText?: string;\n viewAllLabel?: string;\n className?: string;\n}\n\nexport function ChangelogSettingsCard({\n markdown,\n limit = 2,\n title = \"What's new\",\n closeLabel = \"Close\",\n emptyText = \"No updates yet.\",\n viewAllLabel = \"View all updates\",\n className,\n}: ChangelogSettingsCardProps) {\n const entries = useMemo(() => parseChangelog(markdown), [markdown]);\n const [dialogOpen, setDialogOpen] = useState(false);\n\n if (entries.length === 0) return null;\n\n const shown = entries.slice(0, limit);\n const hasMore = entries.length > shown.length;\n\n return (\n <div\n className={cn(\n \"rounded-lg border border-border bg-card text-card-foreground\",\n className,\n )}\n >\n <div className=\"flex items-center gap-2 border-b border-border px-5 py-4\">\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n </div>\n <div className=\"px-5 py-4\">\n <ChangelogEntries entries={shown} emptyText={emptyText} />\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setDialogOpen(true)}\n className=\"mt-4 text-sm font-medium text-foreground underline underline-offset-2\"\n >\n {viewAllLabel}\n </button>\n )}\n </div>\n <ChangelogDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n markdown={markdown}\n title={title}\n closeLabel={closeLabel}\n emptyText={emptyText}\n />\n </div>\n );\n}\n\nexport { parseChangelog };\nexport type { ChangelogEntry };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExtensionsSidebarSection.d.ts","sourceRoot":"","sources":["../../../src/client/extensions/ExtensionsSidebarSection.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ExtensionsSidebarSection.d.ts","sourceRoot":"","sources":["../../../src/client/extensions/ExtensionsSidebarSection.tsx"],"names":[],"mappings":"AAskBA,wBAAgB,wBAAwB,gCA6lBvC"}
|
|
@@ -11,6 +11,7 @@ import { HoverCard, HoverCardContent, HoverCardTrigger, } from "../components/ui
|
|
|
11
11
|
import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
12
12
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
13
13
|
import { PromptComposer } from "../composer/PromptComposer.js";
|
|
14
|
+
import { DEFAULT_LOCALE, useOptionalLocale } from "../i18n.js";
|
|
14
15
|
import { cn } from "../utils.js";
|
|
15
16
|
import { deleteOrHideExtension, invalidateExtensionRemoval, } from "./delete-extension.js";
|
|
16
17
|
import { applyToolsOrder, getToolsOrder, setToolsOrder, } from "./extension-order.js";
|
|
@@ -19,6 +20,332 @@ const FAVORITES_KEY = "extensions-favorites";
|
|
|
19
20
|
const COLLAPSED_EXTENSION_COUNT = 3;
|
|
20
21
|
const EXTENSIONS_OPEN_KEY = "extensions-sidebar-open";
|
|
21
22
|
const EXTENSIONS_SORT_MODE_KEY = "extensions-sort-mode";
|
|
23
|
+
const EXTENSIONS_COPY = {
|
|
24
|
+
"en-US": {
|
|
25
|
+
title: "Extensions",
|
|
26
|
+
description: "Build small sandboxed apps that can read app data, call actions, and save their own state.",
|
|
27
|
+
open: "Open extensions",
|
|
28
|
+
learnMore: "Learn more",
|
|
29
|
+
sortOptions: "Extensions sort options",
|
|
30
|
+
sortTooltip: "Extensions sort",
|
|
31
|
+
sortBy: "Sort by",
|
|
32
|
+
mostUsed: "Most used",
|
|
33
|
+
alphabetical: "Alphabetical",
|
|
34
|
+
manualOrder: "Manual order",
|
|
35
|
+
showHidden: "Show hidden",
|
|
36
|
+
newExtension: "New extension",
|
|
37
|
+
createPlaceholder: "Describe what you'd like to build...",
|
|
38
|
+
collapse: "Collapse extensions",
|
|
39
|
+
expand: "Expand extensions",
|
|
40
|
+
reorder: (name) => `Reorder ${name}`,
|
|
41
|
+
dragToReorder: "Drag to reorder",
|
|
42
|
+
hiddenFromEveryone: "Hidden from everyone",
|
|
43
|
+
file: "File",
|
|
44
|
+
unfavorite: "Unfavorite",
|
|
45
|
+
favorite: "Favorite",
|
|
46
|
+
actions: "Extension actions",
|
|
47
|
+
editInFiles: "Edit in files",
|
|
48
|
+
rename: "Rename",
|
|
49
|
+
unhideForEveryone: "Unhide for everyone",
|
|
50
|
+
hideFromEveryone: "Hide from everyone",
|
|
51
|
+
removeFromMyList: "Remove from my list",
|
|
52
|
+
delete: "Delete",
|
|
53
|
+
showLess: "show less",
|
|
54
|
+
showMore: "show more",
|
|
55
|
+
},
|
|
56
|
+
"zh-CN": {
|
|
57
|
+
title: "扩展",
|
|
58
|
+
description: "构建可读取应用数据、调用操作并保存自身状态的小型沙盒应用。",
|
|
59
|
+
open: "打开扩展",
|
|
60
|
+
learnMore: "了解更多",
|
|
61
|
+
sortOptions: "扩展排序选项",
|
|
62
|
+
sortTooltip: "扩展排序",
|
|
63
|
+
sortBy: "排序方式",
|
|
64
|
+
mostUsed: "最常用",
|
|
65
|
+
alphabetical: "按字母顺序",
|
|
66
|
+
manualOrder: "手动排序",
|
|
67
|
+
showHidden: "显示隐藏项",
|
|
68
|
+
newExtension: "新建扩展",
|
|
69
|
+
createPlaceholder: "描述你想构建的内容...",
|
|
70
|
+
collapse: "收起扩展",
|
|
71
|
+
expand: "展开扩展",
|
|
72
|
+
reorder: (name) => `重新排序 ${name}`,
|
|
73
|
+
dragToReorder: "拖动以重新排序",
|
|
74
|
+
hiddenFromEveryone: "已对所有人隐藏",
|
|
75
|
+
file: "文件",
|
|
76
|
+
unfavorite: "取消收藏",
|
|
77
|
+
favorite: "收藏",
|
|
78
|
+
actions: "扩展操作",
|
|
79
|
+
editInFiles: "在文件中编辑",
|
|
80
|
+
rename: "重命名",
|
|
81
|
+
unhideForEveryone: "对所有人取消隐藏",
|
|
82
|
+
hideFromEveryone: "对所有人隐藏",
|
|
83
|
+
removeFromMyList: "从我的列表中移除",
|
|
84
|
+
delete: "删除",
|
|
85
|
+
showLess: "收起",
|
|
86
|
+
showMore: "显示更多",
|
|
87
|
+
},
|
|
88
|
+
"es-ES": {
|
|
89
|
+
title: "Extensiones",
|
|
90
|
+
description: "Crea pequeñas apps aisladas que pueden leer datos de la app, llamar acciones y guardar su propio estado.",
|
|
91
|
+
open: "Abrir extensiones",
|
|
92
|
+
learnMore: "Más información",
|
|
93
|
+
sortOptions: "Opciones de orden de extensiones",
|
|
94
|
+
sortTooltip: "Orden de extensiones",
|
|
95
|
+
sortBy: "Ordenar por",
|
|
96
|
+
mostUsed: "Más usadas",
|
|
97
|
+
alphabetical: "Alfabético",
|
|
98
|
+
manualOrder: "Orden manual",
|
|
99
|
+
showHidden: "Mostrar ocultas",
|
|
100
|
+
newExtension: "Nueva extensión",
|
|
101
|
+
createPlaceholder: "Describe lo que quieres crear...",
|
|
102
|
+
collapse: "Contraer extensiones",
|
|
103
|
+
expand: "Expandir extensiones",
|
|
104
|
+
reorder: (name) => `Reordenar ${name}`,
|
|
105
|
+
dragToReorder: "Arrastra para reordenar",
|
|
106
|
+
hiddenFromEveryone: "Oculta para todos",
|
|
107
|
+
file: "Archivo",
|
|
108
|
+
unfavorite: "Quitar de favoritos",
|
|
109
|
+
favorite: "Favorito",
|
|
110
|
+
actions: "Acciones de extensión",
|
|
111
|
+
editInFiles: "Editar en archivos",
|
|
112
|
+
rename: "Renombrar",
|
|
113
|
+
unhideForEveryone: "Mostrar para todos",
|
|
114
|
+
hideFromEveryone: "Ocultar para todos",
|
|
115
|
+
removeFromMyList: "Quitar de mi lista",
|
|
116
|
+
delete: "Eliminar",
|
|
117
|
+
showLess: "mostrar menos",
|
|
118
|
+
showMore: "mostrar más",
|
|
119
|
+
},
|
|
120
|
+
"fr-FR": {
|
|
121
|
+
title: "Extensions",
|
|
122
|
+
description: "Créez de petites apps sandboxées capables de lire les données de l'app, d'appeler des actions et d'enregistrer leur propre état.",
|
|
123
|
+
open: "Ouvrir les extensions",
|
|
124
|
+
learnMore: "En savoir plus",
|
|
125
|
+
sortOptions: "Options de tri des extensions",
|
|
126
|
+
sortTooltip: "Tri des extensions",
|
|
127
|
+
sortBy: "Trier par",
|
|
128
|
+
mostUsed: "Les plus utilisées",
|
|
129
|
+
alphabetical: "Alphabétique",
|
|
130
|
+
manualOrder: "Ordre manuel",
|
|
131
|
+
showHidden: "Afficher les masquées",
|
|
132
|
+
newExtension: "Nouvelle extension",
|
|
133
|
+
createPlaceholder: "Décrivez ce que vous voulez créer...",
|
|
134
|
+
collapse: "Replier les extensions",
|
|
135
|
+
expand: "Déplier les extensions",
|
|
136
|
+
reorder: (name) => `Réordonner ${name}`,
|
|
137
|
+
dragToReorder: "Faire glisser pour réordonner",
|
|
138
|
+
hiddenFromEveryone: "Masquée pour tout le monde",
|
|
139
|
+
file: "Fichier",
|
|
140
|
+
unfavorite: "Retirer des favoris",
|
|
141
|
+
favorite: "Favori",
|
|
142
|
+
actions: "Actions de l'extension",
|
|
143
|
+
editInFiles: "Modifier dans les fichiers",
|
|
144
|
+
rename: "Renommer",
|
|
145
|
+
unhideForEveryone: "Afficher pour tout le monde",
|
|
146
|
+
hideFromEveryone: "Masquer pour tout le monde",
|
|
147
|
+
removeFromMyList: "Retirer de ma liste",
|
|
148
|
+
delete: "Supprimer",
|
|
149
|
+
showLess: "afficher moins",
|
|
150
|
+
showMore: "afficher plus",
|
|
151
|
+
},
|
|
152
|
+
"de-DE": {
|
|
153
|
+
title: "Erweiterungen",
|
|
154
|
+
description: "Erstelle kleine Sandbox-Apps, die App-Daten lesen, Aktionen aufrufen und ihren eigenen Zustand speichern können.",
|
|
155
|
+
open: "Erweiterungen öffnen",
|
|
156
|
+
learnMore: "Mehr erfahren",
|
|
157
|
+
sortOptions: "Sortieroptionen für Erweiterungen",
|
|
158
|
+
sortTooltip: "Erweiterungen sortieren",
|
|
159
|
+
sortBy: "Sortieren nach",
|
|
160
|
+
mostUsed: "Am häufigsten genutzt",
|
|
161
|
+
alphabetical: "Alphabetisch",
|
|
162
|
+
manualOrder: "Manuelle Reihenfolge",
|
|
163
|
+
showHidden: "Ausgeblendete anzeigen",
|
|
164
|
+
newExtension: "Neue Erweiterung",
|
|
165
|
+
createPlaceholder: "Beschreibe, was du erstellen möchtest...",
|
|
166
|
+
collapse: "Erweiterungen einklappen",
|
|
167
|
+
expand: "Erweiterungen ausklappen",
|
|
168
|
+
reorder: (name) => `${name} neu anordnen`,
|
|
169
|
+
dragToReorder: "Zum Neuordnen ziehen",
|
|
170
|
+
hiddenFromEveryone: "Für alle ausgeblendet",
|
|
171
|
+
file: "Datei",
|
|
172
|
+
unfavorite: "Aus Favoriten entfernen",
|
|
173
|
+
favorite: "Favorisieren",
|
|
174
|
+
actions: "Erweiterungsaktionen",
|
|
175
|
+
editInFiles: "In Dateien bearbeiten",
|
|
176
|
+
rename: "Umbenennen",
|
|
177
|
+
unhideForEveryone: "Für alle einblenden",
|
|
178
|
+
hideFromEveryone: "Für alle ausblenden",
|
|
179
|
+
removeFromMyList: "Aus meiner Liste entfernen",
|
|
180
|
+
delete: "Löschen",
|
|
181
|
+
showLess: "weniger anzeigen",
|
|
182
|
+
showMore: "mehr anzeigen",
|
|
183
|
+
},
|
|
184
|
+
"ja-JP": {
|
|
185
|
+
title: "拡張機能",
|
|
186
|
+
description: "アプリデータを読み取り、アクションを呼び出し、独自の状態を保存できる小さなサンドボックスアプリを作成します。",
|
|
187
|
+
open: "拡張機能を開く",
|
|
188
|
+
learnMore: "詳しく見る",
|
|
189
|
+
sortOptions: "拡張機能の並べ替えオプション",
|
|
190
|
+
sortTooltip: "拡張機能の並べ替え",
|
|
191
|
+
sortBy: "並べ替え",
|
|
192
|
+
mostUsed: "よく使う順",
|
|
193
|
+
alphabetical: "アルファベット順",
|
|
194
|
+
manualOrder: "手動順",
|
|
195
|
+
showHidden: "非表示を表示",
|
|
196
|
+
newExtension: "新しい拡張機能",
|
|
197
|
+
createPlaceholder: "作りたいものを説明してください...",
|
|
198
|
+
collapse: "拡張機能を折りたたむ",
|
|
199
|
+
expand: "拡張機能を展開",
|
|
200
|
+
reorder: (name) => `${name} を並べ替え`,
|
|
201
|
+
dragToReorder: "ドラッグして並べ替え",
|
|
202
|
+
hiddenFromEveryone: "全員に非表示",
|
|
203
|
+
file: "ファイル",
|
|
204
|
+
unfavorite: "お気に入り解除",
|
|
205
|
+
favorite: "お気に入り",
|
|
206
|
+
actions: "拡張機能の操作",
|
|
207
|
+
editInFiles: "ファイルで編集",
|
|
208
|
+
rename: "名前を変更",
|
|
209
|
+
unhideForEveryone: "全員に表示",
|
|
210
|
+
hideFromEveryone: "全員に非表示",
|
|
211
|
+
removeFromMyList: "自分のリストから削除",
|
|
212
|
+
delete: "削除",
|
|
213
|
+
showLess: "少なく表示",
|
|
214
|
+
showMore: "さらに表示",
|
|
215
|
+
},
|
|
216
|
+
"ko-KR": {
|
|
217
|
+
title: "확장",
|
|
218
|
+
description: "앱 데이터를 읽고, 액션을 호출하고, 자체 상태를 저장할 수 있는 작은 샌드박스 앱을 만듭니다.",
|
|
219
|
+
open: "확장 열기",
|
|
220
|
+
learnMore: "자세히 알아보기",
|
|
221
|
+
sortOptions: "확장 정렬 옵션",
|
|
222
|
+
sortTooltip: "확장 정렬",
|
|
223
|
+
sortBy: "정렬 기준",
|
|
224
|
+
mostUsed: "가장 많이 사용",
|
|
225
|
+
alphabetical: "가나다순",
|
|
226
|
+
manualOrder: "수동 순서",
|
|
227
|
+
showHidden: "숨김 항목 표시",
|
|
228
|
+
newExtension: "새 확장",
|
|
229
|
+
createPlaceholder: "만들고 싶은 것을 설명하세요...",
|
|
230
|
+
collapse: "확장 접기",
|
|
231
|
+
expand: "확장 펼치기",
|
|
232
|
+
reorder: (name) => `${name} 순서 변경`,
|
|
233
|
+
dragToReorder: "드래그하여 순서 변경",
|
|
234
|
+
hiddenFromEveryone: "모두에게 숨김",
|
|
235
|
+
file: "파일",
|
|
236
|
+
unfavorite: "즐겨찾기 해제",
|
|
237
|
+
favorite: "즐겨찾기",
|
|
238
|
+
actions: "확장 작업",
|
|
239
|
+
editInFiles: "파일에서 편집",
|
|
240
|
+
rename: "이름 변경",
|
|
241
|
+
unhideForEveryone: "모두에게 표시",
|
|
242
|
+
hideFromEveryone: "모두에게 숨기기",
|
|
243
|
+
removeFromMyList: "내 목록에서 제거",
|
|
244
|
+
delete: "삭제",
|
|
245
|
+
showLess: "덜 보기",
|
|
246
|
+
showMore: "더 보기",
|
|
247
|
+
},
|
|
248
|
+
"pt-BR": {
|
|
249
|
+
title: "Extensões",
|
|
250
|
+
description: "Crie pequenos apps isolados que podem ler dados do app, chamar ações e salvar o próprio estado.",
|
|
251
|
+
open: "Abrir extensões",
|
|
252
|
+
learnMore: "Saiba mais",
|
|
253
|
+
sortOptions: "Opções de ordenação das extensões",
|
|
254
|
+
sortTooltip: "Ordenação das extensões",
|
|
255
|
+
sortBy: "Ordenar por",
|
|
256
|
+
mostUsed: "Mais usadas",
|
|
257
|
+
alphabetical: "Alfabética",
|
|
258
|
+
manualOrder: "Ordem manual",
|
|
259
|
+
showHidden: "Mostrar ocultas",
|
|
260
|
+
newExtension: "Nova extensão",
|
|
261
|
+
createPlaceholder: "Descreva o que você quer criar...",
|
|
262
|
+
collapse: "Recolher extensões",
|
|
263
|
+
expand: "Expandir extensões",
|
|
264
|
+
reorder: (name) => `Reordenar ${name}`,
|
|
265
|
+
dragToReorder: "Arraste para reordenar",
|
|
266
|
+
hiddenFromEveryone: "Oculta para todos",
|
|
267
|
+
file: "Arquivo",
|
|
268
|
+
unfavorite: "Remover dos favoritos",
|
|
269
|
+
favorite: "Favoritar",
|
|
270
|
+
actions: "Ações da extensão",
|
|
271
|
+
editInFiles: "Editar em arquivos",
|
|
272
|
+
rename: "Renomear",
|
|
273
|
+
unhideForEveryone: "Mostrar para todos",
|
|
274
|
+
hideFromEveryone: "Ocultar para todos",
|
|
275
|
+
removeFromMyList: "Remover da minha lista",
|
|
276
|
+
delete: "Excluir",
|
|
277
|
+
showLess: "mostrar menos",
|
|
278
|
+
showMore: "mostrar mais",
|
|
279
|
+
},
|
|
280
|
+
"hi-IN": {
|
|
281
|
+
title: "एक्सटेंशन",
|
|
282
|
+
description: "छोटे सैंडबॉक्स ऐप बनाएं जो ऐप डेटा पढ़ सकते हैं, कार्रवाइयां चला सकते हैं और अपना स्टेट सहेज सकते हैं।",
|
|
283
|
+
open: "एक्सटेंशन खोलें",
|
|
284
|
+
learnMore: "और जानें",
|
|
285
|
+
sortOptions: "एक्सटेंशन क्रम विकल्प",
|
|
286
|
+
sortTooltip: "एक्सटेंशन क्रम",
|
|
287
|
+
sortBy: "इसके अनुसार क्रमबद्ध करें",
|
|
288
|
+
mostUsed: "सबसे अधिक उपयोग",
|
|
289
|
+
alphabetical: "वर्णानुक्रम",
|
|
290
|
+
manualOrder: "मैन्युअल क्रम",
|
|
291
|
+
showHidden: "छिपे हुए दिखाएं",
|
|
292
|
+
newExtension: "नया एक्सटेंशन",
|
|
293
|
+
createPlaceholder: "बताएं कि आप क्या बनाना चाहते हैं...",
|
|
294
|
+
collapse: "एक्सटेंशन समेटें",
|
|
295
|
+
expand: "एक्सटेंशन फैलाएं",
|
|
296
|
+
reorder: (name) => `${name} का क्रम बदलें`,
|
|
297
|
+
dragToReorder: "क्रम बदलने के लिए खींचें",
|
|
298
|
+
hiddenFromEveryone: "सभी से छिपा हुआ",
|
|
299
|
+
file: "फ़ाइल",
|
|
300
|
+
unfavorite: "पसंदीदा से हटाएं",
|
|
301
|
+
favorite: "पसंदीदा",
|
|
302
|
+
actions: "एक्सटेंशन कार्रवाइयां",
|
|
303
|
+
editInFiles: "फ़ाइलों में संपादित करें",
|
|
304
|
+
rename: "नाम बदलें",
|
|
305
|
+
unhideForEveryone: "सभी के लिए दिखाएं",
|
|
306
|
+
hideFromEveryone: "सभी से छिपाएं",
|
|
307
|
+
removeFromMyList: "मेरी सूची से हटाएं",
|
|
308
|
+
delete: "हटाएं",
|
|
309
|
+
showLess: "कम दिखाएं",
|
|
310
|
+
showMore: "और दिखाएं",
|
|
311
|
+
},
|
|
312
|
+
"ar-SA": {
|
|
313
|
+
title: "الإضافات",
|
|
314
|
+
description: "أنشئ تطبيقات صغيرة معزولة يمكنها قراءة بيانات التطبيق واستدعاء الإجراءات وحفظ حالتها الخاصة.",
|
|
315
|
+
open: "فتح الإضافات",
|
|
316
|
+
learnMore: "معرفة المزيد",
|
|
317
|
+
sortOptions: "خيارات ترتيب الإضافات",
|
|
318
|
+
sortTooltip: "ترتيب الإضافات",
|
|
319
|
+
sortBy: "ترتيب حسب",
|
|
320
|
+
mostUsed: "الأكثر استخدامًا",
|
|
321
|
+
alphabetical: "أبجديًا",
|
|
322
|
+
manualOrder: "ترتيب يدوي",
|
|
323
|
+
showHidden: "إظهار المخفية",
|
|
324
|
+
newExtension: "إضافة جديدة",
|
|
325
|
+
createPlaceholder: "صف ما تريد إنشاءه...",
|
|
326
|
+
collapse: "طي الإضافات",
|
|
327
|
+
expand: "توسيع الإضافات",
|
|
328
|
+
reorder: (name) => `إعادة ترتيب ${name}`,
|
|
329
|
+
dragToReorder: "اسحب لإعادة الترتيب",
|
|
330
|
+
hiddenFromEveryone: "مخفية عن الجميع",
|
|
331
|
+
file: "ملف",
|
|
332
|
+
unfavorite: "إزالة من المفضلة",
|
|
333
|
+
favorite: "إضافة إلى المفضلة",
|
|
334
|
+
actions: "إجراءات الإضافة",
|
|
335
|
+
editInFiles: "تحرير في الملفات",
|
|
336
|
+
rename: "إعادة تسمية",
|
|
337
|
+
unhideForEveryone: "إظهار للجميع",
|
|
338
|
+
hideFromEveryone: "إخفاء عن الجميع",
|
|
339
|
+
removeFromMyList: "إزالة من قائمتي",
|
|
340
|
+
delete: "حذف",
|
|
341
|
+
showLess: "إظهار أقل",
|
|
342
|
+
showMore: "إظهار المزيد",
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
function useExtensionsCopy() {
|
|
346
|
+
const locale = useOptionalLocale()?.locale ?? DEFAULT_LOCALE;
|
|
347
|
+
return EXTENSIONS_COPY[locale] ?? EXTENSIONS_COPY[DEFAULT_LOCALE];
|
|
348
|
+
}
|
|
22
349
|
function getFavorites() {
|
|
23
350
|
try {
|
|
24
351
|
const raw = localStorage.getItem(FAVORITES_KEY);
|
|
@@ -84,16 +411,17 @@ function sortByName(items) {
|
|
|
84
411
|
return name !== 0 ? name : a.id.localeCompare(b.id);
|
|
85
412
|
});
|
|
86
413
|
}
|
|
87
|
-
function ExtensionSortMenu({ value, onChange, showHidden, onShowHiddenChange, }) {
|
|
88
|
-
return (_jsxs(DropdownMenu, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground/45 opacity-0 transition-all hover:bg-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/extensions-section:opacity-100", "aria-label":
|
|
414
|
+
function ExtensionSortMenu({ value, onChange, showHidden, onShowHiddenChange, copy, }) {
|
|
415
|
+
return (_jsxs(DropdownMenu, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground/45 opacity-0 transition-all hover:bg-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/extensions-section:opacity-100", "aria-label": copy.sortOptions, children: _jsx(IconSettings, { className: "h-3.5 w-3.5" }) }) }) }), _jsx(TooltipContent, { children: copy.sortTooltip })] }), _jsxs(DropdownMenuContent, { side: "right", align: "start", className: "w-44", children: [_jsx(DropdownMenuLabel, { children: copy.sortBy }), _jsxs(DropdownMenuRadioGroup, { value: value, onValueChange: (next) => {
|
|
89
416
|
if (next === "most-used" ||
|
|
90
417
|
next === "alphabetical" ||
|
|
91
418
|
next === "manual") {
|
|
92
419
|
onChange(next);
|
|
93
420
|
}
|
|
94
|
-
}, children: [_jsx(DropdownMenuRadioItem, { value: "most-used", children:
|
|
421
|
+
}, children: [_jsx(DropdownMenuRadioItem, { value: "most-used", children: copy.mostUsed }), _jsx(DropdownMenuRadioItem, { value: "alphabetical", children: copy.alphabetical }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuRadioItem, { value: "manual", children: copy.manualOrder })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuCheckboxItem, { checked: showHidden, onCheckedChange: (checked) => onShowHiddenChange(Boolean(checked)), children: copy.showHidden })] })] }));
|
|
95
422
|
}
|
|
96
423
|
export function ExtensionsSidebarSection() {
|
|
424
|
+
const copy = useExtensionsCopy();
|
|
97
425
|
const location = useLocation();
|
|
98
426
|
const navigate = useNavigate();
|
|
99
427
|
const queryClient = useQueryClient();
|
|
@@ -292,7 +620,7 @@ export function ExtensionsSidebarSection() {
|
|
|
292
620
|
};
|
|
293
621
|
return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs("div", { className: "relative min-w-0 py-1", children: [_jsxs("div", { className: cn("group/extensions-section relative flex w-full min-w-0 items-center rounded-md text-sm font-medium transition-all hover:text-primary", location.pathname.startsWith("/extensions")
|
|
294
622
|
? "text-sidebar-accent-foreground"
|
|
295
|
-
: "text-muted-foreground hover:bg-sidebar-accent/50", extensionsOpen && sortedTools.length > 0 && "mb-1"), children: [_jsx("button", { type: "button", onClick: toggleExtensionsOpen, className: "absolute inset-0 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": extensionsOpen ?
|
|
623
|
+
: "text-muted-foreground hover:bg-sidebar-accent/50", extensionsOpen && sortedTools.length > 0 && "mb-1"), children: [_jsx("button", { type: "button", onClick: toggleExtensionsOpen, className: "absolute inset-0 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": extensionsOpen ? copy.collapse : copy.expand, "aria-expanded": extensionsOpen }), _jsxs("div", { className: "pointer-events-none relative z-10 flex min-w-0 flex-1 items-center gap-2 px-3 py-1.5 pr-20", children: [_jsx(IconTool, { className: "h-4 w-4 shrink-0" }), _jsxs(HoverCard, { openDelay: 1200, closeDelay: 200, children: [_jsx(HoverCardTrigger, { asChild: true, children: _jsx("span", { className: "pointer-events-auto min-w-0 select-none truncate", onClick: toggleExtensionsOpen, children: copy.title }) }), _jsxs(HoverCardContent, { side: "top", align: "start", sideOffset: 8, className: "w-72 space-y-3 p-3", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: copy.title }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: copy.description })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Link, { to: "/extensions", className: "inline-flex h-8 items-center rounded-md border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent", children: copy.open }), _jsx("a", { href: "https://agent-native.com/docs/extensions", target: "_blank", rel: "noopener noreferrer", className: "inline-flex h-8 items-center rounded-md px-2.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground", children: copy.learnMore })] })] })] })] }), _jsxs("div", { className: "absolute right-1 top-1/2 z-20 flex -translate-y-1/2 items-center", children: [_jsx(ExtensionSortMenu, { value: sortModeState, onChange: setExtensionSortMode, showHidden: showGloballyHidden, onShowHiddenChange: setShowGloballyHidden, copy: copy }), _jsxs(Popover, { open: showCreate, onOpenChange: setShowCreate, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-accent-foreground", "aria-label": copy.newExtension, children: _jsx(IconPlus, { className: "h-3.5 w-3.5" }) }) }), _jsxs(PopoverContent, { side: "right", align: "start", className: "w-[420px] p-3", children: [_jsx("p", { className: "px-1 pb-2 text-sm font-semibold text-foreground", children: copy.newExtension }), _jsx(PromptComposer, { autoFocus: true, placeholder: copy.createPlaceholder, draftScope: "extensions:sidebar-create", onSubmit: handleCreate })] })] }), _jsx("button", { type: "button", onClick: toggleExtensionsOpen, className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground/70 hover:bg-accent hover:text-foreground", "aria-label": extensionsOpen ? copy.collapse : copy.expand, "aria-expanded": extensionsOpen, children: _jsx(IconChevronDown, { className: cn("h-3.5 w-3.5 shrink-0 transition-transform", !extensionsOpen && "-rotate-90") }) })] })] }), extensionsOpen &&
|
|
296
624
|
(isLoading ? (_jsx("div", { className: "min-w-0 space-y-0.5 px-0.5", children: [1, 2, 3].map((i) => (_jsx("div", { className: "flex items-center rounded-md px-2 py-1.5", children: _jsx("div", { className: "h-3 rounded bg-muted animate-pulse", style: { width: `${60 + i * 20}px` } }) }, i))) })) : sortedTools.length === 0 ? null : (_jsxs("div", { className: "min-w-0 space-y-0.5 px-0.5", children: [visibleTools.map((extension) => {
|
|
297
625
|
const isActive = isExtensionPathname(location.pathname, extension.id);
|
|
298
626
|
const isFav = favoriteIds.has(extension.id);
|
|
@@ -324,7 +652,7 @@ export function ExtensionsSidebarSection() {
|
|
|
324
652
|
}, onDragEnd: () => {
|
|
325
653
|
setDraggingId(null);
|
|
326
654
|
setDragOverId(null);
|
|
327
|
-
}, className: "-ml-2 cursor-grab rounded p-0.5 text-muted-foreground/30 opacity-0 transition-colors hover:text-muted-foreground/70 active:cursor-grabbing group-hover/extension:opacity-100 group-focus-within/extension:opacity-100", "aria-label":
|
|
655
|
+
}, className: "-ml-2 cursor-grab rounded p-0.5 text-muted-foreground/30 opacity-0 transition-colors hover:text-muted-foreground/70 active:cursor-grabbing group-hover/extension:opacity-100 group-focus-within/extension:opacity-100", "aria-label": copy.reorder(extension.name), children: _jsx(IconGripVertical, { className: "h-3 w-3" }) }) }), _jsx(TooltipContent, { children: copy.dragToReorder })] }), _jsx(Link, { to: extensionPath(extension.id, extension.name), className: cn("flex min-w-0 flex-1 items-center rounded-md px-2 py-1.5 pr-12 text-xs transition-[padding,color,background-color] md:pr-2 md:group-hover/extension:pr-12 md:group-focus-within/extension:pr-12", actionsVisible && "md:pr-12", isActive
|
|
328
656
|
? "bg-accent text-accent-foreground font-medium"
|
|
329
657
|
: "text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground"), children: isRenamingThis ? (_jsx("input", { autoFocus: true, value: renameValue, onChange: (e) => setRenameValue(e.target.value), onBlur: () => submitRename(extension.id), onKeyDown: (e) => {
|
|
330
658
|
if (e.key === "Enter")
|
|
@@ -334,17 +662,17 @@ export function ExtensionsSidebarSection() {
|
|
|
334
662
|
}, onClick: (e) => {
|
|
335
663
|
e.preventDefault();
|
|
336
664
|
e.stopPropagation();
|
|
337
|
-
}, className: "min-w-0 flex-1 truncate border-b border-primary bg-transparent px-0 py-0 text-xs outline-none" })) : (_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [extension.globallyHidden && (_jsx(IconEyeOff, { className: "h-3 w-3 shrink-0 text-muted-foreground/60", "aria-label":
|
|
665
|
+
}, className: "min-w-0 flex-1 truncate border-b border-primary bg-transparent px-0 py-0 text-xs outline-none" })) : (_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [extension.globallyHidden && (_jsx(IconEyeOff, { className: "h-3 w-3 shrink-0 text-muted-foreground/60", "aria-label": copy.hiddenFromEveryone })), _jsx("span", { className: "block truncate", children: extension.name }), isLocalExtension && (_jsx("span", { className: "shrink-0 rounded border border-border px-1 text-[9px] font-medium uppercase tracking-wide text-muted-foreground/70", children: copy.file }))] })) }), _jsxs("div", { className: cn("pointer-events-none absolute right-1 top-1/2 flex -translate-y-1/2 items-center gap-0.5 opacity-100 transition-opacity md:opacity-0 md:group-hover/extension:opacity-100 md:group-focus-within/extension:opacity-100", actionsVisible && "md:opacity-100"), children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
338
666
|
e.preventDefault();
|
|
339
667
|
e.stopPropagation();
|
|
340
668
|
toggleFavorite(extension.id);
|
|
341
669
|
}, className: cn("pointer-events-auto cursor-pointer rounded p-0.5 transition-colors", isFav
|
|
342
670
|
? "text-yellow-500"
|
|
343
|
-
: "text-muted-foreground/40 hover:text-yellow-500"), "aria-label": isFav ?
|
|
671
|
+
: "text-muted-foreground/40 hover:text-yellow-500"), "aria-label": isFav ? copy.unfavorite : copy.favorite, children: isFav ? (_jsx(IconStarFilled, { className: "h-3 w-3" })) : (_jsx(IconStar, { className: "h-3 w-3" })) }), _jsxs(DropdownMenu, { open: menuOpenId === extension.id, onOpenChange: (open) => setMenuOpenId(open ? extension.id : null), children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "pointer-events-auto cursor-pointer rounded p-0.5 text-muted-foreground/40 transition-colors hover:text-foreground", "aria-label": copy.actions, children: _jsx(IconDots, { className: "h-3 w-3" }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 4, className: "min-w-[140px]", children: [isLocalExtension ? (_jsxs(DropdownMenuItem, { disabled: true, children: [_jsx(IconPencil, { className: "h-3.5 w-3.5" }), copy.editInFiles] })) : (_jsxs(DropdownMenuItem, { onSelect: () => startRename(extension), children: [_jsx(IconPencil, { className: "h-3.5 w-3.5" }), copy.rename] })), !isLocalExtension &&
|
|
344
672
|
extension.canDelete !== false &&
|
|
345
|
-
(extension.globallyHidden ? (_jsxs(DropdownMenuItem, { onSelect: () => handleGlobalUnhide(extension), children: [_jsx(IconEye, { className: "h-3.5 w-3.5" }),
|
|
346
|
-
?
|
|
347
|
-
:
|
|
348
|
-
}), hasMoreExtensions && (_jsx("button", { type: "button", "aria-expanded": showAllExtensions, onClick: () => setShowAllExtensions((current) => !current), className: "ml-5 mt-1 inline-flex h-5 items-center rounded px-1.5 text-[11px] font-medium text-muted-foreground/60 transition-colors hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", children: showAllExtensions ?
|
|
673
|
+
(extension.globallyHidden ? (_jsxs(DropdownMenuItem, { onSelect: () => handleGlobalUnhide(extension), children: [_jsx(IconEye, { className: "h-3.5 w-3.5" }), copy.unhideForEveryone] })) : (_jsxs(DropdownMenuItem, { onSelect: () => handleGlobalHide(extension), children: [_jsx(IconEyeOff, { className: "h-3.5 w-3.5" }), copy.hideFromEveryone] }))), !isLocalExtension && (_jsxs(DropdownMenuItem, { onSelect: () => handleDelete(extension), className: "text-destructive focus:text-destructive", children: [_jsx(IconTrash, { className: "h-3.5 w-3.5" }), extension.canDelete === false
|
|
674
|
+
? copy.removeFromMyList
|
|
675
|
+
: copy.delete] }))] })] })] })] }, extension.id));
|
|
676
|
+
}), hasMoreExtensions && (_jsx("button", { type: "button", "aria-expanded": showAllExtensions, onClick: () => setShowAllExtensions((current) => !current), className: "ml-5 mt-1 inline-flex h-5 items-center rounded px-1.5 text-[11px] font-medium text-muted-foreground/60 transition-colors hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", children: showAllExtensions ? copy.showLess : copy.showMore }))] })))] }) }));
|
|
349
677
|
}
|
|
350
678
|
//# sourceMappingURL=ExtensionsSidebarSection.js.map
|