kopia lustrzana https://github.com/zhengkyl/qrframe
setup + number input
commit
f653e1a3ee
|
@ -0,0 +1,29 @@
|
|||
|
||||
dist
|
||||
.solid
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
netlify
|
||||
.vinxi
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
.settings/
|
||||
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -0,0 +1,3 @@
|
|||
# QR Frame
|
||||
|
||||
Powered by [`solid-start`](https://start.solidjs.com);
|
|
@ -0,0 +1,21 @@
|
|||
import { fileURLToPath, URL } from "node:url";
|
||||
import { defineConfig } from "@solidjs/start/config";
|
||||
import UnoCSS from "unocss/vite";
|
||||
|
||||
export default defineConfig({
|
||||
server: { prerender: { crawlLinks: true } },
|
||||
vite: {
|
||||
plugins: [UnoCSS()],
|
||||
resolve: {
|
||||
alias: {
|
||||
// https://christopher.engineering/en/blog/lucide-icons-with-vite-dev-server/
|
||||
"lucide-solid/icons": fileURLToPath(
|
||||
new URL(
|
||||
"./node_modules/lucide-solid/dist/source/icons",
|
||||
import.meta.url
|
||||
)
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "example-with-unocss",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vinxi dev",
|
||||
"build": "vinxi build",
|
||||
"start": "vinxi start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kobalte/core": "^0.13.1",
|
||||
"@solidjs/router": "^0.13.3",
|
||||
"@solidjs/start": "^1.0.0-rc.0",
|
||||
"@unocss/reset": "^0.59.4",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-solid": "^0.378.0",
|
||||
"solid-js": "^1.8.17",
|
||||
"unocss": "^0.59.4",
|
||||
"vinxi": "^0.3.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@unocss/transformer-variant-group": "^0.59.4"
|
||||
}
|
||||
}
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<g>
|
||||
<path d="M2.4 1c-1 .8-.8 2.2-.8 3.3.1 1-.5 2.6.6 3.1 1.2.4 1.9-.8 1.7-1.8 0-.7-.2-2 1-1.6 1 .3 2.7-.3 2.2-1.6s-2-.5-3-.8c-.6 0-1-.5-1.7-.6ZM17.2 1.4c-1 .2-2.6-.4-3 .8-.4 1.2 1 1.8 2 1.5 1.3 0 0 1.6.4 2.3-.2 1.2 1.2 2.4 2.2 1.3.5-.7 0-1.6.1-2.3 0-.8.4-1.5.5-2.2.1-1-.9-1.6-1.8-1.4h-.4zM17.6 12c-1.3.2-1.2 1.8-1.3 2.7 0 .7.6 2.2-.7 1.9-1-.3-2.8 0-2.4 1.4.4 1 1.5.9 2.3.9 1 0 1.9 0 2.7-.3 1-.6.6-1.9.5-2.8v-3c0-.5-.6-.8-1.1-.7zM3 12.2c-1.1 0-1.3 1.4-1.1 2.2l.1 3.2c.6 1 2 .7 3 .9 1 0 2.8.5 3.1-.8.2-1.4-1.4-1.6-2.5-1.5-.8.1-1.7-.4-1.4-1.4 0-.9.2-2.6-1.2-2.6ZM10 5.3c-.7.3-1.7 0-2.4.7-1-.4-2 0-2 1.1 0 2.1-.2 4.3.2 6.4.5.8 1.6.7 2.4 1h3.3c1 0 1.8 0 2.4-.7 1.2 0 1.4-1.2 1.1-2.2-.2-1.4 0-2.9-.3-4.3-.4-1-.9-2-2-1.9-.8-.1-2.2.4-2.6-.1ZM8 7.8h4.4c0 1.5 0 2.9.2 4.3H8V7.9zm4.3 4.3z" style="fill:#000"/>
|
||||
<path d="M11.8 8.6c-1 0-1.8.2-2.7.3.2.7-.2 2 .6 2.3h2V8.6z" style="fill:#000"/>
|
||||
</g>
|
||||
</svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 963 B |
|
@ -0,0 +1,7 @@
|
|||
declare module "lucide-solid/icons/*" {
|
||||
import { LucideProps } from "lucide-solid/dist/types/types";
|
||||
import { Component } from "solid-js";
|
||||
const cmp: Component<LucideProps>;
|
||||
|
||||
export = cmp;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import "@unocss/reset/tailwind.css";
|
||||
import "virtual:uno.css";
|
||||
|
||||
import { Router } from "@solidjs/router";
|
||||
import { FileRoutes } from "@solidjs/start/router";
|
||||
import { Suspense } from "solid-js";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router root={(props) => <Suspense>{props.children}</Suspense>}>
|
||||
<FileRoutes />
|
||||
</Router>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import { NumberField } from "@kobalte/core/number-field";
|
||||
import { Slider } from "@kobalte/core/slider";
|
||||
import ChevronUp from "lucide-solid/icons/chevron-up";
|
||||
import ChevronDown from "lucide-solid/icons/chevron-down";
|
||||
import { createSignal } from "solid-js";
|
||||
|
||||
type Props = {
|
||||
min: number;
|
||||
max: number;
|
||||
value: number;
|
||||
setValue: (v: number) => void;
|
||||
};
|
||||
|
||||
export default function NumberInput(props: Props) {
|
||||
const [rawValue, setRawValue] = createSignal(props.value);
|
||||
|
||||
const safeSetValue = (value: number) => {
|
||||
setRawValue(value);
|
||||
if (
|
||||
value < props.min ||
|
||||
value > props.max ||
|
||||
isNaN(value) ||
|
||||
!Number.isInteger(value)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
props.setValue(value);
|
||||
};
|
||||
|
||||
const [focused, setFocused] = createSignal(false);
|
||||
|
||||
return (
|
||||
<div class="flex items-center gap-4 w-full">
|
||||
<Slider
|
||||
class="w-full"
|
||||
minValue={props.min}
|
||||
maxValue={props.max}
|
||||
value={[props.value]}
|
||||
onChange={(values) => props.setValue(values[0])}
|
||||
>
|
||||
<Slider.Track class="relative h-2 bg-back-subtle rounded-full">
|
||||
<div class="absolute w-4 h-full bg-fore-base rounded-full"></div>
|
||||
<div class="relative h-full mx-[0.5rem] w-[calc(100%-1rem)]">
|
||||
<Slider.Fill class="absolute h-full bg-fore-base rounded-full" />
|
||||
<Slider.Thumb class="h-4 w-4 -top-1 bg-back-base rounded-full border-2 border-fore-base cursor-pointer focus:(outline-none ring-2 ring-fore-base ring-offset-2 ring-offset-back-base)">
|
||||
<Slider.Input class="" />
|
||||
</Slider.Thumb>
|
||||
</div>
|
||||
</Slider.Track>
|
||||
</Slider>
|
||||
<NumberField
|
||||
class="relative rounded-md focus-within:(ring-2 ring-fore-base ring-offset-2 ring-offset-back-base)"
|
||||
minValue={props.min}
|
||||
maxValue={props.max}
|
||||
rawValue={focused() ? rawValue() : props.value}
|
||||
onRawValueChange={safeSetValue}
|
||||
>
|
||||
<NumberField.Input
|
||||
class="w-20 text-sm rounded-md leading-none px-3 py-2 border border-fore-subtle bg-back-base focus:outline-none"
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
/>
|
||||
<NumberField.IncrementTrigger
|
||||
aria-label="Increment"
|
||||
class="absolute right-1 top-1 h-3 w-3 bg-back-subtle rounded-t hover:(bg-back-hover)"
|
||||
>
|
||||
<ChevronUp size={12} />
|
||||
</NumberField.IncrementTrigger>
|
||||
<NumberField.DecrementTrigger
|
||||
aria-label="Decrement"
|
||||
class="absolute right-1 bottom-1 h-3 w-3 bg-back-subtle rounded-b hover:(bg-back-hover)"
|
||||
>
|
||||
<ChevronDown size={12} />
|
||||
</NumberField.DecrementTrigger>
|
||||
</NumberField>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// @refresh reload
|
||||
import { mount, StartClient } from "@solidjs/start/client";
|
||||
|
||||
mount(() => <StartClient />, document.getElementById("app")!);
|
|
@ -0,0 +1,21 @@
|
|||
// @refresh reload
|
||||
import { createHandler, StartServer } from "@solidjs/start/server";
|
||||
|
||||
export default createHandler(() => (
|
||||
<StartServer
|
||||
document={({ assets, children, scripts }) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
{assets}
|
||||
</head>
|
||||
<body class="bg-back-base text-fore-base">
|
||||
<div id="app">{children}</div>
|
||||
{scripts}
|
||||
</body>
|
||||
</html>
|
||||
)}
|
||||
/>
|
||||
));
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="@solidjs/start/env" />
|
|
@ -0,0 +1,14 @@
|
|||
import { A } from "@solidjs/router";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<main class="text-center mx-auto text-gray-700 p-4">
|
||||
<h1 class="max-6-xs text-6xl text-sky-700 font-thin uppercase my-16">
|
||||
Not Found
|
||||
</h1>
|
||||
<A href="/" class="text-sky-600 hover:underline">
|
||||
Home
|
||||
</A>
|
||||
</main>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import { createSignal, type Component, type JSX } from "solid-js";
|
||||
import NumberInput from "~/components/NumberInput";
|
||||
|
||||
export default function Home() {
|
||||
const [minVersion, setMinVersion] = createSignal(1);
|
||||
const [maxVersion, setMaxVersion] = createSignal(40);
|
||||
|
||||
return (
|
||||
<main class="text-center max-w-screen-lg mx-auto p-4">
|
||||
<h1 class="max-6-xs text-6xl font-bold my-16">QR Frame</h1>
|
||||
<div class="flex">
|
||||
<div class="w-full flex flex-col gap-2">
|
||||
<Row title="Min version">
|
||||
<NumberInput
|
||||
min={1}
|
||||
max={40}
|
||||
value={minVersion()}
|
||||
setValue={setMinVersion}
|
||||
/>
|
||||
</Row>
|
||||
<Row title="Max version">
|
||||
<NumberInput
|
||||
min={1}
|
||||
max={40}
|
||||
value={maxVersion()}
|
||||
setValue={setMaxVersion}
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
<div class="w-full flex flex-col gap-2">qr code here</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function Row(props: { title: string; children: JSX.Element }) {
|
||||
return (
|
||||
<label class="flex items-center">
|
||||
<span class="w-40 text-left">{props.title}</span>
|
||||
{props.children}
|
||||
</label>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"types": ["vinxi/types/client"],
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// uno.config.ts
|
||||
import { defineConfig } from "unocss";
|
||||
import transformerVariantGroup from "@unocss/transformer-variant-group";
|
||||
export default defineConfig({
|
||||
transformers: [transformerVariantGroup()],
|
||||
theme: {
|
||||
colors: {
|
||||
fore: {
|
||||
base: "#fafafa",
|
||||
subtle: "#adb5b2",
|
||||
},
|
||||
back: {
|
||||
base: "#09090b",
|
||||
subtle: "#2e3130",
|
||||
hover: "#5b625f",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
Ładowanie…
Reference in New Issue