diff --git a/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.5-54c23cf901-23c4c58a03.zip b/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.5-54c23cf901-23c4c58a03.zip deleted file mode 100644 index 4e81640ab..000000000 Binary files a/.yarn/cache/@sveltejs-acorn-typescript-npm-1.0.5-54c23cf901-23c4c58a03.zip and /dev/null differ diff --git a/.yarn/cache/@sveltejs-vite-plugin-svelte-inspector-npm-4.0.1-697ad2300f-af851fbeea.zip b/.yarn/cache/@sveltejs-vite-plugin-svelte-inspector-npm-4.0.1-697ad2300f-af851fbeea.zip deleted file mode 100644 index 85797e631..000000000 Binary files a/.yarn/cache/@sveltejs-vite-plugin-svelte-inspector-npm-4.0.1-697ad2300f-af851fbeea.zip and /dev/null differ diff --git a/.yarn/cache/@sveltejs-vite-plugin-svelte-npm-5.1.0-3ef6724065-5d6abc07e6.zip b/.yarn/cache/@sveltejs-vite-plugin-svelte-npm-5.1.0-3ef6724065-5d6abc07e6.zip deleted file mode 100644 index 067dac047..000000000 Binary files a/.yarn/cache/@sveltejs-vite-plugin-svelte-npm-5.1.0-3ef6724065-5d6abc07e6.zip and /dev/null differ diff --git a/.yarn/cache/axobject-query-npm-4.1.0-9703554323-e275dea9b6.zip b/.yarn/cache/axobject-query-npm-4.1.0-9703554323-e275dea9b6.zip deleted file mode 100644 index 333049a40..000000000 Binary files a/.yarn/cache/axobject-query-npm-4.1.0-9703554323-e275dea9b6.zip and /dev/null differ diff --git a/.yarn/cache/chokidar-npm-4.0.3-962354fbb4-bf2a575ea5.zip b/.yarn/cache/chokidar-npm-4.0.3-962354fbb4-bf2a575ea5.zip deleted file mode 100644 index 0085cb689..000000000 Binary files a/.yarn/cache/chokidar-npm-4.0.3-962354fbb4-bf2a575ea5.zip and /dev/null differ diff --git a/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip b/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip deleted file mode 100644 index cb05c8500..000000000 Binary files a/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip and /dev/null differ diff --git a/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-caf5f3cc2b.zip b/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-caf5f3cc2b.zip deleted file mode 100644 index a4afae9e2..000000000 Binary files a/.yarn/cache/esm-env-npm-1.2.2-c6981cc52f-caf5f3cc2b.zip and /dev/null differ diff --git a/.yarn/cache/esrap-npm-2.1.0-65b4535ba1-32c1eff181.zip b/.yarn/cache/esrap-npm-2.1.0-65b4535ba1-32c1eff181.zip deleted file mode 100644 index 56ef1b59a..000000000 Binary files a/.yarn/cache/esrap-npm-2.1.0-65b4535ba1-32c1eff181.zip and /dev/null differ diff --git a/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip b/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip deleted file mode 100644 index 286ab5771..000000000 Binary files a/.yarn/cache/is-reference-npm-3.0.3-2edaf1be22-11371fb266.zip and /dev/null differ diff --git a/.yarn/cache/kleur-npm-4.1.5-46b6135f41-44d84cc4ee.zip b/.yarn/cache/kleur-npm-4.1.5-46b6135f41-44d84cc4ee.zip deleted file mode 100644 index 60d087be4..000000000 Binary files a/.yarn/cache/kleur-npm-4.1.5-46b6135f41-44d84cc4ee.zip and /dev/null differ diff --git a/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip b/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip deleted file mode 100644 index f2f507648..000000000 Binary files a/.yarn/cache/locate-character-npm-3.0.0-40928dccbb-2d9e9f45e2.zip and /dev/null differ diff --git a/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip b/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip deleted file mode 100644 index 7521d190f..000000000 Binary files a/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip and /dev/null differ diff --git a/.yarn/cache/readdirp-npm-4.1.2-3440472afe-7b817c2659.zip b/.yarn/cache/readdirp-npm-4.1.2-3440472afe-7b817c2659.zip deleted file mode 100644 index 7ea4264a0..000000000 Binary files a/.yarn/cache/readdirp-npm-4.1.2-3440472afe-7b817c2659.zip and /dev/null differ diff --git a/.yarn/cache/sade-npm-1.8.1-4759dc74c1-1c67ba03c9.zip b/.yarn/cache/sade-npm-1.8.1-4759dc74c1-1c67ba03c9.zip deleted file mode 100644 index 00ceb65fe..000000000 Binary files a/.yarn/cache/sade-npm-1.8.1-4759dc74c1-1c67ba03c9.zip and /dev/null differ diff --git a/.yarn/cache/svelte-check-npm-4.2.2-c506e3b85f-e99c890497.zip b/.yarn/cache/svelte-check-npm-4.2.2-c506e3b85f-e99c890497.zip deleted file mode 100644 index 21e662014..000000000 Binary files a/.yarn/cache/svelte-check-npm-4.2.2-c506e3b85f-e99c890497.zip and /dev/null differ diff --git a/.yarn/cache/svelte-npm-5.35.2-57d2809550-03a7a83de1.zip b/.yarn/cache/svelte-npm-5.35.2-57d2809550-03a7a83de1.zip deleted file mode 100644 index c67f17d56..000000000 Binary files a/.yarn/cache/svelte-npm-5.35.2-57d2809550-03a7a83de1.zip and /dev/null differ diff --git a/.yarn/cache/vitefu-npm-1.0.7-410cf070c2-f780b754d8.zip b/.yarn/cache/vitefu-npm-1.0.7-410cf070c2-f780b754d8.zip deleted file mode 100644 index 736270994..000000000 Binary files a/.yarn/cache/vitefu-npm-1.0.7-410cf070c2-f780b754d8.zip and /dev/null differ diff --git a/.yarn/cache/zimmerframe-npm-1.1.2-b7b96e5d54-495e1b263b.zip b/.yarn/cache/zimmerframe-npm-1.1.2-b7b96e5d54-495e1b263b.zip deleted file mode 100644 index 8a111f586..000000000 Binary files a/.yarn/cache/zimmerframe-npm-1.1.2-b7b96e5d54-495e1b263b.zip and /dev/null differ diff --git a/plugins/renamer/index.html b/plugins/renamer/index.html index 0f2791d69..30474461d 100644 --- a/plugins/renamer/index.html +++ b/plugins/renamer/index.html @@ -1,13 +1,13 @@ - - - - - Renamer - - -
- - + + + + + Renamer + + +
+ + diff --git a/plugins/renamer/package.json b/plugins/renamer/package.json index 9100b4cc5..63ab10ff1 100644 --- a/plugins/renamer/package.json +++ b/plugins/renamer/package.json @@ -4,29 +4,23 @@ "version": "0.0.0", "type": "module", "scripts": { - "check-svelte": "svelte-check", - "dev": "vite", - "build": "vite build", + "dev": "run g:dev", + "build": "run g:build", "check-biome": "run g:check-biome", "check-eslint": "run g:check-eslint", - "pack": "npx framer-plugin-tools@latest pack", - "preview": "vite preview", + "preview": "run g:preview", + "pack": "framer-plugin-tools pack", "check-typescript": "run g:check-typescript" }, "dependencies": { - "framer-plugin": "^3.3.2", + "classnames": "^2.5.1", + "framer-plugin": "^3.5.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.1.0", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", - "svelte": "^5.35.2", - "svelte-check": "^4.2.2", - "typescript": "^5.8.3", - "vite": "^7.0.1", - "vite-plugin-framer": "^1.0.7", - "vite-plugin-mkcert": "^1.17.8" + "framer-plugin-tools": "^1.0.0" } } diff --git a/plugins/renamer/public/framer.json b/plugins/renamer/public/framer.json deleted file mode 100644 index e1d73c00f..000000000 --- a/plugins/renamer/public/framer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": "X90AKZ", - "name": "Renamer", - "modes": ["canvas"], - "icon": "/icon.png" -} diff --git a/plugins/renamer/src/App.css b/plugins/renamer/src/App.css new file mode 100644 index 000000000..d7569392b --- /dev/null +++ b/plugins/renamer/src/App.css @@ -0,0 +1,334 @@ +/* App styles */ +.app { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + position: absolute; + padding: 0 15px 15px; +} + +.app-content { + position: relative; + height: 100%; + overflow: hidden; +} + +.empty-state { + display: flex; + align-items: center; + justify-content: center; + user-select: none; + position: absolute; + inset: 0; +} + +[data-framer-theme="dark"] .empty-state img.light { + display: none; +} + +[data-framer-theme="light"] .empty-state img.dark { + display: none; +} + +.empty-state img { + width: 200px; +} + +.list { + background-color: var(--framer-color-bg); + position: absolute; + inset: 0; +} + +/* Tabs styles */ +.tabs { + display: flex; + align-items: center; + height: 52px; + flex-shrink: 0; + border-top: 1px solid var(--framer-color-divider); + border-bottom: 1px solid var(--framer-color-divider); +} + +.tab { + background: none !important; + border: 0; + width: auto; + color: #999999; + font-weight: 600; + user-select: none; + padding: 0 8px; + transition: color 200ms ease; +} + +.tab:first-child { + padding-left: 0; +} + +.tab.active { + color: var(--framer-color-text); +} + +/* TextField styles */ +.text-field { + background-color: var(--framer-color-bg-tertiary); + border-radius: 8px; + display: flex; + align-items: center; + gap: 10px; + padding: 0 10px; + height: 30px; + position: relative; + overflow: hidden; +} + +.text-field:focus-within { + box-shadow: 0 0 0 1px var(--framer-color-tint) inset; +} + +.leading-content { + color: var(--framer-color-text-tertiary); + flex-shrink: 0; + pointer-events: none; +} + +.text-field input { + background-color: transparent; + width: 100%; + height: 100%; + padding: 0; + flex-shrink: 1; + border: none; + outline: none; +} + +.text-field input:focus { + box-shadow: none; +} + +.text-field input::placeholder { + color: #999999; +} + +/* SearchReplace styles */ +.search-replace { + display: flex; + flex-direction: column; + gap: 10px; + padding-top: 15px; + border-top: 1px solid var(--framer-color-divider); +} + +.rename-button { + display: flex; + align-items: center; + justify-content: center; + user-select: none; + border: none; + border-radius: 8px; + height: 30px; + font-weight: 600; + cursor: pointer; + transition: opacity 200ms ease; +} + +.rename-button:hover, +.rename-button:focus { + opacity: 0.9; +} + +.rename-button:active { + opacity: 0.8; +} + +.rename-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +[data-framer-theme="light"] .rename-button { + background: #111 !important; + color: #fff; + --framer-color-text: #fff; +} + +[data-framer-theme="dark"] .rename-button { + background: #fff !important; + color: #111; + --framer-color-text: #111; +} + +/* Results styles */ +.results { + display: flex; + flex-direction: column; + gap: 1px; + height: 100%; + overflow: hidden; +} + +.container { + flex: 1; + overflow-y: auto; + padding-top: 15px; + padding-bottom: 15px; +} + +.results-list { + position: relative; +} + +.loading-placeholders { + padding: 15px 0; +} + +.results-empty-state { + color: var(--framer-color-text-tertiary); + display: flex; + align-items: center; + justify-content: center; + position: absolute; + inset: 0; + user-select: none; +} + +/* LayerIcon styles */ +.icon svg { + width: 100%; +} + +/* PlaceholderRenameComparison styles */ +@keyframes pulse { + 0% { + opacity: 0.3; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0.3; + } +} + +.placeholder-rename-comparison { + border-radius: 8px; + display: flex; + flex-shrink: 0; + align-items: center; + width: 100%; + height: 30px; + gap: 7px; + animation: pulse 1.5s ease infinite; + animation-fill-mode: forwards; +} + +.content { + background: color-mix(in srgb, transparent, var(--framer-color-text) 10%); + border-radius: 100px; + height: 12px; +} + +/* RenameComparison styles */ +.replace-comparison { + background: none !important; + align-items: center; + height: 30px; + gap: 10px; + width: 100%; + user-select: none; + border: none; + cursor: pointer; + text-align: left; + font-weight: 500; + padding: 0; +} + +[data-framer-theme="dark"] .replace-comparison { + color: #999999; +} + +[data-framer-theme="light"] .replace-comparison { + color: #666666; +} + +.replace-comparison.grid { + display: grid; + grid-template-columns: 1fr 12px 1fr; +} + +.chevron { + place-self: center; +} + +[data-framer-theme="dark"] .chevron { + color: #666666; +} + +[data-framer-theme="light"] .chevron { + color: #999999; +} + +.before, +.after { + display: flex; + align-items: center; + gap: 10px; + overflow: hidden; + flex: 1; +} + +.label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + width: 100%; +} + +.icon { + flex-shrink: 0; +} + +.before .icon { + color: var(--framer-color-text-tertiary); +} + +.after .frame-icon { + color: var(--framer-color-tint); +} + +.after .component-icon { + color: #9a66ff; +} + +.after .text-icon { + color: #999; +} + +/* Overflow gradients */ + +.overflow-gradient-top { + top: 0; + background: linear-gradient(to bottom, var(--framer-color-bg), transparent); +} + +.overflow-gradient-bottom { + bottom: 0; + background: linear-gradient(to top, var(--framer-color-bg), transparent); +} + +.overflow-gradient-top, +.overflow-gradient-bottom { + position: absolute; + width: 100%; + height: 40px; + transition: opacity 200ms ease; + pointer-events: none; +} + +.overflow-gradient-top.hidden, +.overflow-gradient-bottom.hidden { + opacity: 0; +} diff --git a/plugins/renamer/src/App.tsx b/plugins/renamer/src/App.tsx new file mode 100644 index 000000000..5d0d1b453 --- /dev/null +++ b/plugins/renamer/src/App.tsx @@ -0,0 +1,274 @@ +import { framer, useIsAllowedTo } from "framer-plugin" +import { useCallback, useEffect, useMemo, useRef, useState } from "react" +import starsDarkImage from "./assets/stars_dark.png" +import starsLightImage from "./assets/stars_light.png" +import Results from "./components/Results.tsx" +import SearchReplace from "./components/SearchReplace.tsx" +import Tabs from "./components/Tabs.tsx" +import { BatchProcessResults } from "./search/batch_process_results" +import { executeFilters } from "./search/execute_filters" +import type { CategoryFilter, Filter, TextFilter } from "./search/filters" +import { Indexer } from "./search/indexer" +import { cleanUpResult } from "./search/result_processors/clean_up_result" +import { renameResult } from "./search/result_processors/rename_result" +import type { CanvasNode, IndexEntry, Result } from "./search/types" +import { assertNever } from "./utils/assert" +import "./App.css" + +void framer.showUI({ + position: "top right", + width: 260, + height: 450, + minWidth: 260, + minHeight: 450, + resizable: true, +}) + +export function App() { + const isAllowedToSetAttributes = useIsAllowedTo("Node.setAttributes") + const [currentRootId, setCurrentRootId] = useState() + const [currentMode, setCurrentMode] = useState<"search" | "clean">("search") + const [indexing, setIndexing] = useState(false) + const [replacing, setReplacing] = useState(false) + const [selectedNodeIds, setSelectedNodeIds] = useState([]) + const [index, setIndex] = useState>({}) + const [textSearchFilter, setTextSearchFilter] = useState({ + id: "text-search", + type: "text", + query: "", + caseSensitive: false, + regex: false, + }) + const [categoryFilter] = useState({ + id: "category", + type: "category", + category: "all", + }) + const [replacement, setReplacement] = useState("") + + const filters: Filter[] = useMemo(() => [textSearchFilter, categoryFilter], [textSearchFilter, categoryFilter]) + const entries: IndexEntry[] = useMemo(() => Object.values(index), [index]) + const results: Result[] = useMemo(() => executeFilters(filters, entries), [filters, entries]) + + const resultsRenamerRef = useRef(null) + const replacementRef = useRef(replacement) + + const noResults = results.length === 0 && textSearchFilter.query !== "" && !indexing + + const indexer = useMemo( + () => + new Indexer({ + scope: "page", + includedNodeTypes: ["FrameNode", "SVGNode", "ComponentInstanceNode", "TextNode"], + includedAttributes: [], + + onRestarted: () => { + setIndex({}) + setIndexing(false) + }, + + onStarted: () => { + setIndexing(true) + resultsRenamerRef.current?.setReady(false) + }, + + onUpsert: entry => { + setIndex(prev => ({ ...prev, [entry.id]: entry })) + }, + + onCompleted: () => { + setIndexing(false) + resultsRenamerRef.current?.setReady(true) + }, + }), + [] + ) + + const resultsRenamer = useMemo(() => { + let renamedCount = 0 + + const instance = new BatchProcessResults({ + process: async (result: Result, node: CanvasNode) => { + switch (currentMode) { + case "search": + await node.setAttributes({ + name: renameResult(result, replacementRef.current), + }) + renamedCount += 1 // The name is always changed in search mode + break + + case "clean": { + const originalName = result.title + const cleanedName = cleanUpResult(result) + + // Only increment count if the name actually changed + if (originalName !== cleanedName) { + await node.setAttributes({ + name: cleanedName, + }) + renamedCount += 1 + } + break + } + + default: + assertNever(currentMode) + } + }, + + onStarted: () => { + setReplacing(true) + renamedCount = 0 // Reset counter at start + }, + + onCompleted: () => { + setReplacing(false) + void indexer.restart() + framer.notify(`Renamed ${renamedCount} layer${renamedCount === 1 ? "" : "s"}`, { variant: "success" }) + }, + }) + + resultsRenamerRef.current = instance + return instance + }, [currentMode, indexer]) + + const renameResults = useCallback( + (e?: React.FormEvent) => { + e?.preventDefault() + + if (!isAllowedToSetAttributes) return + void resultsRenamer.start(results) + }, + [isAllowedToSetAttributes, resultsRenamer, results] + ) + + const throttle = useCallback((callback: () => void, delay = 1000) => { + let timeout: ReturnType | null = null + + return () => { + if (timeout) return + + timeout = setTimeout(() => { + callback() + timeout = null + }, delay) + } + }, []) + + const throttledStartIndexer = useMemo( + () => + throttle(() => { + void indexer.restart() + }), + [throttle, indexer] + ) + + // Subscribe to selection + useEffect(() => { + return framer.subscribeToSelection(selection => { + setSelectedNodeIds(selection.map(node => node.id)) + }) + }, []) + + // Restart indexer when root changes + useEffect(() => { + void indexer.restart() + }, [currentRootId, indexer]) + + // Subscribe to canvas root + useEffect(() => { + setIndex({}) + void indexer.start() + + return framer.subscribeToCanvasRoot(root => { + setCurrentRootId(root.id) + + if (replacing) return + + throttledStartIndexer() + }) + }, [indexer, replacing, throttledStartIndexer]) + + const tabItems = useMemo( + () => [ + { + label: "Search", + active: currentMode === "search", + select: () => { + setCurrentMode("search") + }, + }, + { + label: "Clean", + active: currentMode === "clean", + select: () => { + setCurrentMode("clean") + }, + }, + ], + [currentMode] + ) + + const getTextAfterRename = useCallback( + (result: Result) => { + switch (currentMode) { + case "search": + return renameResult(result, replacement) + + case "clean": + return cleanUpResult(result) + + default: + assertNever(currentMode) + } + }, + [currentMode, replacement] + ) + + const setReplacementValue = useCallback((value: string) => { + setReplacement(value) + replacementRef.current = value + }, []) + + const setQuery = useCallback((query: string) => { + setTextSearchFilter(prev => ({ ...prev, query })) + }, []) + + return ( +
+ + +
+ {!textSearchFilter.query ? ( +
+ Stars + Stars +
+ ) : ( +
+ +
+ )} +
+ + +
+ ) +} diff --git a/plugins/renamer/src/app.svelte b/plugins/renamer/src/app.svelte deleted file mode 100644 index 022012891..000000000 --- a/plugins/renamer/src/app.svelte +++ /dev/null @@ -1,266 +0,0 @@ - - -
- currentMode === "search", - select: () => (currentMode = "search"), - }, - { - label: "Clean", - active: () => currentMode === "clean", - select: () => (currentMode = "clean"), - }, - ]} - /> - -
- {#if !textSearchFilter.query} -
- Stars - Stars -
- {/if} - - {#if textSearchFilter.query} -
- { - switch (currentMode) { - case "search": - return renameResult(result, replacement); - - case "clean": - return cleanUpResult(result); - - default: - assertNever(currentMode); - } - }} - /> -
- {/if} -
- - -
- - diff --git a/plugins/renamer/src/assets/icon_search.svg b/plugins/renamer/src/assets/icon_search.svg deleted file mode 100644 index 2fd336255..000000000 --- a/plugins/renamer/src/assets/icon_search.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/plugins/renamer/src/components/LayerIcon.tsx b/plugins/renamer/src/components/LayerIcon.tsx new file mode 100644 index 000000000..746462381 --- /dev/null +++ b/plugins/renamer/src/components/LayerIcon.tsx @@ -0,0 +1,65 @@ +import type { IndexNodeType } from "../search/types" + +interface Props { + type: IndexNodeType +} + +export default function LayerIcon({ type }: Props) { + const width = 12 + const height = 12 + + let icon = null + + switch (type) { + case "TextNode": + icon = ( + + + + ) + break + + case "FrameNode": + icon = ( + + + + ) + break + + case "ComponentInstanceNode": + icon = ( + + + + ) + break + + default: + icon = null + } + + return ( +
+ {icon} +
+ ) +} diff --git a/plugins/renamer/src/components/PlaceholderRenameComparison.tsx b/plugins/renamer/src/components/PlaceholderRenameComparison.tsx new file mode 100644 index 000000000..6541683c0 --- /dev/null +++ b/plugins/renamer/src/components/PlaceholderRenameComparison.tsx @@ -0,0 +1,26 @@ +interface Props { + index: number + total: number + width: number +} + +export default function PlaceholderRenameComparison({ index, total, width }: Props) { + return ( +
+
+
+
+ ) +} diff --git a/plugins/renamer/src/components/RenameComparison.tsx b/plugins/renamer/src/components/RenameComparison.tsx new file mode 100644 index 000000000..5aaf65730 --- /dev/null +++ b/plugins/renamer/src/components/RenameComparison.tsx @@ -0,0 +1,49 @@ +import cx from "classnames" + +interface Props { + selected: boolean + before: string + after: string + children: React.ReactNode + onClick: () => void +} + +export default function RenameComparison({ selected, before, after, children, onClick }: Props) { + return ( + + ) +} diff --git a/plugins/renamer/src/components/Results.tsx b/plugins/renamer/src/components/Results.tsx new file mode 100644 index 000000000..879d66b15 --- /dev/null +++ b/plugins/renamer/src/components/Results.tsx @@ -0,0 +1,140 @@ +import cx from "classnames" +import { framer } from "framer-plugin" +import { useEffect, useMemo, useRef, useState } from "react" + +import type { Result } from "../search/types" +import LayerIcon from "./LayerIcon" +import PlaceholderRenameComparison from "./PlaceholderRenameComparison" +import RenameComparison from "./RenameComparison" + +interface Props { + query: string + indexing: boolean + results: Result[] + selectedNodeIds: string[] + getTextAfterRename: (result: Result) => string +} + +const ITEM_HEIGHT = 30 +const PAGE_SIZE = 10 +const BUFFER_SIZE = 5 + +export default function Results({ query, indexing, results, selectedNodeIds, getTextAfterRename }: Props) { + const scrollAreaRef = useRef(null) + const [showTopGradient, setShowTopGradient] = useState(false) + const [showBottomGradient, setShowBottomGradient] = useState(false) + const [scrollTop, setScrollTop] = useState(0) + const [containerHeight, setContainerHeight] = useState(0) + + const focusResult = async (result: Result) => { + await framer.setSelection(result.id) + await framer.zoomIntoView(result.id, { maxZoom: 1 }) + } + + // Reset scroll position when query changes + useEffect(() => { + if (scrollAreaRef.current) { + scrollAreaRef.current.scrollTop = 0 + setScrollTop(0) + } + }, [query]) + + // Calculate virtual list range + const { startIndex, endIndex } = useMemo(() => { + const visibleItemCount = Math.ceil(containerHeight / ITEM_HEIGHT) + + // Calculate the range of items that should be visible based on container height + const visibleStartIndex = Math.floor(scrollTop / ITEM_HEIGHT) + const visibleEndIndex = Math.min(results.length, visibleStartIndex + visibleItemCount) + + // Add buffer items above and below the visible range + const rawStartIndex = Math.max(0, visibleStartIndex - BUFFER_SIZE) + const rawEndIndex = Math.min(results.length, visibleEndIndex + BUFFER_SIZE) + + // Snap to multiples of PAGE_SIZE + const startIndex = Math.floor(rawStartIndex / PAGE_SIZE) * PAGE_SIZE + const endIndex = Math.min(results.length, Math.ceil(rawEndIndex / PAGE_SIZE) * PAGE_SIZE) + + return { startIndex, endIndex } + }, [results, scrollTop, containerHeight]) + + const visibleItems = useMemo(() => { + return results.slice(startIndex, endIndex) + }, [results, startIndex, endIndex]) + + useEffect(() => { + const scrollArea = scrollAreaRef.current + if (scrollArea) { + const handleScrollAndResize = () => { + if (scrollAreaRef.current) { + setContainerHeight(scrollAreaRef.current.clientHeight) + + const newScrollTop = scrollAreaRef.current.scrollTop + setScrollTop(newScrollTop) + + // Show top gradient when scrolled down + setShowTopGradient(newScrollTop > 0) + + // Show bottom gradient when not at the bottom + const scrollHeight = scrollAreaRef.current.scrollHeight + const clientHeight = scrollAreaRef.current.clientHeight + setShowBottomGradient(newScrollTop + clientHeight < scrollHeight) + } + } + + const resizeObserver = new ResizeObserver(handleScrollAndResize) + resizeObserver.observe(scrollArea) + + scrollArea.addEventListener("scroll", handleScrollAndResize) + handleScrollAndResize() + + return () => { + resizeObserver.disconnect() + scrollArea.removeEventListener("scroll", handleScrollAndResize) + } + } + }, [results]) + + return ( +
+
+
+ {visibleItems.map(result => ( + { + void focusResult(result) + }} + > + + + ))} +
+ + {indexing && query && ( +
+ + + + + +
+ )} +
+ +
+
+ + {results.length === 0 && query && !indexing &&
No Results
} +
+ ) +} diff --git a/plugins/renamer/src/components/SearchIcon.tsx b/plugins/renamer/src/components/SearchIcon.tsx new file mode 100644 index 000000000..52720f5cf --- /dev/null +++ b/plugins/renamer/src/components/SearchIcon.tsx @@ -0,0 +1,10 @@ +export default function SearchIcon() { + return ( + + + + ) +} diff --git a/plugins/renamer/src/components/SearchReplace.tsx b/plugins/renamer/src/components/SearchReplace.tsx new file mode 100644 index 000000000..bc0eb1b32 --- /dev/null +++ b/plugins/renamer/src/components/SearchReplace.tsx @@ -0,0 +1,54 @@ +import SearchIcon from "./SearchIcon" +import TextField from "./TextField" + +interface Props { + query: string + setQuery: (query: string) => void + replacement: string + setReplacement: (replacement: string) => void + loading: boolean + disableAction: boolean + actionLabel: string + showReplacement: boolean + isAllowed: boolean + onRenameClick: (e?: React.FormEvent) => void +} + +export default function SearchReplace({ + query, + setQuery, + replacement, + setReplacement, + loading, + disableAction, + actionLabel, + showReplacement, + isAllowed, + onRenameClick, +}: Props) { + return ( +
+ } + autoFocus + /> + + {showReplacement && ( + + )} + + + + ) +} diff --git a/plugins/renamer/src/components/Tabs.tsx b/plugins/renamer/src/components/Tabs.tsx new file mode 100644 index 000000000..c8f3aa9c5 --- /dev/null +++ b/plugins/renamer/src/components/Tabs.tsx @@ -0,0 +1,23 @@ +import cx from "classnames" + +interface TabItem { + label: string + active: boolean + select: () => void +} + +interface Props { + items: TabItem[] +} + +export default function Tabs({ items }: Props) { + return ( +
+ {items.map((item, index) => ( + + ))} +
+ ) +} diff --git a/plugins/renamer/src/components/TextField.tsx b/plugins/renamer/src/components/TextField.tsx new file mode 100644 index 000000000..85f09f327 --- /dev/null +++ b/plugins/renamer/src/components/TextField.tsx @@ -0,0 +1,47 @@ +import { useEffect, useRef } from "react" + +interface Props { + value: string + setValue: (value: string) => void + placeholder: string + focused?: boolean + disabled?: boolean + autoFocus?: boolean + leadingContent?: React.ReactNode +} + +export default function TextField({ + value, + setValue, + placeholder, + focused, + disabled = false, + autoFocus = false, + leadingContent, +}: Props) { + const inputRef = useRef(null) + + useEffect(() => { + if (focused) { + inputRef.current?.focus() + } + }, [focused]) + + return ( + + ) +} diff --git a/plugins/renamer/src/components/highlight_range.svelte b/plugins/renamer/src/components/highlight_range.svelte deleted file mode 100644 index 54f8bb1a7..000000000 --- a/plugins/renamer/src/components/highlight_range.svelte +++ /dev/null @@ -1,89 +0,0 @@ - - -{#each texts as { text, highlighted }} - {#if replacement && highlighted} - {text} - {preserveCase ? matchCase(replacement, text) : replacement} - {:else} - {text} - {/if} -{/each} - - diff --git a/plugins/renamer/src/components/icon_component_layer.svelte b/plugins/renamer/src/components/icon_component_layer.svelte deleted file mode 100644 index cdd16d174..000000000 --- a/plugins/renamer/src/components/icon_component_layer.svelte +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/plugins/renamer/src/components/icon_framer_layer.svelte b/plugins/renamer/src/components/icon_framer_layer.svelte deleted file mode 100644 index cdd16d174..000000000 --- a/plugins/renamer/src/components/icon_framer_layer.svelte +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/plugins/renamer/src/components/icon_locked_layer.svelte b/plugins/renamer/src/components/icon_locked_layer.svelte deleted file mode 100644 index f58b5e2b6..000000000 --- a/plugins/renamer/src/components/icon_locked_layer.svelte +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/plugins/renamer/src/components/icon_text_layer.svelte b/plugins/renamer/src/components/icon_text_layer.svelte deleted file mode 100644 index 8cbf985c4..000000000 --- a/plugins/renamer/src/components/icon_text_layer.svelte +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/plugins/renamer/src/components/layer_icon.svelte b/plugins/renamer/src/components/layer_icon.svelte deleted file mode 100644 index b02bc76a8..000000000 --- a/plugins/renamer/src/components/layer_icon.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - -
- {#if type === "TextNode"} - - {/if} - - {#if type === "FrameNode"} - - {/if} - - {#if type === "ComponentInstanceNode"} - - {/if} -
- - diff --git a/plugins/renamer/src/components/placeholder_rename_comparison.svelte b/plugins/renamer/src/components/placeholder_rename_comparison.svelte deleted file mode 100644 index e6c68003e..000000000 --- a/plugins/renamer/src/components/placeholder_rename_comparison.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - -
-
-
-
- - diff --git a/plugins/renamer/src/components/rename_comparison.svelte b/plugins/renamer/src/components/rename_comparison.svelte deleted file mode 100644 index 96f451fc3..000000000 --- a/plugins/renamer/src/components/rename_comparison.svelte +++ /dev/null @@ -1,125 +0,0 @@ - - - - - diff --git a/plugins/renamer/src/components/results.svelte b/plugins/renamer/src/components/results.svelte deleted file mode 100644 index 74cdd2cd7..000000000 --- a/plugins/renamer/src/components/results.svelte +++ /dev/null @@ -1,78 +0,0 @@ - - -
- - {#snippet item(result)} - {#key (result.title, result.ranges)} - focusResult(result)} - > - - - {/key} - {/snippet} - - {#snippet trailingContent()} - {#if indexing && query} -
- - - - - -
- {/if} - {/snippet} -
- - {#if results.length === 0 && query && !indexing} -
No Results
- {/if} -
- - diff --git a/plugins/renamer/src/components/search_replace.svelte b/plugins/renamer/src/components/search_replace.svelte deleted file mode 100644 index 735283de3..000000000 --- a/plugins/renamer/src/components/search_replace.svelte +++ /dev/null @@ -1,85 +0,0 @@ - - -
- - {#snippet leadingContent()} - {@html iconSearch} - {/snippet} - - - {#if showReplacement} - - {/if} - - -
- - diff --git a/plugins/renamer/src/components/spinner.svelte b/plugins/renamer/src/components/spinner.svelte deleted file mode 100644 index ee9ee40e9..000000000 --- a/plugins/renamer/src/components/spinner.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - -
- {#if type === "dashed"} - - - - - - - - - - - - {/if} - - {#if type === "solid"} - - {/if} -
- - diff --git a/plugins/renamer/src/components/tabs.svelte b/plugins/renamer/src/components/tabs.svelte deleted file mode 100644 index 54f6663e9..000000000 --- a/plugins/renamer/src/components/tabs.svelte +++ /dev/null @@ -1,56 +0,0 @@ - - -
- {#each items as item} - - {/each} -
- - diff --git a/plugins/renamer/src/components/text_field.svelte b/plugins/renamer/src/components/text_field.svelte deleted file mode 100644 index a3cd2823d..000000000 --- a/plugins/renamer/src/components/text_field.svelte +++ /dev/null @@ -1,76 +0,0 @@ - - -
- {#if leadingContent} -
- {@render leadingContent?.()} -
- {/if} - - -
- - diff --git a/plugins/renamer/src/components/toggle_button.svelte b/plugins/renamer/src/components/toggle_button.svelte deleted file mode 100644 index 120084ae6..000000000 --- a/plugins/renamer/src/components/toggle_button.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - -
- -
- -
-
- - diff --git a/plugins/renamer/src/components/virtual_list.svelte b/plugins/renamer/src/components/virtual_list.svelte deleted file mode 100644 index 20872e582..000000000 --- a/plugins/renamer/src/components/virtual_list.svelte +++ /dev/null @@ -1,116 +0,0 @@ - - -
- {#if scrollTop > 0} -
- {/if} - -
-
- {#each currentPageEntries as entry, index} -
- {@render item(entry, itemsPerPage * currentPage + index)} -
- {/each} - - {#each nextPageEntries as entry, index} -
- {@render item(entry, itemsPerPage * (currentPage + 1) + index)} -
- {/each} - - {@render trailingContent?.()} -
-
- -
-
- - diff --git a/plugins/renamer/src/main.ts b/plugins/renamer/src/main.ts deleted file mode 100644 index e20d82188..000000000 --- a/plugins/renamer/src/main.ts +++ /dev/null @@ -1,24 +0,0 @@ -import "framer-plugin/framer.css" -import "./reset.css" - -import { framer } from "framer-plugin" -import { mount } from "svelte" - -import App from "./app.svelte" - -// Expose framer on the global scope for testing. -;(window as unknown as Record).framer = framer - -void framer.showUI({ - position: "top right", - width: 260, - height: 450, - minWidth: 260, - minHeight: 450, - resizable: true, -}) - -const target = document.getElementById("app") -if (!target) throw new Error("#app element not found") - -export default mount(App, { target }) diff --git a/plugins/renamer/src/main.tsx b/plugins/renamer/src/main.tsx new file mode 100644 index 000000000..ed682df10 --- /dev/null +++ b/plugins/renamer/src/main.tsx @@ -0,0 +1,14 @@ +import "framer-plugin/framer.css" + +import React from "react" +import ReactDOM from "react-dom/client" +import { App } from "./App.tsx" + +const root = document.getElementById("root") +if (!root) throw new Error("Root element not found") + +ReactDOM.createRoot(root).render( + + + +) diff --git a/plugins/renamer/src/search/batch_process_results.ts b/plugins/renamer/src/search/batch_process_results.ts index ef325ce4f..c5b2e09fc 100644 --- a/plugins/renamer/src/search/batch_process_results.ts +++ b/plugins/renamer/src/search/batch_process_results.ts @@ -5,7 +5,7 @@ import type { CanvasNode, Result } from "./types" interface BatchProcessResultsOptions { process: (result: Result, node: CanvasNode, index: number) => Promise onStarted: () => void - onProgress: (count: number, total: number) => void + onProgress?: (count: number, total: number) => void onCompleted: () => void } @@ -33,7 +33,7 @@ export class BatchProcessResults { return } - setTimeout(poll, 500) + setTimeout(poll, 100) } poll() @@ -58,7 +58,7 @@ export class BatchProcessResults { } async start(results: Result[]) { - if (this.started || !this.ready) return + if (this.started) return this.started = true this.onStarted() @@ -76,7 +76,7 @@ export class BatchProcessResults { index += 1 } - this.onProgress(index, results.length) + this.onProgress?.(index, results.length) } this.started = false diff --git a/plugins/renamer/src/search/indexer.ts b/plugins/renamer/src/search/indexer.ts index 8d311e626..2fb594709 100644 --- a/plugins/renamer/src/search/indexer.ts +++ b/plugins/renamer/src/search/indexer.ts @@ -1,4 +1,4 @@ -import { framer, isFrameNode, isTextNode, isWebPageNode, WebPageNode } from "framer-plugin" +import { type CanvasRootNode, framer, isComponentNode, isFrameNode, isTextNode, isWebPageNode } from "framer-plugin" import { isCanvasNode } from "./traits" import type { CanvasNode, IndexEntry } from "./types" @@ -59,20 +59,25 @@ export class Indexer { } } - private async *crawl(pages: WebPageNode[]): AsyncGenerator { + private async *crawl(rootNodes: CanvasRootNode[]): AsyncGenerator { let batch: IndexEntry[] = [] - for (const page of pages) { - for await (const node of page.walk()) { + for (const rootNode of rootNodes) { + const children = await rootNode.getChildren() + const childNodeIds = children.map(node => node.id) + + for await (const node of rootNode.walk()) { if (this.abortRequested) return if (!isCanvasNode(node)) continue if (!this.isIncludedNodeType(node)) continue - const name = node.name ?? (await getDefaultCanvasNodeName(node)) + // Filter out replica nodes unless they are a variant/breakpoint + // Replica nodes share the same name between variants/breakpoints, so they can be filtered out + if (node.isReplica && !childNodeIds.includes(node.id)) continue + const name = node.name ?? (await getDefaultCanvasNodeName(node)) const rect = this.includedAttributes.includes("rect") ? await node.getRect() : null - const text = this.includedAttributes.includes("text") && isTextNode(node) ? await node.getText() : null batch.push({ @@ -97,24 +102,28 @@ export class Indexer { } } - private async getPages(): Promise { - const root = await framer.getCanvasRoot() - if (!isWebPageNode(root)) return [] - - if (this.scope === "page") { - return [root] + private async getRootNodes(): Promise { + if (this.scope === "project") { + const [webPages, componentNodes] = await Promise.all([ + framer.getNodesWithType("WebPageNode"), + framer.getNodesWithType("ComponentNode"), + ]) + return [...webPages, ...componentNodes] } - return await framer.getNodesWithType("WebPageNode") + const root = await framer.getCanvasRoot() + if (!isWebPageNode(root) && !isComponentNode(root)) return [] + + return [root] } async start() { - const pages = await this.getPages() + const rootNodes = await this.getRootNodes() this.abortRequested = false this.onStarted() - for await (const batch of this.crawl(pages)) { + for await (const batch of this.crawl(rootNodes)) { this.upsertEntries(batch) } diff --git a/plugins/renamer/src/vite-env.d.ts b/plugins/renamer/src/vite-env.d.ts index 334c21d22..25d1a3e93 100644 --- a/plugins/renamer/src/vite-env.d.ts +++ b/plugins/renamer/src/vite-env.d.ts @@ -1,4 +1,3 @@ -/// /// interface ViteTypeOptions { diff --git a/plugins/renamer/svelte.config.js b/plugins/renamer/svelte.config.js deleted file mode 100644 index 0c5870ea6..000000000 --- a/plugins/renamer/svelte.config.js +++ /dev/null @@ -1,8 +0,0 @@ -import { vitePreprocess } from "@sveltejs/vite-plugin-svelte" - -export default { - preprocess: vitePreprocess(), - compilerOptions: { - runes: true, - }, -} diff --git a/plugins/renamer/vite.config.ts b/plugins/renamer/vite.config.ts deleted file mode 100644 index dbd21fd0b..000000000 --- a/plugins/renamer/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { svelte } from "@sveltejs/vite-plugin-svelte" -import type { UserConfig } from "vite" -import framer from "vite-plugin-framer" -import mkcert from "vite-plugin-mkcert" - -export default { plugins: [svelte(), mkcert(), framer()] } satisfies UserConfig diff --git a/yarn.lock b/yarn.lock index 219ee4279..bf23e971f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -623,14 +623,14 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": version: 1.5.0 resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" checksum: 10/4ed6123217569a1484419ac53f6ea0d9f3b57e5b57ab30d7c267bdb27792a27eb0e4b08e84a2680aa55cc2f2b411ffd6ec3db01c44fdc6dc43aca4b55f8374fd languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.24": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -2245,45 +2245,6 @@ __metadata: languageName: node linkType: hard -"@sveltejs/acorn-typescript@npm:^1.0.5": - version: 1.0.5 - resolution: "@sveltejs/acorn-typescript@npm:1.0.5" - peerDependencies: - acorn: ^8.9.0 - checksum: 10/23c4c58a0336f44802609dea5ac7ed71d2bc02b8a3b001b03a0accf96a70f2f3d357b1677fd50fbf195d5ed772afed8757451b11c3eda3319fe57925160865d8 - languageName: node - linkType: hard - -"@sveltejs/vite-plugin-svelte-inspector@npm:^4.0.1": - version: 4.0.1 - resolution: "@sveltejs/vite-plugin-svelte-inspector@npm:4.0.1" - dependencies: - debug: "npm:^4.3.7" - peerDependencies: - "@sveltejs/vite-plugin-svelte": ^5.0.0 - svelte: ^5.0.0 - vite: ^6.0.0 - checksum: 10/af851fbeeaa8fd014ab09bd2ff2960593c200ed4673180e44aff21253b5324218853b3782fff7c90755d3f95e8fb073ce2ea533d4acce3d71febf42451024e2d - languageName: node - linkType: hard - -"@sveltejs/vite-plugin-svelte@npm:^5.1.0": - version: 5.1.0 - resolution: "@sveltejs/vite-plugin-svelte@npm:5.1.0" - dependencies: - "@sveltejs/vite-plugin-svelte-inspector": "npm:^4.0.1" - debug: "npm:^4.4.1" - deepmerge: "npm:^4.3.1" - kleur: "npm:^4.1.5" - magic-string: "npm:^0.30.17" - vitefu: "npm:^1.0.6" - peerDependencies: - svelte: ^5.0.0 - vite: ^6.0.0 - checksum: 10/5d6abc07e6e024e4abbcc68a56b3f975b9ec53c096c686cb2f22b2130f01cd7385786c1e309103277d791bf791de5aa7135821e392ea5b55a54e6d92e3eea3d0 - languageName: node - linkType: hard - "@swc/core-darwin-arm64@npm:1.12.6": version: 1.12.6 resolution: "@swc/core-darwin-arm64@npm:1.12.6" @@ -2761,7 +2722,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 @@ -3139,7 +3100,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.12.1, acorn@npm:^8.15.0": +"acorn@npm:^8.15.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -3252,7 +3213,7 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.0.0, aria-query@npm:^5.3.1": +"aria-query@npm:^5.0.0": version: 5.3.2 resolution: "aria-query@npm:5.3.2" checksum: 10/b2fe9bc98bd401bc322ccb99717c1ae2aaf53ea0d468d6e7aebdc02fac736e4a99b46971ee05b783b08ade23c675b2d8b60e4a1222a95f6e27bc4d2a0bfdcc03 @@ -3333,13 +3294,6 @@ __metadata: languageName: node linkType: hard -"axobject-query@npm:^4.1.0": - version: 4.1.0 - resolution: "axobject-query@npm:4.1.0" - checksum: 10/e275dea9b673f71170d914f2d2a18be5d57d8d29717b629e7fedd907dcc2ebdc7a37803ff975874810bd423f222f299c020d28fde40a146f537448bf6bfecb6e - languageName: node - linkType: hard - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -3544,15 +3498,6 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^4.0.1": - version: 4.0.3 - resolution: "chokidar@npm:4.0.3" - dependencies: - readdirp: "npm:^4.0.1" - checksum: 10/bf2a575ea5596000e88f5db95461a9d59ad2047e939d5a4aac59dd472d126be8f1c1ff3c7654b477cf532d18f42a97279ef80ee847972fd2a25410bf00b80b59 - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -3884,7 +3829,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.7, debug@npm:^4.4.0, debug@npm:^4.4.1": +"debug@npm:4, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0, debug@npm:^4.4.1": version: 4.4.1 resolution: "debug@npm:4.4.1" dependencies: @@ -3917,13 +3862,6 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.3.1": - version: 4.3.1 - resolution: "deepmerge@npm:4.3.1" - checksum: 10/058d9e1b0ff1a154468bf3837aea436abcfea1ba1d165ddaaf48ca93765fdd01a30d33c36173da8fbbed951dd0a267602bc782fe288b0fc4b7e1e7091afc4529 - languageName: node - linkType: hard - "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -4367,13 +4305,6 @@ __metadata: languageName: node linkType: hard -"esm-env@npm:^1.2.1": - version: 1.2.2 - resolution: "esm-env@npm:1.2.2" - checksum: 10/caf5f3cc2bc7107494585b4e38835787f48ef77b670aeb2d765a5b6b64c41102d20bbdd34bda32474291b6b8d819d4d02ce92570a0886baca6cef70f5fe689f3 - languageName: node - linkType: hard - "espree@npm:^10.0.1, espree@npm:^10.4.0": version: 10.4.0 resolution: "espree@npm:10.4.0" @@ -4394,15 +4325,6 @@ __metadata: languageName: node linkType: hard -"esrap@npm:^2.1.0": - version: 2.1.0 - resolution: "esrap@npm:2.1.0" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.4.15" - checksum: 10/32c1eff1819ec4d6ed0b8232375a106947d71bd8b0d175cd984d64b22f5734ae0acaf8ce94ad1ad693730f6cc057a6be75b14a4ff31beafe683266e81a600b08 - languageName: node - linkType: hard - "esrecurse@npm:^4.3.0": version: 4.3.0 resolution: "esrecurse@npm:4.3.0" @@ -4506,7 +4428,7 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.2.0, fdir@npm:^6.4.4, fdir@npm:^6.4.6": +"fdir@npm:^6.4.4, fdir@npm:^6.4.6": version: 6.4.6 resolution: "fdir@npm:6.4.6" peerDependencies: @@ -5100,15 +5022,6 @@ __metadata: languageName: node linkType: hard -"is-reference@npm:^3.0.3": - version: 3.0.3 - resolution: "is-reference@npm:3.0.3" - dependencies: - "@types/estree": "npm:^1.0.6" - checksum: 10/11371fb2669a8144bffb2ae9bd11b0342b7dc384c3c0f8d5996566b071614282a3a0d306fd2fd1c6b4c9078d0e2703d191b47f4f78f9ce08f464c44a3a412412 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -5207,13 +5120,6 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.1.5": - version: 4.1.5 - resolution: "kleur@npm:4.1.5" - checksum: 10/44d84cc4eedd4311099402ef6d4acd9b2d16e08e499d6ef3bb92389bd4692d7ef09e35248c26e27f98acac532122acb12a1bfee645994ae3af4f0a37996da7df - languageName: node - linkType: hard - "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -5346,13 +5252,6 @@ __metadata: languageName: unknown linkType: soft -"locate-character@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-character@npm:3.0.0" - checksum: 10/2d9e9f45e2dce7464c016ed6d81ebc938bc9c656392f7d6858308ab6fdaa57bcd4b6b479291d49e7db4047e3f321ddadbe78355f349b7974b203f19674e277cc - languageName: node - linkType: hard - "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" @@ -5424,7 +5323,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.11, magic-string@npm:^0.30.17": +"magic-string@npm:^0.30.17": version: 0.30.17 resolution: "magic-string@npm:0.30.17" dependencies: @@ -5662,13 +5561,6 @@ __metadata: languageName: node linkType: hard -"mri@npm:^1.1.0": - version: 1.2.0 - resolution: "mri@npm:1.2.0" - checksum: 10/6775a1d2228bb9d191ead4efc220bd6be64f943ad3afd4dcb3b3ac8fc7b87034443f666e38805df38e8d047b29f910c3cc7810da0109af83e42c82c73bd3f6bc - languageName: node - linkType: hard - "mrmime@npm:^2.0.0": version: 2.0.1 resolution: "mrmime@npm:2.0.1" @@ -5972,7 +5864,7 @@ __metadata: languageName: unknown linkType: soft -"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": +"picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -6437,13 +6329,6 @@ __metadata: languageName: node linkType: hard -"readdirp@npm:^4.0.1": - version: 4.1.2 - resolution: "readdirp@npm:4.1.2" - checksum: 10/7b817c265940dba90bb9c94d82920d76c3a35ea2d67f9f9d8bd936adcfe02d50c802b14be3dd2e725e002dddbe2cc1c7a0edfb1bc3a365c9dfd5a61e612eea1e - languageName: node - linkType: hard - "recharts@npm:^3.0.2": version: 3.0.2 resolution: "recharts@npm:3.0.2" @@ -6518,18 +6403,13 @@ __metadata: version: 0.0.0-use.local resolution: "renamer@workspace:plugins/renamer" dependencies: - "@sveltejs/vite-plugin-svelte": "npm:^5.1.0" "@types/react": "npm:^18.3.23" "@types/react-dom": "npm:^18.3.7" - framer-plugin: "npm:^3.3.2" + classnames: "npm:^2.5.1" + framer-plugin: "npm:^3.5.2" + framer-plugin-tools: "npm:^1.0.0" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" - svelte: "npm:^5.35.2" - svelte-check: "npm:^4.2.2" - typescript: "npm:^5.8.3" - vite: "npm:^7.0.1" - vite-plugin-framer: "npm:^1.0.7" - vite-plugin-mkcert: "npm:^1.17.8" languageName: unknown linkType: soft @@ -6684,15 +6564,6 @@ __metadata: languageName: node linkType: hard -"sade@npm:^1.7.4": - version: 1.8.1 - resolution: "sade@npm:1.8.1" - dependencies: - mri: "npm:^1.1.0" - checksum: 10/1c67ba03c94083e0ae307ff5564ecb86c2104c0f558042fdaa40ea0054f91a63a9783f14069870f2f784336adabb70f90f22a84dc457b5a25e859aaadefe0910 - languageName: node - linkType: hard - "safe-buffer@npm:@nolyfill/safe-buffer@latest": version: 1.0.44 resolution: "@nolyfill/safe-buffer@npm:1.0.44" @@ -6905,46 +6776,6 @@ __metadata: languageName: node linkType: hard -"svelte-check@npm:^4.2.2": - version: 4.2.2 - resolution: "svelte-check@npm:4.2.2" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.25" - chokidar: "npm:^4.0.1" - fdir: "npm:^6.2.0" - picocolors: "npm:^1.0.0" - sade: "npm:^1.7.4" - peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.0 - typescript: ">=5.0.0" - bin: - svelte-check: bin/svelte-check - checksum: 10/e99c890497def7eabd1e5eaa35d568db6109f1fcf57eb2c753f9655ba3f23e51d78d91171a9635f14b87d7f42ce4f1130703a6f1b9bef8a552fc90289c286374 - languageName: node - linkType: hard - -"svelte@npm:^5.35.2": - version: 5.35.2 - resolution: "svelte@npm:5.35.2" - dependencies: - "@ampproject/remapping": "npm:^2.3.0" - "@jridgewell/sourcemap-codec": "npm:^1.5.0" - "@sveltejs/acorn-typescript": "npm:^1.0.5" - "@types/estree": "npm:^1.0.5" - acorn: "npm:^8.12.1" - aria-query: "npm:^5.3.1" - axobject-query: "npm:^4.1.0" - clsx: "npm:^2.1.1" - esm-env: "npm:^1.2.1" - esrap: "npm:^2.1.0" - is-reference: "npm:^3.0.3" - locate-character: "npm:^3.0.0" - magic-string: "npm:^0.30.11" - zimmerframe: "npm:^1.1.2" - checksum: 10/03a7a83de1b4264d0ebf8cf2754b0026c0abf5c0ad51dc5d1e9935cc59ee8f69c59a71b8e62fe264122d29f49d110fcbeb18ac9e59e4f10b4a51ca8744dffaf8 - languageName: node - linkType: hard - "tailwind-merge@npm:^3.3.1": version: 3.3.1 resolution: "tailwind-merge@npm:3.3.1" @@ -7488,18 +7319,6 @@ __metadata: languageName: node linkType: hard -"vitefu@npm:^1.0.6": - version: 1.0.7 - resolution: "vitefu@npm:1.0.7" - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 - peerDependenciesMeta: - vite: - optional: true - checksum: 10/f780b754d859819c0a6e10f890e2519479194e34692b580f89fb864fa169d9df012622a2b4a4d5e3f1c524117ee7ba2a3555acf89e3bc98445251b7af328e3c0 - languageName: node - linkType: hard - "vitest@npm:^3.2.4": version: 3.2.4 resolution: "vitest@npm:3.2.4" @@ -7721,10 +7540,3 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"zimmerframe@npm:^1.1.2": - version: 1.1.2 - resolution: "zimmerframe@npm:1.1.2" - checksum: 10/495e1b263b288d2c423bafb6897060856b86a32c21a3550ed2b4b30779051824b7cd3e606f46cbcdfd5b0d47660fe3ef418e9c2369d0f0709f0e6111c4d096d4 - languageName: node - linkType: hard