Merge pull request 'ui_minimize' (#4024) from Qubasa/clan-core:ui_minimize into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4024
This commit is contained in:
Luis Hebendanz
2025-06-18 19:17:59 +00:00
24 changed files with 541 additions and 882 deletions

View File

@@ -1,43 +0,0 @@
## Usage
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via
`pnpm up -Lri`.
This is the reason you see a `pnpm-lock.yaml`. That being said, any package
manager will work. This file can be safely be removed once you clone a template.
```bash
$ npm install # or pnpm install or yarn install
```
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
## Available Scripts
In the project directory, you can run:
### `npm run dev` or `npm start`
Runs the app in the development mode.<br> Open
[http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
### `npm run build`
Builds the app for production to the `dist` folder.<br> It correctly bundles
Solid in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br> Your app is
ready to be deployed!
### `npm run storybook`
Starts an instance of [storybook](https://storybook.js.org/).
For more info on how to write stories, please [see here](https://storybook.js.org/docs).
## Deployment
You can deploy the `dist` folder to any static host provider (netlify, surge,
now, etc.)

View File

@@ -1,37 +0,0 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import tailwind from "eslint-plugin-tailwindcss";
import pluginQuery from "@tanstack/eslint-plugin-query";
import { globalIgnores } from "eslint/config";
const config = tseslint.config(
eslint.configs.recommended,
...pluginQuery.configs["flat/recommended"],
...tseslint.configs.strict,
...tseslint.configs.stylistic,
...tailwind.configs["flat/recommended"],
globalIgnores(["src/types/index.d.ts"]),
{
rules: {
"tailwindcss/no-contradicting-classname": [
"error",
{
callees: ["cx"],
},
],
"tailwindcss/no-custom-classname": [
"error",
{
callees: ["cx"],
whitelist: ["material-icons"],
},
],
// TODO: make this more strict by removing later
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-non-null-assertion": "off",
},
},
);
export default config;

View File

@@ -0,0 +1 @@
../ui/eslint.config.mjs

View File

@@ -1,97 +0,0 @@
/**
* This script generates a custom index.html file for the webview UI.
* It reads the manifest.json file generated by Vite and uses it to generate the HTML file.
* It also processes the CSS files to rewrite the URLs in the CSS files to match the new location of the assets.
* The script is run after the Vite build is complete.
*
* This is necessary because the webview UI is loaded from the local file system and the URLs in the CSS files need to be rewritten to match the new location of the assets.
* The generated index.html file is then used as the entry point for the webview UI.
*/
import fs from "node:fs";
import postcss from "postcss";
import path from "node:path";
import css_url from "postcss-url";
const distPath = path.resolve("dist");
const manifestPath = path.join(distPath, ".vite/manifest.json");
const outputPath = path.join(distPath, "index.html");
fs.readFile(manifestPath, { encoding: "utf8" }, (err, data) => {
if (err) {
return console.error("Failed to read manifest:", err);
}
const manifest = JSON.parse(data);
/** @type {{ file: string; name: string; src: string; isEntry: bool; css: string[]; } []} */
const assets = Object.values(manifest);
console.log(`Generate custom index.html from ${manifestPath} ...`);
// Start with a basic HTML structure
let htmlContent = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webview UI</title>`;
// Add linked stylesheets
assets.forEach((asset) => {
// console.log(asset);
if (asset.src === "index.html") {
asset.css.forEach((cssEntry) => {
// css to be processed
const css = fs.readFileSync(`dist/${cssEntry}`, "utf8");
// process css
postcss()
.use(
css_url({
url: (asset, dir) => {
const res = path.basename(asset.url);
console.log(`Rewriting CSS url(): ${asset.url} to ${res}`);
return res;
},
}),
)
.process(css, {
from: `dist/${cssEntry}`,
to: `dist/${cssEntry}`,
})
.then((result) => {
fs.writeFileSync(`dist/${cssEntry}`, result.css, "utf8");
});
// Extend the HTML content with the linked stylesheet
console.log(`Relinking html css stylesheet: ${cssEntry}`);
htmlContent += `\n <link rel="stylesheet" href="${cssEntry}">`;
});
}
});
htmlContent += `
</head>
<body>
<div id="app"></div>
`;
// Add scripts
assets.forEach((asset) => {
if (asset.file.endsWith(".js")) {
console.log(`Relinking js script: ${asset.file}`);
htmlContent += `\n <script src="${asset.file}"></script>`;
}
});
htmlContent += `
</body>
</html>`;
// Write the HTML file
fs.writeFile(outputPath, htmlContent, (err) => {
if (err) {
console.error("Failed to write custom index.html:", err);
} else {
console.log("Custom index.html generated successfully!");
}
});
});

View File

@@ -0,0 +1 @@
../ui/gtk.webview.js

View File

@@ -0,0 +1,9 @@
{
"ignore": [
"gtk.webview.js",
"stylelint.config.js",
"util.ts",
"src/components/v2/**",
"api/**"
]
}

1
pkgs/clan-app/ui-2d/package-lock.json generated Symbolic link
View File

@@ -0,0 +1 @@
../ui/package-lock.json

View File

@@ -0,0 +1,95 @@
{
"name": "@clan/ui",
"version": "0.0.1",
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "npm run check && npm run test && vite build && npm run convert-html",
"convert-html": "node gtk.webview.js",
"serve": "vite preview",
"check": "tsc --noEmit --skipLibCheck && eslint ./src",
"knip": "knip",
"test": "vitest run --project unit --typecheck",
"storybook": "storybook",
"storybook-build": "storybook build",
"storybook-dev": "storybook dev -p 6006",
"test-storybook": "vitest run --project storybook",
"test-storybook-update-snapshots": "vitest run --project storybook --update",
"test-storybook-static": "npm run storybook-build && concurrently -k -s first -n 'SB,TEST' -c 'magenta,blue' 'http-server storybook-static --port 6006 --silent' 'wait-on tcp:127.0.0.1:6006 && npm run test-storybook'"
},
"license": "MIT",
"devDependencies": {
"@babel/plugin-syntax-import-attributes": "^7.27.1",
"@eslint/js": "^9.3.0",
"@kachurun/storybook-solid-vite": "^9.0.11",
"@storybook/addon-a11y": "^9.0.8",
"@storybook/addon-docs": "^9.0.8",
"@storybook/addon-links": "^9.0.8",
"@storybook/addon-onboarding": "^9.0.8",
"@storybook/addon-viewport": "^9.0.8",
"@storybook/addon-vitest": "^9.0.8",
"@tailwindcss/typography": "^0.5.13",
"@types/json-schema": "^7.0.15",
"@types/node": "^22.15.19",
"@types/three": "^0.176.0",
"@typescript-eslint/parser": "^8.32.1",
"@vitest/browser": "^3.2.3",
"@vitest/coverage-v8": "^3.2.3",
"autoprefixer": "^10.4.19",
"classnames": "^2.5.1",
"concurrently": "^9.1.2",
"eslint": "^9.27.0",
"eslint-plugin-tailwindcss": "^3.17.0",
"http-server": "^14.1.1",
"jsdom": "^26.1.0",
"knip": "^5.61.2",
"playwright": "~1.52.0",
"postcss": "^8.4.38",
"postcss-url": "^10.1.3",
"prettier": "^3.2.5",
"solid-devtools": "^0.34.0",
"storybook": "^9.0.8",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",
"typescript-eslint": "^8.32.1",
"vite": "^6.3.5",
"vite-plugin-solid": "^2.8.2",
"vite-plugin-solid-svg": "^0.8.1",
"vitest": "^3.2.3",
"wait-on": "^8.0.3"
},
"dependencies": {
"@floating-ui/dom": "^1.6.8",
"@kobalte/core": "^0.13.10",
"@kobalte/tailwindcss": "^0.9.0",
"@modular-forms/solid": "^0.25.1",
"@solid-primitives/storage": "^4.3.2",
"@solidjs/router": "^0.15.3",
"@tanstack/eslint-plugin-query": "^5.51.12",
"@tanstack/solid-query": "^5.76.0",
"corvu": "^0.7.1",
"material-icons": "^1.13.12",
"nanoid": "^5.0.7",
"solid-js": "^1.9.7",
"solid-markdown": "^2.0.13",
"solid-toast": "^0.5.0",
"three": "^0.176.0"
},
"optionalDependencies": {
"@esbuild/darwin-arm64": "^0.25.4",
"@esbuild/darwin-x64": "^0.25.4",
"@esbuild/linux-arm64": "^0.25.4",
"@esbuild/linux-x64": "^0.25.4"
},
"overrides": {
"vite": {
"rollup": "npm:@rollup/wasm-node@^4.34.9"
},
"@rollup/rollup-darwin-x64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-linux-x64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-darwin-arm64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-linux-arm64": "npm:@rollup/wasm-node@^4.34.9"
}
}

View File

@@ -1,8 +0,0 @@
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
export default config;

View File

@@ -0,0 +1 @@
../ui/postcss.config.js

View File

@@ -1,9 +0,0 @@
/**
* @see https://prettier.io/docs/en/configuration.html
* @type {import("prettier").Config}
*/
const config = {
trailingComma: "all",
};
export default config;

View File

@@ -0,0 +1 @@
../ui/prettier.config.js

View File

@@ -6,7 +6,6 @@ import {
RemoteDataSource,
} from "./RemoteForm";
import { createSignal } from "solid-js";
import { fn } from "@storybook/test";
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
// Default values for the form

View File

@@ -89,7 +89,6 @@ const Icon: Component<IconProps> = (props) => {
width={iconProps.size || 16}
height={iconProps.size || 16}
viewBox="0 0 48 48"
// @ts-expect-error: dont know, fix this type nit later
ref={iconProps.ref}
{...iconProps}
/>

View File

@@ -23,7 +23,6 @@ import { ApiTester } from "./api_test";
import { IconVariant } from "./components/icon";
import { Components } from "./routes/components";
import { VarsPage } from "./routes/machines/install/vars-step";
import { ThreePlayground } from "./three";
import { ClanProvider } from "./contexts/clan";
export const client = new QueryClient();
@@ -160,28 +159,12 @@ export const routes: AppRoute[] = [
path: "/internal-dev",
label: "Internal (Only visible in dev mode)",
children: [
{
path: "/hosts",
label: "Local Hosts",
component: () => <HostList />,
},
{
path: "/3d",
label: "3D-Playground",
component: () => <ThreePlayground />,
},
{
path: "/api_testing",
label: "api_testing",
hidden: false,
component: () => <ApiTester />,
},
{
path: "/components",
label: "Components",
hidden: false,
component: () => <Components />,
},
],
},
];

View File

@@ -23,7 +23,6 @@ import {
type RemoteData,
HostKeyCheck,
} from "@/src/components/RemoteForm";
import { ac } from "vitest/dist/chunks/reporters.d.C-cu31ET";
export type HardwareValues = FieldValues & {
report: boolean;

View File

@@ -1,271 +0,0 @@
import { createEffect, createSignal, onCleanup, onMount, Show } from "solid-js";
import * as THREE from "three";
import { Button } from "./components/Button/Button";
import Icon from "./components/icon";
function addCubesSpiral({
scene,
count,
gap,
selected,
}: {
scene: THREE.Scene;
count: number;
gap: number;
selected?: string;
}) {
const cubeSize = 1;
const baseSize = 1.4;
const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
const baseGeometry = new THREE.BoxGeometry(baseSize, 0.05, baseSize);
const cubeMaterial = new THREE.MeshStandardMaterial({
color: 0xe0e0e0,
roughness: 0.6,
metalness: 0.1,
});
const baseMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.8,
metalness: 0,
});
let placed = 0;
const visited = new Set<string>();
let x = 0;
let z = 0;
let dx = 1;
let dz = 0;
let segmentLength = 1;
let segmentPassed = 0;
let stepsTaken = 0;
let turnCounter = 0;
while (placed < count) {
const key = `${x},${z}`;
if (!visited.has(key)) {
if ((x + z) % 2 === 0) {
// Place base
const base = new THREE.Mesh(baseGeometry, baseMaterial);
base.position.set(x * gap, 0, z * gap);
base.receiveShadow = true;
base.castShadow = true;
scene.add(base);
// Place cube
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
if (selected && +selected === placed) {
console.log("Selected", placed);
cube.material = new THREE.MeshStandardMaterial({
color: 0x99e0ff,
roughness: 0.6,
metalness: 0.1,
});
base.material = new THREE.MeshStandardMaterial({
color: 0x99e0ff,
roughness: 0.6,
metalness: 0.1,
});
}
// Store
cube.userData = { id: placed };
cube.position.set(x * gap, 0.55, z * gap);
cube.castShadow = true;
scene.add(cube);
placed++;
}
visited.add(key);
}
x += dx;
z += dz;
segmentPassed++;
stepsTaken++;
if (segmentPassed === segmentLength) {
segmentPassed = 0;
// Turn right: [1,0] → [0,1] → [-1,0] → [0,-1]
const temp = dx;
dx = -dz;
dz = temp;
turnCounter++;
if (turnCounter % 2 === 0) {
segmentLength++;
}
}
// Fail-safe to prevent infinite loops
if (stepsTaken > count * 20) break;
}
// Clean up geometry
cubeGeometry.dispose();
baseGeometry.dispose();
}
interface ViewProps {
count: number;
onCubeClick: (id: number) => void;
selected?: string;
}
const View = (props: ViewProps) => {
let container: HTMLDivElement | undefined;
onMount(() => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
container!.clientWidth / container!.clientHeight,
0.1,
1000,
);
// Transparent renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(container!.clientWidth, container!.clientHeight);
renderer.setClearColor(0x000000, 0); // Transparent background
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
container!.appendChild(renderer.domElement);
// Cube (casts shadow)
const cubeGeometry = new THREE.BoxGeometry();
const cubeMaterial = new THREE.MeshStandardMaterial({
color: 0xb0c0c2,
roughness: 0.4,
metalness: 0.1,
});
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
cube.position.y = 1;
// scene.add(cube);
addCubesSpiral({
scene,
count: props.count,
gap: 1.5,
selected: props.selected,
});
const factor = Math.log10(props.count) / 10 + 1;
camera.position.set(5 * factor, 6 * factor, 5 * factor); // from above and to the side
camera.lookAt(0, 0, 0);
// Floor (receives shadow)
const floorGeometry = new THREE.PlaneGeometry(100, 100);
const floorMaterial = new THREE.ShadowMaterial({ opacity: 0.1 });
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.position.y = -0.1;
floor.receiveShadow = true;
scene.add(floor);
// Light (casts shadow)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(-20, 30, 20); // above & behind the cube
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048; // higher res = smoother shadow
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.radius = 6;
// directionalLight.shadow.radius
scene.add(directionalLight);
// Optional ambient light for slight scene illumination
scene.add(new THREE.AmbientLight(0xffffff, 0.2));
// Animate
// const animate = () => {
// animationId = requestAnimationFrame(animate);
// };
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const handleClick = (event: MouseEvent) => {
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
const cube = intersects.find((i) => i.object.userData?.id !== undefined);
if (cube) {
props.onCubeClick(cube.object.userData.id);
}
};
renderer.domElement.addEventListener("click", handleClick);
renderer.render(scene, camera);
// let animationId = requestAnimationFrame(animate);
onCleanup(() => {
// cancelAnimationFrame(animationId);
renderer.dispose();
cubeGeometry.dispose();
cubeMaterial.dispose();
floorGeometry.dispose();
floorMaterial.dispose();
container?.removeChild(renderer.domElement);
renderer.domElement.removeEventListener("click", handleClick);
});
});
return (
<div
ref={container}
style={{ width: "100%", height: "100%", overflow: "hidden" }}
/>
);
};
export const ThreePlayground = () => {
const [count, setCount] = createSignal(1);
const [selected, setSelected] = createSignal<string>("");
const onCubeClick = (id: number) => {
console.log(`Cube ${id} clicked`);
setSelected(`${id}`);
};
return (
<div class="relative size-full">
<Show when={selected() || !selected()} keyed>
<Show when={count()} keyed>
{(c) => (
<View count={c} onCubeClick={onCubeClick} selected={selected()} />
)}
</Show>
</Show>
<div class="absolute bottom-4 right-0 z-10 flex w-full items-center justify-center">
<div class="flex w-fit items-center justify-between gap-4 rounded-xl border px-8 py-2 text-white shadow-2xl bg-inv-1 border-inv-1">
<Button startIcon={<Icon icon="Edit" />}></Button>
<Button startIcon={<Icon icon="Grid" />}></Button>
<Button
startIcon={<Icon icon="Plus" />}
onClick={() => {
setCount((c) => c + 1);
}}
></Button>
<Button
startIcon={<Icon icon="Trash" />}
onClick={() => {
setCount((c) => c - 1);
}}
></Button>
</div>
</div>
</div>
);
};

View File

@@ -1,6 +0,0 @@
module.exports = {
extends: ["stylelint-config-standard", "stylelint-config-tailwindcss"],
rules: {
// You can adjust rules here
},
};

View File

@@ -0,0 +1 @@
../ui/stylelint.config.js

View File

@@ -0,0 +1 @@
../ui/tailwind

View File

@@ -1,12 +0,0 @@
import typography from "@tailwindcss/typography";
import kobalte from "@kobalte/tailwindcss";
import core from "./tailwind/core-plugin";
/** @type {import('tailwindcss').Config} */
const config = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {},
plugins: [typography, core, kobalte],
};
export default config;

View File

@@ -0,0 +1 @@
../ui/tailwind.config.ts

View File

@@ -1,322 +0,0 @@
import plugin from "tailwindcss/plugin";
import { typography } from "./typography";
// @ts-expect-error: lib of tailwind has no types
import { parseColor } from "tailwindcss/lib/util/color";
/* Converts HEX color to RGB */
const toRGB = (value: string) =>
"rgb(" + parseColor(value).color.join(" ") + ")";
const mkBorderUtils = (
theme: (n: string) => unknown,
prefix: string,
cssProperty: string,
) => ({
// - def colors
[`.${prefix}-def-1`]: {
[cssProperty]: theme("colors.secondary.100"),
},
[`.${prefix}-def-2`]: {
[cssProperty]: theme("colors.secondary.200"),
},
[`.${prefix}-def-3`]: {
[cssProperty]: theme("colors.secondary.300"),
},
[`.${prefix}-def-4`]: {
[cssProperty]: theme("colors.secondary.400"),
},
// - def acc colors
[`.${prefix}-def-acc-1`]: {
[cssProperty]: theme("colors.secondary.500"),
},
[`.${prefix}-def-acc-2`]: {
[cssProperty]: theme("colors.secondary.900"),
},
[`.${prefix}-def-acc-3`]: {
[cssProperty]: theme("colors.secondary.900"),
},
[`.${prefix}-def-acc-4`]: {
[cssProperty]: theme("colors.secondary.950"),
},
// - inverse colors
[`.${prefix}-inv-1`]: {
[cssProperty]: theme("colors.secondary.700"),
},
[`.${prefix}-inv-2`]: {
[cssProperty]: theme("colors.secondary.800"),
},
[`.${prefix}-inv-3`]: {
[cssProperty]: theme("colors.secondary.900"),
},
[`.${prefix}-inv-4`]: {
[cssProperty]: theme("colors.secondary.950"),
},
// - inverse acc
[`.${prefix}-inv-acc-1`]: {
[cssProperty]: theme("colors.secondary.300"),
},
[`.${prefix}-inv-acc-2`]: {
[cssProperty]: theme("colors.secondary.200"),
},
[`.${prefix}-inv-acc-3`]: {
[cssProperty]: theme("colors.secondary.100"),
},
[`.${prefix}-inv-acc-4`]: {
[cssProperty]: theme("colors.secondary.50"),
},
[`.${prefix}-int-1`]: {
[cssProperty]: theme("colors.info.500"),
},
[`.${prefix}-int-2`]: {
[cssProperty]: theme("colors.info.600"),
},
[`.${prefix}-int-3`]: {
[cssProperty]: theme("colors.info.700"),
},
[`.${prefix}-int-4`]: {
[cssProperty]: theme("colors.info.800"),
},
[`.${prefix}-semantic-1`]: {
[cssProperty]: theme("colors.error.500"),
},
[`.${prefix}-semantic-2`]: {
[cssProperty]: theme("colors.error.600"),
},
[`.${prefix}-semantic-3`]: {
[cssProperty]: theme("colors.error.700"),
},
[`.${prefix}-semantic-4`]: {
[cssProperty]: theme("colors.error.800"),
},
});
export default plugin.withOptions(
(_options = {}) =>
({ addUtilities, theme, addVariant, e }) => {
// @ts-expect-error: lib of tailwind has no types
addVariant("popover-open", ({ modifySelectors, separator }) => {
// @ts-expect-error: lib of tailwind has no types
modifySelectors(({ className }) => {
return `.${e(`popover-open${separator}${className}`)}:popover-open`;
});
});
addUtilities({
// Background colors
// default
".bg-def-1": {
backgroundColor: theme("colors.white"),
},
".bg-def-2": {
backgroundColor: theme("colors.secondary.50"),
},
".bg-def-3": {
backgroundColor: theme("colors.secondary.100"),
},
".bg-def-4": {
backgroundColor: theme("colors.secondary.200"),
},
// default accessible
".bg-def-acc-1": {
backgroundColor: theme("colors.primary.50"),
},
".bg-def-acc-2": {
backgroundColor: theme("colors.secondary.100"),
},
".bg-def-acc-3": {
backgroundColor: theme("colors.secondary.200"),
},
".bg-def-acc-4": {
backgroundColor: theme("colors.secondary.300"),
},
// bg inverse
".bg-inv-1": {
backgroundColor: theme("colors.primary.600"),
},
".bg-inv-2": {
backgroundColor: theme("colors.primary.700"),
},
".bg-inv-3": {
backgroundColor: theme("colors.primary.800"),
},
".bg-inv-4": {
backgroundColor: theme("colors.primary.900"),
},
// bg inverse accessible
".bg-inv-acc-1": {
backgroundColor: theme("colors.secondary.500"),
},
".bg-inv-acc-2": {
backgroundColor: theme("colors.secondary.600"),
},
".bg-inv-acc-3": {
backgroundColor: theme("colors.secondary.700"),
},
".bg-inv-acc-4": {
backgroundColor: theme("colors.secondary.900"),
},
// bg inverse accent
".bg-semantic-1": {
backgroundColor: theme("colors.error.50"),
},
".bg-semantic-2": {
backgroundColor: theme("colors.error.100"),
},
".bg-semantic-3": {
backgroundColor: theme("colors.error.200"),
},
".bg-semantic-4": {
backgroundColor: theme("colors.error.300"),
},
// Text colors
".fg-def-1": {
color: theme("colors.secondary.950"),
},
".fg-def-2": {
color: theme("colors.secondary.900"),
},
".fg-def-3": {
color: theme("colors.secondary.700"),
},
".fg-def-4": {
color: theme("colors.secondary.400"),
},
// fg inverse
".fg-inv-1": {
color: theme("colors.white"),
},
".fg-inv-2": {
color: theme("colors.secondary.100"),
},
".fg-inv-3": {
color: theme("colors.secondary.300"),
},
".fg-inv-4": {
color: theme("colors.secondary.400"),
},
".fg-semantic-1": {
color: theme("colors.error.500"),
},
".fg-semantic-2": {
color: theme("colors.error.600"),
},
".fg-semantic-3": {
color: theme("colors.error.700"),
},
".fg-semantic-4": {
color: theme("colors.error.800"),
},
...mkBorderUtils(theme, "border", "borderColor"),
...mkBorderUtils(theme, "border-b", "borderBottom"),
...mkBorderUtils(theme, "border-t", "borderTop"),
...mkBorderUtils(theme, "border-l", "borderLeft"),
...mkBorderUtils(theme, "border-r", "borderRight"),
// Example: dark mode utilities (all elements within <html class="dark"> )
// ".dark .bg-def-1": {
// backgroundColor: theme("colors.black"),
// },
// ".dark .bg-def-2": {
// backgroundColor: theme("colors.primary.900"),
// },
// ".dark .bg-def-3": {
// backgroundColor: theme("colors.primary.800"),
// },
// ".dark .bg-def-4": {
// backgroundColor: theme("colors.primary.700"),
// },
// ".dark .bg-def-5": {
// backgroundColor: theme("colors.primary.600"),
// },
});
// add more base styles
},
// add configuration which is merged with the final config
() => ({
theme: {
extend: {
colors: {
white: toRGB("#ffffff"),
black: toRGB("#000000"),
primary: {
50: toRGB("#f4f9f9"),
100: toRGB("#dbeceb"),
200: toRGB("#b6d9d6"),
300: toRGB("#8abebc"),
400: toRGB("#478585"),
500: toRGB("#526f6f"),
600: toRGB("#4b6767"),
700: toRGB("#345253"),
800: toRGB("#2b4647"),
900: toRGB("#203637"),
950: toRGB("#162324"),
},
secondary: {
50: toRGB("#f7f9fA"),
100: toRGB("#e7f2f4"),
200: toRGB("#d8e8eb"),
300: toRGB("#afc6ca"),
400: toRGB("#90b2b7"),
500: toRGB("#7b9b9f"),
600: toRGB("#4f747A"),
700: toRGB("#415e63"),
800: toRGB("#446065"),
900: toRGB("#2c4347"),
950: toRGB("#0d1416"),
},
info: {
50: toRGB("#eff9ff"),
100: toRGB("#dff2ff"),
200: toRGB("#b8e8ff"),
300: toRGB("#78d6ff"),
400: toRGB("#2cc0ff"),
500: toRGB("#06aaf1"),
600: toRGB("#006ca7"),
700: toRGB("#006ca7"),
800: toRGB("#025b8a"),
900: toRGB("#084c72"),
950: toRGB("#06304b"),
},
error: {
50: toRGB("#fcf3f8"),
100: toRGB("#f9eaf4"),
200: toRGB("#f5d5e9"),
300: toRGB("#ea9ecb"),
400: toRGB("#e383ba"),
500: toRGB("#d75d9f"),
600: toRGB("#c43e81"),
700: toRGB("#a82e67"),
800: toRGB("#8c2855"),
900: toRGB("#75264a"),
950: toRGB("#461129"),
},
},
boxShadow: {
"input-active": "0px 0px 0px 1px #FFF, 0px 0px 0px 2px #203637",
"button-primary":
"2px 2px 0px 0px var(--clr-bg-inv-acc-3, #415E63) inset",
"button-primary-hover":
"2px 2px 0px 0px var(--clr-bg-inv-acc-2, #4F747A) inset",
"button-primary-focus":
"0px 0px 0px 1px #FFF, 0px 0px 0px 2px var(--clr-border-def-sem-inf-1, #06AAF1), 2px 2px 0px 0px var(--clr-bg-inv-acc-2, #4F747A) inset",
"button-primary-active":
"0px 0px 0px 1px #FFF, 0px 0px 0px 2px var(--clr-bg-inv-acc-4, #203637), -2px -2px 0px 0px var(--clr-bg-inv-acc-1, #7B9B9F) inset",
"button-secondary":
"-2px -2px 0px 0px #CEDFE2 inset, 2px 2px 0px 0px white inset",
"button-secondary-hover":
"-2px -2px 0px 0px #CEDFE2 inset, 2px 2px 0px 0px #FFF inset",
"button-secondary-focus":
"0px 0px 0px 1px #FFF, 0px 0px 0px 2px var(--clr-border-def-sem-inf-1, #06AAF1), -2px -2px 0px 0px #CEDFE2 inset, 2px 2px 0px 0px #FFF inset",
"button-secondary-active":
"0px 0px 0px 1px white, 0px 0px 0px 2px var(--clr-bg-inv-acc-4, #203637), 2px 2px 0px 0px var(--clr-bg-inv-acc-2, #4F747A) inset",
},
},
...typography,
},
}),
);

View File

@@ -1,22 +0,0 @@
import defaultTheme from "tailwindcss/defaultTheme";
import type { Config } from "tailwindcss";
export const typography: Partial<Config["theme"]> = {
fontFamily: {
sans: ["Archivo SemiCondensed", ...defaultTheme.fontFamily.sans],
},
fontSize: {
...defaultTheme.fontSize,
title: ["1.125rem", { lineHeight: "124%" }],
"title-m": ["1.25rem", { lineHeight: "124%" }],
"title-l": ["1.375rem", { lineHeight: "124%" }],
label: ["0.8125rem", { lineHeight: "100%" }],
"label-s": ["0.75rem", { lineHeight: "100%" }],
"label-xs": ["0.6875rem", { lineHeight: "124%" }],
},
// textColor: {
// ...defaultTheme.textColor,
// primary: "#0D1416",
// secondary: "#2C4347",
// },
} as const;

1
pkgs/clan-app/ui-2d/tests Symbolic link
View File

@@ -0,0 +1 @@
../ui/tests

View File

@@ -8,7 +8,7 @@
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite-plugin-solid-svg/types-component-solid", "vite/client"],
"types": ["vite/client", "vite-plugin-solid-svg/types-component-solid"],
"noEmit": true,
"resolveJsonModule": true,
"allowJs": true,

View File

@@ -1,33 +0,0 @@
export function isValidHostname(value: string | null | undefined) {
if (typeof value !== "string") return false;
const validHostnameChars = /^[a-zA-Z0-9-.]{1,253}\.?$/g;
if (!validHostnameChars.test(value)) {
return false;
}
if (value.endsWith(".")) {
value = value.slice(0, value.length - 1);
}
if (value.length > 253) {
return false;
}
const labels = value.split(".");
const isValid = labels.every(function (label) {
const validLabelChars = /^([a-zA-Z0-9-]+)$/g;
const validLabel =
validLabelChars.test(label) &&
label.length < 64 &&
!label.startsWith("-") &&
!label.endsWith("-");
return validLabel;
});
return isValid;
}

1
pkgs/clan-app/ui-2d/util.ts Symbolic link
View File

@@ -0,0 +1 @@
../ui/util.ts

View File

@@ -27,7 +27,7 @@ function regenPythonApiOnFileChange() {
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "./"), // Adjust the path as needed
"@": path.resolve(__dirname, "./"), // This now points to ui-2d directory
},
},
optimizeDeps: {

View File

@@ -0,0 +1 @@
../ui/vitest.config.ts

View File

@@ -49,6 +49,7 @@
"eslint-plugin-tailwindcss": "^3.17.0",
"http-server": "^14.1.1",
"jsdom": "^26.1.0",
"knip": "^5.61.2",
"playwright": "~1.52.0",
"postcss": "^8.4.38",
"postcss-url": "^10.1.3",
@@ -738,6 +739,40 @@
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@emnapi/core": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
"integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.0.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
"integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz",
"integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
@@ -1637,6 +1672,19 @@
"solid-js": "^1.3.1"
}
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
"integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.4.3",
"@emnapi/runtime": "^1.4.3",
"@tybys/wasm-util": "^0.9.0"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1679,6 +1727,191 @@
"dev": true,
"license": "MIT"
},
"node_modules/@oxc-resolver/binding-darwin-arm64": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.2.0.tgz",
"integrity": "sha512-ruKLkS+Dm/YIJaUhzEB7zPI+jh3EXxu0QnNV8I7t9jf0lpD2VnltuyRbhrbJEkksklZj//xCMyFFsILGjiU2Mg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oxc-resolver/binding-darwin-x64": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.2.0.tgz",
"integrity": "sha512-0zhgNUm5bYezdSFOg3FYhtVP83bAq7FTV/3suGQDl/43MixfQG7+bl+hlrP4mz6WlD2SUb2u9BomnJWl1uey9w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oxc-resolver/binding-freebsd-x64": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.2.0.tgz",
"integrity": "sha512-SHOxfCcZV1axeIGfyeD1BkdLvfQgjmPy18tO0OUXGElcdScxD6MqU5rj/AVtiuBT+51GtFfOKlwl1+BdVwhD1A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.2.0.tgz",
"integrity": "sha512-mgEkYrJ+N90sgEDqEZ07zH+4I1D28WjqAhdzfW3aS2x2vynVpoY9jWfHuH8S62vZt3uATJrTKTRa8CjPWEsrdw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-arm64-gnu": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.2.0.tgz",
"integrity": "sha512-BhEzNLjn4HjP8+Q18D3/jeIDBxW7OgoJYIjw2CaaysnYneoTlij8hPTKxHfyqq4IGM3fFs9TLR/k338M3zkQ7g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-arm64-musl": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.2.0.tgz",
"integrity": "sha512-yxbMYUgRmN2V8x8XoxmD/Qq6aG7YIW3ToMDILfmcfeeRRVieEJ3DOWBT0JSE+YgrOy79OyFDH/1lO8VnqLmDQQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-riscv64-gnu": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.2.0.tgz",
"integrity": "sha512-QG1UfgC2N2qhW1tOnDCgB/26vn1RCshR5sYPhMeaxO1gMQ3kEKbZ3QyBXxrG1IX5qsXYj5hPDJLDYNYUjRcOpg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-s390x-gnu": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.2.0.tgz",
"integrity": "sha512-uqTDsQdi6mrkSV1gvwbuT8jf/WFl6qVDVjNlx7IPSaAByrNiJfPrhTmH8b+Do58Dylz7QIRZgxQ8CHIZSyBUdg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-x64-gnu": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.2.0.tgz",
"integrity": "sha512-GZdHXhJ7p6GaQg9MjRqLebwBf8BLvGIagccI6z5yMj4fV3LU4QuDfwSEERG+R6oQ/Su9672MBqWwncvKcKT68w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-linux-x64-musl": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.2.0.tgz",
"integrity": "sha512-YBAC3GOicYznReG2twE7oFPSeK9Z1f507z1EYWKg6HpGYRYRlJyszViu7PrhMT85r/MumDTs429zm+CNqpFWOA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxc-resolver/binding-wasm32-wasi": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.2.0.tgz",
"integrity": "sha512-+qlIg45CPVPy+Jn3vqU1zkxA/AAv6e/2Ax/ImX8usZa8Tr2JmQn/93bmSOOOnr9fXRV9d0n4JyqYzSWxWPYDEw==",
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@napi-rs/wasm-runtime": "^0.2.11"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@oxc-resolver/binding-win32-arm64-msvc": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.2.0.tgz",
"integrity": "sha512-AI4KIpS8Zf6vwfOPk0uQPSC0pQ1m5HU4hCbtrgL21JgJSlnJaeEu3/aoOBB45AXKiExBU9R+CDR7aSnW7uhc5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@oxc-resolver/binding-win32-x64-msvc": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.2.0.tgz",
"integrity": "sha512-r19cQc7HaEJ76HFsMsbiKMTIV2YqFGSof8H5hB7e5Jkb/23Y8Isv1YrSzkDaGhcw02I/COsrPo+eEmjy35eFuA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -2348,6 +2581,17 @@
"dev": true,
"license": "MIT"
},
"node_modules/@tybys/wasm-util": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
"integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@types/aria-query": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
@@ -4619,6 +4863,16 @@
"reusify": "^1.0.4"
}
},
"node_modules/fd-package-json": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz",
"integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"walk-up-path": "^4.0.0"
}
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
@@ -4739,6 +4993,22 @@
"node": ">= 6"
}
},
"node_modules/formatly": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/formatly/-/formatly-0.2.4.tgz",
"integrity": "sha512-lIN7GpcvX/l/i24r/L9bnJ0I8Qn01qijWpQpDDvTLL29nKqSaJJu4h20+7VJ6m2CAhQ2/En/GbxDiHCzq/0MyA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fd-package-json": "^2.0.0"
},
"bin": {
"formatly": "bin/index.mjs"
},
"engines": {
"node": ">=18.3.0"
}
},
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -5491,6 +5761,89 @@
"node": ">=6"
}
},
"node_modules/knip": {
"version": "5.61.2",
"resolved": "https://registry.npmjs.org/knip/-/knip-5.61.2.tgz",
"integrity": "sha512-ZBv37zDvZj0/Xwk0e93xSjM3+5bjxgqJ0PH2GlB5tnWV0ktXtmatWLm+dLRUCT/vpO3SdGz2nNAfvVhuItUNcQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/webpro"
},
{
"type": "opencollective",
"url": "https://opencollective.com/knip"
},
{
"type": "polar",
"url": "https://polar.sh/webpro-nl"
}
],
"license": "ISC",
"dependencies": {
"@nodelib/fs.walk": "^1.2.3",
"fast-glob": "^3.3.3",
"formatly": "^0.2.4",
"jiti": "^2.4.2",
"js-yaml": "^4.1.0",
"minimist": "^1.2.8",
"oxc-resolver": "^11.1.0",
"picocolors": "^1.1.1",
"picomatch": "^4.0.1",
"smol-toml": "^1.3.4",
"strip-json-comments": "5.0.2",
"zod": "^3.22.4",
"zod-validation-error": "^3.0.3"
},
"bin": {
"knip": "bin/knip.js",
"knip-bun": "bin/knip-bun.js"
},
"engines": {
"node": ">=18.18.0"
},
"peerDependencies": {
"@types/node": ">=18",
"typescript": ">=5.0.4"
}
},
"node_modules/knip/node_modules/jiti": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"dev": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/knip/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/knip/node_modules/strip-json-comments": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.2.tgz",
"integrity": "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -6505,6 +6858,31 @@
"node": ">= 0.8.0"
}
},
"node_modules/oxc-resolver": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.2.0.tgz",
"integrity": "sha512-3iJYyIdDZMDoj0ZSVBrI1gUvPBMkDC4gxonBG+7uqUyK5EslG0mCwnf6qhxK8oEU7jLHjbRBNyzflPSd3uvH7Q==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Boshen"
},
"optionalDependencies": {
"@oxc-resolver/binding-darwin-arm64": "11.2.0",
"@oxc-resolver/binding-darwin-x64": "11.2.0",
"@oxc-resolver/binding-freebsd-x64": "11.2.0",
"@oxc-resolver/binding-linux-arm-gnueabihf": "11.2.0",
"@oxc-resolver/binding-linux-arm64-gnu": "11.2.0",
"@oxc-resolver/binding-linux-arm64-musl": "11.2.0",
"@oxc-resolver/binding-linux-riscv64-gnu": "11.2.0",
"@oxc-resolver/binding-linux-s390x-gnu": "11.2.0",
"@oxc-resolver/binding-linux-x64-gnu": "11.2.0",
"@oxc-resolver/binding-linux-x64-musl": "11.2.0",
"@oxc-resolver/binding-wasm32-wasi": "11.2.0",
"@oxc-resolver/binding-win32-arm64-msvc": "11.2.0",
"@oxc-resolver/binding-win32-x64-msvc": "11.2.0"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -7549,6 +7927,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/smol-toml": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz",
"integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">= 18"
},
"funding": {
"url": "https://github.com/sponsors/cyyynthia"
}
},
"node_modules/solid-devtools": {
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/solid-devtools/-/solid-devtools-0.34.2.tgz",
@@ -9005,6 +9396,16 @@
"node": ">=12.0.0"
}
},
"node_modules/walk-up-path": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz",
"integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==",
"dev": true,
"license": "ISC",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -9332,6 +9733,29 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.25.67",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.67.tgz",
"integrity": "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zod-validation-error": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.2.tgz",
"integrity": "sha512-mdi7YOLtram5dzJ5aDtm1AG9+mxRma1iaMrZdYIpFO7epdKBUwLHIxTF8CPDeCQ828zAXYtizrKlEJAtzgfgrw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"peerDependencies": {
"zod": "^3.25.0"
}
}
}
}