multiclone 0.0.0-stage → 0.2.0
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/README.md +78 -2
- package/agents/section-builder.md +37 -0
- package/commands/multiclone.md +15 -0
- package/dist/adapters/cli.js +129 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/adapters/cliArgs.js +63 -0
- package/dist/adapters/cliArgs.js.map +1 -0
- package/dist/adapters/mcp.js +83 -0
- package/dist/adapters/mcp.js.map +1 -0
- package/dist/analyze/analyze.js +85 -0
- package/dist/analyze/analyze.js.map +1 -0
- package/dist/analyze/animations.js +340 -0
- package/dist/analyze/animations.js.map +1 -0
- package/dist/analyze/ast.js +182 -0
- package/dist/analyze/ast.js.map +1 -0
- package/dist/analyze/chunks.js +160 -0
- package/dist/analyze/chunks.js.map +1 -0
- package/dist/analyze/jobs/code.js +117 -0
- package/dist/analyze/jobs/code.js.map +1 -0
- package/dist/analyze/jobs/sections.js +356 -0
- package/dist/analyze/jobs/sections.js.map +1 -0
- package/dist/analyze/pretty.js +20 -0
- package/dist/analyze/pretty.js.map +1 -0
- package/dist/analyze/report.js +101 -0
- package/dist/analyze/report.js.map +1 -0
- package/dist/analyze/worker.js +71 -0
- package/dist/analyze/worker.js.map +1 -0
- package/dist/capture/capture.js +340 -0
- package/dist/capture/capture.js.map +1 -0
- package/dist/capture/collectors/a11y.js +92 -0
- package/dist/capture/collectors/a11y.js.map +1 -0
- package/dist/capture/collectors/animations.js +113 -0
- package/dist/capture/collectors/animations.js.map +1 -0
- package/dist/capture/collectors/breakpoints.js +31 -0
- package/dist/capture/collectors/breakpoints.js.map +1 -0
- package/dist/capture/collectors/consent.js +39 -0
- package/dist/capture/collectors/consent.js.map +1 -0
- package/dist/capture/collectors/coverage.js +121 -0
- package/dist/capture/collectors/coverage.js.map +1 -0
- package/dist/capture/collectors/dom.js +16 -0
- package/dist/capture/collectors/dom.js.map +1 -0
- package/dist/capture/collectors/fonts.js +154 -0
- package/dist/capture/collectors/fonts.js.map +1 -0
- package/dist/capture/collectors/frames.js +93 -0
- package/dist/capture/collectors/frames.js.map +1 -0
- package/dist/capture/collectors/index.js +61 -0
- package/dist/capture/collectors/index.js.map +1 -0
- package/dist/capture/collectors/interactions.js +207 -0
- package/dist/capture/collectors/interactions.js.map +1 -0
- package/dist/capture/collectors/intro.js +84 -0
- package/dist/capture/collectors/intro.js.map +1 -0
- package/dist/capture/collectors/listeners.js +84 -0
- package/dist/capture/collectors/listeners.js.map +1 -0
- package/dist/capture/collectors/motion.js +91 -0
- package/dist/capture/collectors/motion.js.map +1 -0
- package/dist/capture/collectors/network.js +288 -0
- package/dist/capture/collectors/network.js.map +1 -0
- package/dist/capture/collectors/probes.js +34 -0
- package/dist/capture/collectors/probes.js.map +1 -0
- package/dist/capture/collectors/runtime.js +38 -0
- package/dist/capture/collectors/runtime.js.map +1 -0
- package/dist/capture/collectors/scripts.js +98 -0
- package/dist/capture/collectors/scripts.js.map +1 -0
- package/dist/capture/collectors/sections.js +17 -0
- package/dist/capture/collectors/sections.js.map +1 -0
- package/dist/capture/collectors/shots.js +58 -0
- package/dist/capture/collectors/shots.js.map +1 -0
- package/dist/capture/collectors/snapshot.js +47 -0
- package/dist/capture/collectors/snapshot.js.map +1 -0
- package/dist/capture/collectors/sourcemaps.js +153 -0
- package/dist/capture/collectors/sourcemaps.js.map +1 -0
- package/dist/capture/collectors/storage.js +72 -0
- package/dist/capture/collectors/storage.js.map +1 -0
- package/dist/capture/context.js +40 -0
- package/dist/capture/context.js.map +1 -0
- package/dist/capture/hooks/candidates.js +104 -0
- package/dist/capture/hooks/candidates.js.map +1 -0
- package/dist/capture/hooks/consent.js +82 -0
- package/dist/capture/hooks/consent.js.map +1 -0
- package/dist/capture/hooks/recorders.js +507 -0
- package/dist/capture/hooks/recorders.js.map +1 -0
- package/dist/capture/hooks/sections.js +62 -0
- package/dist/capture/hooks/sections.js.map +1 -0
- package/dist/capture/hooks/styles.js +86 -0
- package/dist/capture/hooks/styles.js.map +1 -0
- package/dist/capture/probes.js +491 -0
- package/dist/capture/probes.js.map +1 -0
- package/dist/capture/report.js +115 -0
- package/dist/capture/report.js.map +1 -0
- package/dist/compare/compare.js +391 -0
- package/dist/compare/compare.js.map +1 -0
- package/dist/compare/image.js +105 -0
- package/dist/compare/image.js.map +1 -0
- package/dist/compare/probes.js +129 -0
- package/dist/compare/probes.js.map +1 -0
- package/dist/compare/report.js +99 -0
- package/dist/compare/report.js.map +1 -0
- package/dist/compare/session.js +139 -0
- package/dist/compare/session.js.map +1 -0
- package/dist/compare/shoot.js +62 -0
- package/dist/compare/shoot.js.map +1 -0
- package/dist/contracts/catalog.js +29 -0
- package/dist/contracts/catalog.js.map +1 -0
- package/dist/contracts/context.js +19 -0
- package/dist/contracts/context.js.map +1 -0
- package/dist/contracts/fields.js +16 -0
- package/dist/contracts/fields.js.map +1 -0
- package/dist/contracts/tools/analyze.js +38 -0
- package/dist/contracts/tools/analyze.js.map +1 -0
- package/dist/contracts/tools/capture.js +87 -0
- package/dist/contracts/tools/capture.js.map +1 -0
- package/dist/contracts/tools/compare.js +142 -0
- package/dist/contracts/tools/compare.js.map +1 -0
- package/dist/contracts/tools/doctor.js +23 -0
- package/dist/contracts/tools/doctor.js.map +1 -0
- package/dist/contracts/tools/inspect.js +41 -0
- package/dist/contracts/tools/inspect.js.map +1 -0
- package/dist/contracts/tools/method.js +60 -0
- package/dist/contracts/tools/method.js.map +1 -0
- package/dist/contracts/tools/mirror.js +53 -0
- package/dist/contracts/tools/mirror.js.map +1 -0
- package/dist/contracts/tools/project.js +61 -0
- package/dist/contracts/tools/project.js.map +1 -0
- package/dist/contracts/tools/session.js +195 -0
- package/dist/contracts/tools/session.js.map +1 -0
- package/dist/contracts/types.js +20 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/core/cdp.js +146 -0
- package/dist/core/cdp.js.map +1 -0
- package/dist/core/chrome.js +185 -0
- package/dist/core/chrome.js.map +1 -0
- package/dist/core/files.js +31 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/inpage.js +24 -0
- package/dist/core/inpage.js.map +1 -0
- package/dist/core/log.js +10 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/page.js +269 -0
- package/dist/core/page.js.map +1 -0
- package/dist/doctor.js +37 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain/breakpoints.js +47 -0
- package/dist/domain/breakpoints.js.map +1 -0
- package/dist/domain/budget.js +38 -0
- package/dist/domain/budget.js.map +1 -0
- package/dist/domain/compare.js +138 -0
- package/dist/domain/compare.js.map +1 -0
- package/dist/domain/coverage.js +96 -0
- package/dist/domain/coverage.js.map +1 -0
- package/dist/domain/motion.js +142 -0
- package/dist/domain/motion.js.map +1 -0
- package/dist/domain/paths.js +55 -0
- package/dist/domain/paths.js.map +1 -0
- package/dist/domain/result.js +38 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/domain/routes.js +160 -0
- package/dist/domain/routes.js.map +1 -0
- package/dist/domain/sections.js +94 -0
- package/dist/domain/sections.js.map +1 -0
- package/dist/domain/snapshot.js +268 -0
- package/dist/domain/snapshot.js.map +1 -0
- package/dist/domain/sourcemap.js +95 -0
- package/dist/domain/sourcemap.js.map +1 -0
- package/dist/domain/stack.js +342 -0
- package/dist/domain/stack.js.map +1 -0
- package/dist/domain/tokens.js +183 -0
- package/dist/domain/tokens.js.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/viewports.js +45 -0
- package/dist/domain/viewports.js.map +1 -0
- package/dist/mirror/rewrite.js +56 -0
- package/dist/mirror/rewrite.js.map +1 -0
- package/dist/mirror/server.js +191 -0
- package/dist/mirror/server.js.map +1 -0
- package/dist/mirror/store.js +86 -0
- package/dist/mirror/store.js.map +1 -0
- package/dist/project/assets.js +69 -0
- package/dist/project/assets.js.map +1 -0
- package/dist/project/draft.js +860 -0
- package/dist/project/draft.js.map +1 -0
- package/dist/project/method.js +154 -0
- package/dist/project/method.js.map +1 -0
- package/dist/project/scaffold.js +142 -0
- package/dist/project/scaffold.js.map +1 -0
- package/dist/session/discover.js +53 -0
- package/dist/session/discover.js.map +1 -0
- package/dist/session/proc.js +113 -0
- package/dist/session/proc.js.map +1 -0
- package/dist/session/progress.js +83 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/session.js +450 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/state.js +47 -0
- package/dist/session/state.js.map +1 -0
- package/dist/store/inspect.js +212 -0
- package/dist/store/inspect.js.map +1 -0
- package/dist/store/run.js +112 -0
- package/dist/store/run.js.map +1 -0
- package/dist/store/summary.js +69 -0
- package/dist/store/summary.js.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install.sh +29 -0
- package/package.json +67 -4
- package/skills/multiclone/SKILL.md +123 -0
- package/skills/multiclone/references/capture-format.md +73 -0
- package/skills/multiclone/references/fidelity.md +54 -0
- package/skills/multiclone/references/quality.md +47 -0
- package/skills/multiclone/references/stacks.md +156 -0
- package/templates/react-vite/.prettierignore +5 -0
- package/templates/react-vite/.prettierrc.json +6 -0
- package/templates/react-vite/eslint.config.js +38 -0
- package/templates/react-vite/gitignore +4 -0
- package/templates/react-vite/index.html +12 -0
- package/templates/react-vite/package.json +36 -0
- package/templates/react-vite/src/app/App.tsx +15 -0
- package/templates/react-vite/src/app/Page.tsx +11 -0
- package/templates/react-vite/src/app/routes.ts +7 -0
- package/templates/react-vite/src/components/README.md +7 -0
- package/templates/react-vite/src/content/README.md +2 -0
- package/templates/react-vite/src/hooks/useActiveSection.ts +37 -0
- package/templates/react-vite/src/hooks/useInView.ts +45 -0
- package/templates/react-vite/src/hooks/useMediaQuery.ts +15 -0
- package/templates/react-vite/src/lib/cn.ts +4 -0
- package/templates/react-vite/src/lib/math.ts +21 -0
- package/templates/react-vite/src/lib/mc.ts +13 -0
- package/templates/react-vite/src/lib/media.ts +4 -0
- package/templates/react-vite/src/main.tsx +13 -0
- package/templates/react-vite/src/providers/SmoothScroll.tsx +24 -0
- package/templates/react-vite/src/styles/base.css +42 -0
- package/templates/react-vite/src/styles/draft.css +1 -0
- package/templates/react-vite/src/styles/fonts.css +1 -0
- package/templates/react-vite/src/styles/index.css +4 -0
- package/templates/react-vite/src/styles/tokens.css +3 -0
- package/templates/react-vite/src/vite-env.d.ts +1 -0
- package/templates/react-vite/tsconfig.app.json +29 -0
- package/templates/react-vite/tsconfig.json +4 -0
- package/templates/react-vite/tsconfig.node.json +19 -0
- package/templates/react-vite/vite.config.ts +37 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
One folder per page area (layout, hero, sections, ui). Keep heavy parts (canvas, WebGL, Rive) lazy.
|
|
2
|
+
|
|
3
|
+
Compare markers (helpers in `@/lib/mc`):
|
|
4
|
+
|
|
5
|
+
- Wrap each rebuilt section in `<section {...mcSection('03-pricing')}>` using the id from the capture's `sections/<id>/section.md`.
|
|
6
|
+
- Tag scroll-animated elements with `{...mcTrack('t0abc123')}` using the track id from `motion.json`.
|
|
7
|
+
- Tag elements with captured hover states with `{...mcHover('t0abc123')}` (same id scheme, listed in `interactions.json`).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tracks the last section whose top has crossed a line `lineRatio` down the viewport.
|
|
5
|
+
* Null above the first section.
|
|
6
|
+
*/
|
|
7
|
+
export function useActiveSection(ids: readonly string[], lineRatio = 0.4): string | null {
|
|
8
|
+
const [active, setActive] = useState<string | null>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let frame = 0;
|
|
12
|
+
const update = () => {
|
|
13
|
+
frame = 0;
|
|
14
|
+
const line = window.innerHeight * lineRatio;
|
|
15
|
+
let current: string | null = null;
|
|
16
|
+
for (const id of ids) {
|
|
17
|
+
const node = document.getElementById(id);
|
|
18
|
+
if (!node) continue;
|
|
19
|
+
if (node.getBoundingClientRect().top <= line) current = id;
|
|
20
|
+
}
|
|
21
|
+
setActive(current);
|
|
22
|
+
};
|
|
23
|
+
const schedule = () => {
|
|
24
|
+
if (!frame) frame = requestAnimationFrame(update);
|
|
25
|
+
};
|
|
26
|
+
update();
|
|
27
|
+
window.addEventListener('scroll', schedule, { passive: true });
|
|
28
|
+
window.addEventListener('resize', schedule);
|
|
29
|
+
return () => {
|
|
30
|
+
cancelAnimationFrame(frame);
|
|
31
|
+
window.removeEventListener('scroll', schedule);
|
|
32
|
+
window.removeEventListener('resize', schedule);
|
|
33
|
+
};
|
|
34
|
+
}, [ids, lineRatio]);
|
|
35
|
+
|
|
36
|
+
return active;
|
|
37
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect, useState, type RefObject } from 'react';
|
|
2
|
+
|
|
3
|
+
/** Flips to true once the element comes within `rootMargin` of the viewport, then stays true. */
|
|
4
|
+
export function useInViewOnce(ref: RefObject<Element | null>, rootMargin = '200px'): boolean {
|
|
5
|
+
const [seen, setSeen] = useState(false);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const node = ref.current;
|
|
8
|
+
if (!node || seen) return;
|
|
9
|
+
const observer = new IntersectionObserver(
|
|
10
|
+
(entries) => {
|
|
11
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
12
|
+
setSeen(true);
|
|
13
|
+
observer.disconnect();
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{ rootMargin },
|
|
17
|
+
);
|
|
18
|
+
observer.observe(node);
|
|
19
|
+
return () => {
|
|
20
|
+
observer.disconnect();
|
|
21
|
+
};
|
|
22
|
+
}, [ref, rootMargin, seen]);
|
|
23
|
+
return seen;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Live visibility for media that should pause off-screen. */
|
|
27
|
+
export function useInView(ref: RefObject<Element | null>, rootMargin = '0px'): boolean {
|
|
28
|
+
const [visible, setVisible] = useState(false);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const node = ref.current;
|
|
31
|
+
if (!node) return;
|
|
32
|
+
const observer = new IntersectionObserver(
|
|
33
|
+
(entries) => {
|
|
34
|
+
const last = entries.at(-1);
|
|
35
|
+
if (last) setVisible(last.isIntersecting);
|
|
36
|
+
},
|
|
37
|
+
{ rootMargin },
|
|
38
|
+
);
|
|
39
|
+
observer.observe(node);
|
|
40
|
+
return () => {
|
|
41
|
+
observer.disconnect();
|
|
42
|
+
};
|
|
43
|
+
}, [ref, rootMargin]);
|
|
44
|
+
return visible;
|
|
45
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
export function useMediaQuery(query: string): boolean {
|
|
4
|
+
return useSyncExternalStore(
|
|
5
|
+
(notify) => {
|
|
6
|
+
const list = window.matchMedia(query);
|
|
7
|
+
list.addEventListener('change', notify);
|
|
8
|
+
return () => {
|
|
9
|
+
list.removeEventListener('change', notify);
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
() => window.matchMedia(query).matches,
|
|
13
|
+
() => false,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const clamp = (value: number, min = 0, max = 1): number =>
|
|
2
|
+
Math.min(max, Math.max(min, value));
|
|
3
|
+
|
|
4
|
+
export const lerp = (from: number, to: number, t: number): number => from + (to - from) * t;
|
|
5
|
+
|
|
6
|
+
/** Hermite smoothstep, matching the CSS `t*t*(3-2t)` curve the stylesheet uses. */
|
|
7
|
+
export const smoothstep = (t: number): number => {
|
|
8
|
+
const x = clamp(t);
|
|
9
|
+
return x * x * (3 - 2 * x);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Deterministic PRNG so the graph lays out identically on every load. */
|
|
13
|
+
export function mulberry32(seed: number): () => number {
|
|
14
|
+
let a = seed;
|
|
15
|
+
return () => {
|
|
16
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
17
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
18
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
19
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markers `multiclone compare` reads to line the rebuild up with the original. They have no
|
|
3
|
+
* styling effect; keep them in production builds or strip them, either works.
|
|
4
|
+
*/
|
|
5
|
+
export const mcSection = (id: string): { 'data-mc-section': string } => ({
|
|
6
|
+
'data-mc-section': id,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/** Element whose scroll motion must match the original track `id` from motion.json. */
|
|
10
|
+
export const mcTrack = (id: string): { 'data-mc-track': string } => ({ 'data-mc-track': id });
|
|
11
|
+
|
|
12
|
+
/** Element whose hover state must match the captured interaction with this track id. */
|
|
13
|
+
export const mcHover = (id: string): { 'data-mc-hover': string } => ({ 'data-mc-hover': id });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { App } from '@/app/App';
|
|
4
|
+
import '@/styles/index.css';
|
|
5
|
+
|
|
6
|
+
const container = document.getElementById('root');
|
|
7
|
+
if (!container) throw new Error('Missing #root container');
|
|
8
|
+
|
|
9
|
+
createRoot(container).render(
|
|
10
|
+
<StrictMode>
|
|
11
|
+
<App />
|
|
12
|
+
</StrictMode>,
|
|
13
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, type ReactNode } from 'react';
|
|
2
|
+
import Lenis from 'lenis';
|
|
3
|
+
import { prefersReducedMotion } from '@/lib/media';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Inertial scrolling for originals that use Lenis/Locomotive/ScrollSmoother. Native scroll stays
|
|
7
|
+
* authoritative so CSS scroll timelines keep working. Remove it if the original scrolls natively.
|
|
8
|
+
*/
|
|
9
|
+
export function SmoothScroll({ children }: { readonly children: ReactNode }) {
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (prefersReducedMotion()) return;
|
|
12
|
+
const lenis = new Lenis({ lerp: 0.12, anchors: { offset: 0 } });
|
|
13
|
+
let frame = requestAnimationFrame(function loop(time) {
|
|
14
|
+
lenis.raf(time);
|
|
15
|
+
frame = requestAnimationFrame(loop);
|
|
16
|
+
});
|
|
17
|
+
return () => {
|
|
18
|
+
cancelAnimationFrame(frame);
|
|
19
|
+
lenis.destroy();
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
*,
|
|
2
|
+
*::before,
|
|
3
|
+
*::after {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
html {
|
|
8
|
+
-webkit-text-size-adjust: 100%;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
-webkit-font-smoothing: antialiased;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
img,
|
|
17
|
+
video,
|
|
18
|
+
canvas,
|
|
19
|
+
svg {
|
|
20
|
+
display: block;
|
|
21
|
+
max-width: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
html.lenis,
|
|
25
|
+
html.lenis body {
|
|
26
|
+
height: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.lenis.lenis-smooth {
|
|
30
|
+
scroll-behavior: auto !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@media (prefers-reduced-motion: reduce) {
|
|
34
|
+
*,
|
|
35
|
+
*::before,
|
|
36
|
+
*::after {
|
|
37
|
+
animation-duration: 0.01ms !important;
|
|
38
|
+
animation-iteration-count: 1 !important;
|
|
39
|
+
transition-duration: 0.01ms !important;
|
|
40
|
+
scroll-behavior: auto !important;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Filled by `multiclone draft`: element reset and page-level styles of the original. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* `multiclone scaffold --capture <dir>` writes the captured @font-face rules here. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"types": ["vite/client"],
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"verbatimModuleSyntax": true,
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUncheckedIndexedAccess": true,
|
|
19
|
+
"exactOptionalPropertyTypes": true,
|
|
20
|
+
"noImplicitOverride": true,
|
|
21
|
+
"noUnusedLocals": true,
|
|
22
|
+
"noUnusedParameters": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noUncheckedSideEffectImports": true,
|
|
25
|
+
|
|
26
|
+
"paths": { "@/*": ["./src/*"] }
|
|
27
|
+
},
|
|
28
|
+
"include": ["src"]
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"types": ["node"],
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["vite.config.ts", "eslint.config.js"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath, URL } from 'node:url';
|
|
3
|
+
import { defineConfig, type ProxyOptions } from 'vite';
|
|
4
|
+
import react from '@vitejs/plugin-react';
|
|
5
|
+
|
|
6
|
+
interface MockConfig {
|
|
7
|
+
readonly mirror: string;
|
|
8
|
+
readonly paths: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** `mc.config.json` (written by `multiclone scaffold --capture`) proxies captured API calls to the mirror. */
|
|
12
|
+
function mockProxy(): Record<string, ProxyOptions> {
|
|
13
|
+
const file = fileURLToPath(new URL('./mc.config.json', import.meta.url));
|
|
14
|
+
if (!existsSync(file)) return {};
|
|
15
|
+
const parsed: unknown = JSON.parse(readFileSync(file, 'utf8'));
|
|
16
|
+
if (!isMockConfig(parsed)) return {};
|
|
17
|
+
const mirror = process.env.MC_MIRROR ?? parsed.mirror;
|
|
18
|
+
return Object.fromEntries(parsed.paths.map((path) => [path, { target: mirror, changeOrigin: true }]));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isMockConfig(value: unknown): value is MockConfig {
|
|
22
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
23
|
+
const { mirror, paths } = value as { mirror?: unknown; paths?: unknown };
|
|
24
|
+
return (
|
|
25
|
+
typeof mirror === 'string' &&
|
|
26
|
+
Array.isArray(paths) &&
|
|
27
|
+
paths.every((path) => typeof path === 'string')
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default defineConfig({
|
|
32
|
+
plugins: [react()],
|
|
33
|
+
resolve: {
|
|
34
|
+
alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
|
|
35
|
+
},
|
|
36
|
+
server: { host: '127.0.0.1', port: {{port}}, strictPort: true, proxy: mockProxy() },
|
|
37
|
+
});
|