Compare commits
69 Commits
ee382fa555
...
renovate/g
| Author | SHA1 | Date | |
|---|---|---|---|
| 400d722429 | |||
| 4b81b6f339 | |||
| 25680b6dda | |||
| 4964a38613 | |||
| 45417d4412 | |||
| c2866720eb | |||
| 6150943347 | |||
| 6546ca8837 | |||
| 31621d43d6 | |||
| 9db3849efc | |||
| b4a8a79a6f | |||
| cba342f08e | |||
| a68ad22e66 | |||
| 3f21f0ae8a | |||
| f71b2a99d6 | |||
| 2ae49eeda8 | |||
|
|
3f45c7ae3e | ||
|
|
35d4bf7d7f | ||
| 1da0fbfce1 | |||
| de39e4fa94 | |||
|
|
76ac4317f3 | ||
|
|
1b1f88cf76 | ||
|
|
64a564b6cc | ||
| 4ad043db82 | |||
|
|
4d22f8e46a | ||
| da1149eb23 | |||
|
|
b0408a8929 | ||
|
|
afabfc957b | ||
| 8688604e13 | |||
|
|
999fff8ddc | ||
|
|
eefb4481ec | ||
|
|
26bc15c15b | ||
| d6ec4e9e46 | |||
| 9f9e62858d | |||
|
|
569874a7af | ||
|
|
693e6ec492 | ||
| dd4e8f47b6 | |||
|
|
6c9dcaafc6 | ||
|
|
411aea0a29 | ||
| be0c942316 | |||
| 7df3e93c3d | |||
|
|
cc3db52f02 | ||
| 6f26582f5a | |||
|
|
619f6a78b2 | ||
|
|
3416c5a90c | ||
| 7ee611ed32 | |||
| e35587b1d4 | |||
|
|
04c8640133 | ||
| e37592eaf2 | |||
| 8f0b319229 | |||
| dbe47272cc | |||
| 5269948e21 | |||
|
|
ca00d12a35 | ||
|
|
cf73d97896 | ||
|
|
ef3204322a | ||
|
|
9fbdeb6aa4 | ||
|
|
c15b91a3d9 | ||
|
|
29d9d6bd11 | ||
| 3273bbb9d1 | |||
| 22c43906f8 | |||
|
|
6b88f2948e | ||
|
|
fb860e8be6 | ||
|
|
0e605fb6d8 | ||
| c5558e356f | |||
| f87d952531 | |||
| a0d442f5af | |||
| 1cd70b3ed0 | |||
|
|
ba72ca8889 | ||
|
|
b4ce75500d |
@@ -9,13 +9,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Set up Bun
|
- name: Set up Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
- name: Set up Node
|
|
||||||
uses: actions/setup-node@v5
|
|
||||||
with:
|
|
||||||
node-version: "22.19.0"
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install --frozen-lockfile
|
run: bun install --frozen-lockfile
|
||||||
- name: Lint TypeScript
|
- name: Lint TypeScript
|
||||||
run: npm run lint:tsc
|
run: bun lint:tsc
|
||||||
|
- name: Lint Biome
|
||||||
|
run: bun lint:biome
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
@@ -1,3 +1,7 @@
|
|||||||
{
|
{
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.biome": "explicit"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM oven/bun:1.2.22 AS bun
|
FROM oven/bun:1.3.1@sha256:9c5d3c92b234b4708198577d2f39aab7397a242a40da7c2f059e51b9dc62b408 AS bun
|
||||||
FROM node:22.19.0-trixie-slim
|
FROM node:22.21.0-trixie-slim@sha256:569753d685702eec9855b1bf2fdcc003e8ee47f1915f9a4e4e38fc6a880c7612
|
||||||
COPY --from=bun /usr/local/bin/bun \
|
COPY --from=bun /usr/local/bin/bun \
|
||||||
/usr/local/bin/bunx \
|
/usr/local/bin/bunx \
|
||||||
/usr/local/bin/
|
/usr/local/bin/
|
||||||
@@ -7,9 +7,8 @@ WORKDIR /app
|
|||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
RUN bun install --frozen-lockfile && \
|
RUN bun install --frozen-lockfile && \
|
||||||
bun lint:tsc && \
|
bun lint:tsc && \
|
||||||
bun --cwd=./packages/server bun:build && \
|
bun lint:biome && \
|
||||||
bun --cwd=./packages/server node:build && \
|
bun run build && \
|
||||||
bun --cwd=./packages/webapp run build && \
|
|
||||||
bun clean:cache && \
|
bun clean:cache && \
|
||||||
bun clean:modules && \
|
bun clean:modules && \
|
||||||
bun install --frozen-lockfile --production
|
bun install --frozen-lockfile --production
|
||||||
|
|||||||
36
biome.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
|
||||||
|
"vcs": {
|
||||||
|
"enabled": false,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": false
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"nursery": {
|
||||||
|
"useSortedClasses": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assist": {
|
||||||
|
"enabled": true,
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
compose.yml
@@ -11,18 +11,18 @@ x-env-base: &env-base
|
|||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
<<: *service-base
|
<<: *service-base
|
||||||
image: oven/bun:1.2.22
|
image: oven/bun:1.3.1@sha256:9c5d3c92b234b4708198577d2f39aab7397a242a40da7c2f059e51b9dc62b408
|
||||||
volumes:
|
volumes:
|
||||||
- *volume-app
|
- *volume-app
|
||||||
working_dir: /app/packages/server
|
working_dir: /app/packages/server
|
||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
<<: *env-base
|
<<: *env-base
|
||||||
entrypoint: ["bun", "bun:dev"]
|
entrypoint: ["bun", "dev:bun"]
|
||||||
|
|
||||||
cli:
|
cli:
|
||||||
<<: *service-base
|
<<: *service-base
|
||||||
image: oven/bun:1.2.22
|
image: oven/bun:1.3.1@sha256:9c5d3c92b234b4708198577d2f39aab7397a242a40da7c2f059e51b9dc62b408
|
||||||
volumes:
|
volumes:
|
||||||
- *volume-app
|
- *volume-app
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
@@ -35,7 +35,7 @@ services:
|
|||||||
|
|
||||||
webapp:
|
webapp:
|
||||||
<<: *service-base
|
<<: *service-base
|
||||||
image: node:22.19.0
|
image: node:22.21.0@sha256:23c24e85395992be118734a39903e08c8f7d1abc73978c46b6bda90060091a49
|
||||||
ports:
|
ports:
|
||||||
- ${PORT:?PORT missing}:80
|
- ${PORT:?PORT missing}:80
|
||||||
volumes:
|
volumes:
|
||||||
@@ -48,7 +48,7 @@ services:
|
|||||||
|
|
||||||
tempo:
|
tempo:
|
||||||
<<: *service-base
|
<<: *service-base
|
||||||
image: grafana/tempo:main-8d7feda
|
image: grafana/tempo:latest@sha256:bbb7c84ba5b9d03203aa7f35c038ea2e770336e041dc0eecb0798d4d7fcac15b
|
||||||
command: [-config.file=/etc/tempo.yaml]
|
command: [-config.file=/etc/tempo.yaml]
|
||||||
volumes:
|
volumes:
|
||||||
- ./telemetry/tempo.yaml:/etc/tempo.yaml
|
- ./telemetry/tempo.yaml:/etc/tempo.yaml
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
stop_signal: SIGKILL
|
stop_signal: SIGKILL
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
image: prom/prometheus:v3.5.0
|
image: prom/prometheus:v3.7.2@sha256:23031bfe0e74a13004252caaa74eccd0d62b6c6e7a04711d5b8bf5b7e113adc7
|
||||||
command:
|
command:
|
||||||
- --config.file=/etc/prometheus.yaml
|
- --config.file=/etc/prometheus.yaml
|
||||||
- --web.enable-remote-write-receiver
|
- --web.enable-remote-write-receiver
|
||||||
@@ -65,7 +65,7 @@ services:
|
|||||||
- ./telemetry/prometheus.yaml:/etc/prometheus.yaml
|
- ./telemetry/prometheus.yaml:/etc/prometheus.yaml
|
||||||
|
|
||||||
grafana:
|
grafana:
|
||||||
image: grafana/grafana:12.3.0-17782621999
|
image: grafana/grafana:latest@sha256:aa42cb1d973fc3d10609cd579455470f7255c535c9d3c3059c390c583709c14a
|
||||||
volumes:
|
volumes:
|
||||||
- ./telemetry/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
|
- ./telemetry/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -5,14 +5,17 @@
|
|||||||
"workspaces": ["./packages/*"],
|
"workspaces": ["./packages/*"],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:tsc": "turbo lint:tsc",
|
"lint:tsc": "turbo lint:tsc",
|
||||||
|
"lint:biome": "turbo lint:biome",
|
||||||
|
"build": "turbo build",
|
||||||
"clean:cache": "rm -rf .turbo",
|
"clean:cache": "rm -rf .turbo",
|
||||||
"clean:dist": "turbo clean:dist && rm -rf dist",
|
"clean:dist": "turbo clean:dist && rm -rf dist",
|
||||||
"clean:modules": "turbo clean:modules && rm -rf node_modules"
|
"clean:modules": "turbo clean:modules && rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@effect/language-service": "^0.40.0",
|
"@biomejs/biome": "^2.2.4",
|
||||||
"@types/bun": "latest",
|
"@effect/language-service": "^0.48.0",
|
||||||
"npm-check-updates": "^18.1.1",
|
"@types/bun": "^1.2.23",
|
||||||
|
"npm-check-updates": "^19.0.0",
|
||||||
"npm-sort": "^0.0.4",
|
"npm-sort": "^0.0.4",
|
||||||
"turbo": "^2.5.6",
|
"turbo": "^2.5.6",
|
||||||
"typescript": "^5.9.2"
|
"typescript": "^5.9.2"
|
||||||
|
|||||||
8
packages/common/biome.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
|
||||||
|
"root": false,
|
||||||
|
"extends": "//",
|
||||||
|
"files": {
|
||||||
|
"includes": ["./src/**"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,10 +10,11 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:tsc": "tsc --noEmit",
|
"lint:tsc": "tsc --noEmit",
|
||||||
|
"lint:biome": "biome lint",
|
||||||
"clean:modules": "rm -rf node_modules"
|
"clean:modules": "rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/rpc": "^0.69.2",
|
"@effect/rpc": "^0.71.0",
|
||||||
"effect": "^3.17.13"
|
"effect": "^3.17.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
packages/server/biome.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
|
||||||
|
"root": false,
|
||||||
|
"extends": "//",
|
||||||
|
"files": {
|
||||||
|
"includes": ["./src/**"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,22 +5,22 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:tsc": "tsc --noEmit",
|
"lint:tsc": "tsc --noEmit",
|
||||||
"bun:dev": "NODE_ENV=development bun --hot ./src/entrypoint.bun.ts",
|
"lint:biome": "biome lint",
|
||||||
"bun:build": "esbuild ./src/entrypoint.bun.ts --outdir=./dist --bundle --minify --format=esm --sourcemap --platform=node",
|
"build": "rollup -c",
|
||||||
"bun:start": "NODE_ENV=production bun ./dist/entrypoint.bun.js",
|
"dev:bun": "NODE_ENV=development bun --watch ./src/entrypoint.bun.ts",
|
||||||
"node:dev": "NODE_ENV=development tsx --watch ./src/entrypoint.node.ts",
|
"dev:node": "NODE_ENV=development tsx --watch ./src/entrypoint.node.ts",
|
||||||
"node:build": "esbuild ./src/entrypoint.node.ts --outdir=./dist --bundle --minify --format=esm --sourcemap --platform=node",
|
"start:bun": "NODE_ENV=production bun ./dist/entrypoint.bun.js",
|
||||||
"node:start": "NODE_ENV=production node --enable-source-maps ./dist/entrypoint.node.js",
|
"start:node": "NODE_ENV=production node --enable-source-maps ./dist/entrypoint.node.js",
|
||||||
"clean:dist": "rm -rf dist",
|
"clean:dist": "rm -rf dist",
|
||||||
"clean:modules": "rm -rf node_modules"
|
"clean:modules": "rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/opentelemetry": "^0.56.6",
|
"@effect/opentelemetry": "^0.58.0",
|
||||||
"@effect/platform": "^0.90.9",
|
"@effect/platform": "^0.92.0",
|
||||||
"@effect/platform-bun": "^0.79.0",
|
"@effect/platform-bun": "^0.81.0",
|
||||||
"@effect/platform-node": "^0.96.1",
|
"@effect/platform-node": "^0.98.0",
|
||||||
"@effect/rpc": "^0.69.2",
|
"@effect/rpc": "^0.71.0",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.205.0",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.207.0",
|
||||||
"@opentelemetry/sdk-metrics": "^2.1.0",
|
"@opentelemetry/sdk-metrics": "^2.1.0",
|
||||||
"@opentelemetry/sdk-trace-base": "^2.1.0",
|
"@opentelemetry/sdk-trace-base": "^2.1.0",
|
||||||
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
||||||
@@ -29,7 +29,10 @@
|
|||||||
"effect": "^3.17.13"
|
"effect": "^3.17.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||||
"esbuild": "^0.25.9",
|
"esbuild": "^0.25.9",
|
||||||
|
"rollup": "^4.52.0",
|
||||||
|
"rollup-plugin-esbuild": "^6.2.1",
|
||||||
"tsx": "^4.20.5"
|
"tsx": "^4.20.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
packages/server/rollup.config.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { nodeResolve } from "@rollup/plugin-node-resolve"
|
||||||
|
import path from "node:path"
|
||||||
|
import url from "node:url"
|
||||||
|
import { defineConfig } from "rollup"
|
||||||
|
import esbuild from "rollup-plugin-esbuild"
|
||||||
|
|
||||||
|
|
||||||
|
const __relativeDirname = path.relative(".", url.fileURLToPath(new URL(".", import.meta.url)))
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
input: {
|
||||||
|
"entrypoint.bun": path.join(__relativeDirname, "src", "entrypoint.bun.ts"),
|
||||||
|
"entrypoint.node": path.join(__relativeDirname, "src", "entrypoint.node.ts"),
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
dir: path.join(__relativeDirname, "dist"),
|
||||||
|
format: "es",
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
external: id => !/^[./]/.test(id) && !/^@website\//.test(id),
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
nodeResolve(),
|
||||||
|
esbuild({ minify: true }),
|
||||||
|
],
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { createServer } from "node:http"
|
||||||
import { NodeContext, NodeHttpServer, NodeRuntime } from "@effect/platform-node"
|
import { NodeContext, NodeHttpServer, NodeRuntime } from "@effect/platform-node"
|
||||||
import { Effect, Layer } from "effect"
|
import { Effect, Layer } from "effect"
|
||||||
import { createServer } from "node:http"
|
|
||||||
import { ServerConfig } from "./config"
|
import { ServerConfig } from "./config"
|
||||||
import { Server } from "./server"
|
import { Server } from "./server"
|
||||||
|
|
||||||
|
|||||||
@@ -16,51 +16,41 @@ const makeWebRpcRoute = Effect.all([
|
|||||||
Effect.provide(WebRpcLive),
|
Effect.provide(WebRpcLive),
|
||||||
)
|
)
|
||||||
|
|
||||||
const makeProductionWebappMiddleware = Effect.gen(function*() {
|
const makeProductionWebappRoute = Effect.fnUntraced(function*(route: HttpRouter.PathInput) {
|
||||||
const path = yield* Path.Path
|
const path = yield* Path.Path
|
||||||
const fs = yield* FileSystem.FileSystem
|
const fs = yield* FileSystem.FileSystem
|
||||||
const dist = path.join(yield* path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), "dist")
|
const dist = path.join(yield* path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), "dist")
|
||||||
|
|
||||||
return () => Effect.gen(function*() {
|
return HttpRouter.all(route, Effect.gen(function*() {
|
||||||
const req = yield* HttpServerRequest.HttpServerRequest
|
const req = yield* HttpServerRequest.HttpServerRequest
|
||||||
const source = path.join(dist, req.url)
|
const source = path.join(dist, req.url)
|
||||||
const isValid = yield* fs.stat(source).pipe(
|
const exists = yield* fs.stat(source).pipe(
|
||||||
Effect.andThen(stat => stat.type === "File"),
|
Effect.andThen(stat => stat.type === "File"),
|
||||||
Effect.catchAll(() => Effect.succeed(false)),
|
Effect.catchAll(() => Effect.succeed(false)),
|
||||||
)
|
)
|
||||||
|
|
||||||
return yield* HttpServerResponse.setHeader(
|
return yield* HttpServerResponse.setHeader(
|
||||||
yield* HttpServerResponse.file(isValid ? source : path.join(dist, "index.html")),
|
yield* HttpServerResponse.file(exists ? source : path.join(dist, "index.html")),
|
||||||
"Cache-Control",
|
"Cache-Control",
|
||||||
`public, max-age=${Duration.toSeconds("365 days")}, immutable`
|
`public, max-age=${Duration.toSeconds("365 days")}, immutable`
|
||||||
)
|
)
|
||||||
})
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export const HttpAppDevelopment = Effect.provide(makeWebRpcRoute, WebRpcSerializationDevelopment).pipe(
|
export const HttpAppDevelopment = Layer.unwrapScoped(Effect.gen(function*() {
|
||||||
Effect.map(serveWebRpc => router.pipe(
|
return router.pipe(
|
||||||
serveWebRpc,
|
yield* Effect.provide(makeWebRpcRoute, WebRpcSerializationDevelopment),
|
||||||
HttpServer.serve(flow(
|
HttpServer.serve(flow(HttpMiddleware.logger, HttpMiddleware.xForwardedHeaders)),
|
||||||
HttpMiddleware.logger,
|
|
||||||
HttpMiddleware.xForwardedHeaders,
|
|
||||||
)),
|
|
||||||
HttpServer.withLogAddress,
|
HttpServer.withLogAddress,
|
||||||
)),
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
Layer.unwrapScoped,
|
export const HttpAppProduction = Layer.unwrapScoped(Effect.gen(function*() {
|
||||||
)
|
return router.pipe(
|
||||||
|
yield* Effect.provide(makeWebRpcRoute, WebRpcSerializationProduction),
|
||||||
export const HttpAppProduction = Effect.all([
|
yield* makeProductionWebappRoute("*"),
|
||||||
Effect.provide(makeWebRpcRoute, WebRpcSerializationProduction),
|
|
||||||
makeProductionWebappMiddleware,
|
|
||||||
]).pipe(
|
|
||||||
Effect.map(([serveWebRpc, serveProductionWebapp]) => router.pipe(
|
|
||||||
serveWebRpc,
|
|
||||||
serveProductionWebapp,
|
|
||||||
HttpServer.serve(HttpMiddleware.xForwardedHeaders),
|
HttpServer.serve(HttpMiddleware.xForwardedHeaders),
|
||||||
HttpServer.withLogAddress,
|
HttpServer.withLogAddress,
|
||||||
)),
|
)
|
||||||
|
}))
|
||||||
Layer.unwrapScoped,
|
|
||||||
)
|
|
||||||
|
|||||||
2
packages/webapp/.gitignore
vendored
@@ -22,3 +22,5 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
.tanstack
|
||||||
|
|||||||
8
packages/webapp/biome.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
|
||||||
|
"root": false,
|
||||||
|
"extends": "//",
|
||||||
|
"files": {
|
||||||
|
"includes": ["./src/**", "!src/routeTree.gen.ts"]
|
||||||
|
}
|
||||||
|
}
|
||||||
22
packages/webapp/components.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "new-york",
|
||||||
|
"rsc": false,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "",
|
||||||
|
"css": "src/index.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide",
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
},
|
||||||
|
"registries": {}
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import js from '@eslint/js'
|
|
||||||
import globals from 'globals'
|
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
|
||||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
||||||
import tseslint from 'typescript-eslint'
|
|
||||||
import { globalIgnores } from 'eslint/config'
|
|
||||||
|
|
||||||
export default tseslint.config([
|
|
||||||
globalIgnores(['dist']),
|
|
||||||
{
|
|
||||||
files: ['**/*.{ts,tsx}'],
|
|
||||||
extends: [
|
|
||||||
js.configs.recommended,
|
|
||||||
tseslint.configs.recommended,
|
|
||||||
reactHooks.configs['recommended-latest'],
|
|
||||||
reactRefresh.configs.vite,
|
|
||||||
],
|
|
||||||
languageOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
globals: globals.browser,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
@@ -7,31 +7,45 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
|
||||||
"lint:tsc": "tsc --noEmit",
|
"lint:tsc": "tsc --noEmit",
|
||||||
|
"lint:biome": "biome lint",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"clean:dist": "rm -rf dist",
|
"clean:dist": "rm -rf dist",
|
||||||
"clean:modules": "rm -rf node_modules"
|
"clean:modules": "rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform": "^0.90.9",
|
"@effect/platform": "^0.92.0",
|
||||||
"@effect/platform-browser": "^0.70.0",
|
"@effect/platform-browser": "^0.72.0",
|
||||||
"@effect/rpc": "^0.69.2",
|
"@effect/rpc": "^0.71.0",
|
||||||
|
"@fontsource/work-sans": "^5.2.8",
|
||||||
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
|
"@tanstack/react-router": "^1.131.48",
|
||||||
"@website/common": "workspace:*",
|
"@website/common": "workspace:*",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"effect": "^3.17.13",
|
"effect": "^3.17.13",
|
||||||
"effect-fc": "^0.1.3",
|
"effect-fc": "^0.2.0",
|
||||||
|
"i18next": "^25.6.0",
|
||||||
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
|
"lucide-react": "^0.548.0",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1"
|
"react-dom": "^19.1.1",
|
||||||
|
"react-i18next": "^16.0.1",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
|
"react-shadow": "^20.6.0",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
|
"tailwindcss": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.35.0",
|
"@tailwindcss/vite": "^4.1.13",
|
||||||
|
"@tanstack/react-router-devtools": "^1.131.48",
|
||||||
|
"@tanstack/router-plugin": "^1.131.48",
|
||||||
"@types/react": "^19.1.13",
|
"@types/react": "^19.1.13",
|
||||||
"@types/react-dom": "^19.1.9",
|
"@types/react-dom": "^19.1.9",
|
||||||
"@vitejs/plugin-react": "^5.0.2",
|
"@vitejs/plugin-react": "^5.0.2",
|
||||||
"eslint": "^9.35.0",
|
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
|
||||||
"globals": "^16.4.0",
|
"globals": "^16.4.0",
|
||||||
|
"tw-animate-css": "^1.3.8",
|
||||||
"typescript-eslint": "^8.44.0",
|
"typescript-eslint": "^8.44.0",
|
||||||
"vite": "^7.1.5"
|
"vite": "^7.1.5"
|
||||||
}
|
}
|
||||||
|
|||||||
18
packages/webapp/public/98.css/.editorconfig
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 80
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = 0
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[COMMIT_EDITMSG]
|
||||||
|
max_line_length = 0
|
||||||
23
packages/webapp/public/98.css/.github/workflows/npm-publish.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
||||||
|
|
||||||
|
name: Publish to NPM
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-npm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
registry-url: https://registry.npmjs.org/
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run release
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||||
7
packages/webapp/public/98.css/LICENSE
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright 2020 Jordan Scales
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
76
packages/webapp/public/98.css/README.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
## 98.css
|
||||||
|
|
||||||
|
[](http://npm.im/98.css)
|
||||||
|
[](https://unpkg.com/98.css)
|
||||||
|
|
||||||
|
A design system for building faithful recreations of old UIs.
|
||||||
|
|
||||||
|
<img alt="a screenshot of a window with the title 'My First VB4 Program' and two buttons OK and Cancel, styled like a Windows 98 dialog" src="https://github.com/jdan/98.css/blob/main/docs/window.png?raw=true" height="133"> <img alt="a magnified view showing pixel-perfect borders on a scrollbar and button element" src="https://github.com/jdan/98.css/blob/main/docs/zoom.png?raw=true?raw=true" height="133">
|
||||||
|
|
||||||
|
98.css is a CSS file that takes semantic HTML and makes it look pretty. It does not ship with any JavaScript, so it is compatible with your frontend framework of choice.
|
||||||
|
|
||||||
|
Be sure to check out [XP.css](https://botoxparty.github.io/XP.css/) and [7.css](https://khang-nd.github.io/7.css/) as well.
|
||||||
|
|
||||||
|
### Installation / Usage
|
||||||
|
|
||||||
|
The easiest way to use 98.css is to import it from [unpkg](https://unpkg.com/).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>98.css example</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/98.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="window" style="margin: 32px; width: 250px">
|
||||||
|
<div class="title-bar">
|
||||||
|
<div class="title-bar-text">
|
||||||
|
My First VB4 Program
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="window-body">
|
||||||
|
<p>Hello, world!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can grab 98.css for [the releases page](https://github.com/jdan/98.css/releases) or [npm](https://www.npmjs.com/package/98.css).
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install 98.css
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example of [98.css being used with React](https://codesandbox.io/s/objective-chandrasekhar-t5t6h?file=/src/index.js), and [an example with vanilla JavaScript](https://codesandbox.io/s/late-sound-miqho?file=/index.html).
|
||||||
|
|
||||||
|
Refer to the [documentation page](https://jdan.github.io/98.css/) for specific instructions on this library's components.
|
||||||
|
|
||||||
|
### Developing
|
||||||
|
|
||||||
|
First, run `npm install`.
|
||||||
|
|
||||||
|
[`style.css`](https://github.com/jdan/98.css/blob/main/style.css) is where everything happens.
|
||||||
|
|
||||||
|
You can use `npm start` to start a development environment that will watch for file changes and rebuild 98.css, reloading your browser in the process.
|
||||||
|
|
||||||
|
You can run a build manually with `npm run build`. This will write to the `dist/` directory.
|
||||||
|
|
||||||
|
### Issues, Contributing, etc.
|
||||||
|
|
||||||
|
Refer to [the GitHub issues page](https://github.com/jdan/98.css/issues) to see bugs in my CSS or report new ones. I'd really like to see your pull requests (especially those new to open-source!) and will happily provide code review. 98.css is a fun, silly project and I'd like to make it a fun place to build your open-source muscle.
|
||||||
|
|
||||||
|
Thank you for checking my little project out, I hope it brought you some joy today. Consider [starring/following along on GitHub](https://github.com/jdan/98.css/stargazers) and maybe subscribing to more fun things on [my twitter](https://twitter.com/jdan). 👋
|
||||||
|
|
||||||
|
### Publishing
|
||||||
|
|
||||||
|
Building the docs site: `npm run deploy:docs`
|
||||||
|
|
||||||
|
Publishing to npm: `npm run release`
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
[MIT](https://github.com/jdan/98.css/blob/main/LICENSE)
|
||||||
81
packages/webapp/public/98.css/build.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const dedent = require("dedent");
|
||||||
|
const ejs = require("ejs");
|
||||||
|
const fs = require("fs");
|
||||||
|
const glob = require("glob");
|
||||||
|
const hljs = require("highlight.js");
|
||||||
|
const mkdirp = require("mkdirp");
|
||||||
|
const path = require("path");
|
||||||
|
const postcss = require("postcss");
|
||||||
|
|
||||||
|
const { homepage, version } = require("./package.json");
|
||||||
|
|
||||||
|
function buildCSS() {
|
||||||
|
const input =
|
||||||
|
`/*! 98.css v${version} - ${homepage} */\n` + fs.readFileSync("style.css");
|
||||||
|
|
||||||
|
return postcss()
|
||||||
|
.use(require("postcss-inline-svg"))
|
||||||
|
.use(require("postcss-css-variables"))
|
||||||
|
.use(require("postcss-calc"))
|
||||||
|
.use(require("postcss-copy")({ dest: "dist", template: "[name].[ext]" }))
|
||||||
|
.use(require("cssnano"))
|
||||||
|
.process(input, {
|
||||||
|
from: "style.css",
|
||||||
|
to: "dist/98.css",
|
||||||
|
map: { inline: false },
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
mkdirp.sync("dist");
|
||||||
|
fs.writeFileSync("dist/98.css", result.css);
|
||||||
|
fs.writeFileSync("dist/98.css.map", result.map.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDocs() {
|
||||||
|
let id = 0;
|
||||||
|
function getNewId() {
|
||||||
|
return ++id;
|
||||||
|
}
|
||||||
|
function getCurrentId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = fs.readFileSync("docs/index.html.ejs", "utf-8");
|
||||||
|
function example(code) {
|
||||||
|
const magicBrackets = /\[\[(.*)\]\]/g;
|
||||||
|
const dedented = dedent(code);
|
||||||
|
const inline = dedented.replace(magicBrackets, "$1");
|
||||||
|
const escaped = hljs.highlight("html", dedented.replace(magicBrackets, ""))
|
||||||
|
.value;
|
||||||
|
|
||||||
|
return `<div class="example">
|
||||||
|
${inline}
|
||||||
|
<details>
|
||||||
|
<summary>Show code</summary>
|
||||||
|
<pre><code>${escaped}</code></pre>
|
||||||
|
</details>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
glob("docs/*", (err, files) => {
|
||||||
|
if (!err) {
|
||||||
|
files.forEach((srcFile) =>
|
||||||
|
fs.copyFileSync(srcFile, path.join("dist", path.basename(srcFile)))
|
||||||
|
);
|
||||||
|
} else throw "error globbing dist directory.";
|
||||||
|
});
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(__dirname, "/dist/index.html"),
|
||||||
|
ejs.render(template, { getNewId, getCurrentId, example })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
buildCSS()
|
||||||
|
.then(buildDocs)
|
||||||
|
.catch((err) => console.log(err));
|
||||||
|
}
|
||||||
|
module.exports = build;
|
||||||
|
|
||||||
|
build();
|
||||||
152
packages/webapp/public/98.css/docs/docs.css
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: #c0c0c0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: 65rem;
|
||||||
|
margin-left: 240px;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
width: 200px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside .tree-view {
|
||||||
|
width: 100%;
|
||||||
|
/* TODO: Move scrollbar into the recessed region? */
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
width: 400px;
|
||||||
|
height: 1px;
|
||||||
|
opacity: 0.5;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
red 20%,
|
||||||
|
yellow 20%,
|
||||||
|
yellow 36%,
|
||||||
|
green 36%,
|
||||||
|
green 60%,
|
||||||
|
blue 60%,
|
||||||
|
blue 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
/* Swap the margin for a top-padding so linking to this section
|
||||||
|
results in a better scroll position */
|
||||||
|
padding-top: 20px;
|
||||||
|
margin-top: 0;
|
||||||
|
display: block;
|
||||||
|
flex: 0 0 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
max-width: 50rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
padding: 20px;
|
||||||
|
background: #dfdfdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote footer {
|
||||||
|
margin: 12px 0 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example {
|
||||||
|
margin: 16px 0;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-left: 1px solid #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
details {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
details[open] summary {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.focused {
|
||||||
|
outline: 1px dotted #000000;
|
||||||
|
outline-offset: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.active {
|
||||||
|
box-shadow: inset -1px -1px #ffffff, inset 1px 1px #0a0a0a,
|
||||||
|
inset -2px -2px #dfdfdf, inset 2px 2px #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
aside {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component {
|
||||||
|
display: block;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
packages/webapp/public/98.css/docs/icon.png
Normal file
|
After Width: | Height: | Size: 209 B |
1129
packages/webapp/public/98.css/docs/index.html.ejs
Normal file
67
packages/webapp/public/98.css/docs/vs.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>
|
||||||
|
|
||||||
|
*/
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote,
|
||||||
|
.hljs-variable {
|
||||||
|
color: #008000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-tag {
|
||||||
|
color: #00f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-template-tag,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-addition {
|
||||||
|
color: #a31515;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #2b91af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-doctag {
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr {
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-link {
|
||||||
|
color: #00b0e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
BIN
packages/webapp/public/98.css/docs/window.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
packages/webapp/public/98.css/docs/zoom.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
packages/webapp/public/98.css/fonts/converted/ms_sans_serif.woff
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
The FontStruction “MS Sans Serif Bold”
|
||||||
|
(https://fontstruct.com/fontstructions/show/1384862) by “lou” is licensed
|
||||||
|
under a Creative Commons Attribution Share Alike license
|
||||||
|
(http://creativecommons.org/licenses/by-sa/3.0/).
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
The font file in this archive was created using Fontstruct the free, online
|
||||||
|
font-building tool.
|
||||||
|
This font was created by “lou”.
|
||||||
|
This font has a homepage where this archive and other versions may be found:
|
||||||
|
https://fontstruct.com/fontstructions/show/1384862
|
||||||
|
|
||||||
|
Try Fontstruct at http://fontstruct.com
|
||||||
|
It’s easy and it’s fun.
|
||||||
|
|
||||||
|
NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash.
|
||||||
|
If the font in this archive is a pixel font, it is best displayed at a font-size
|
||||||
|
of 11.
|
||||||
|
|
||||||
|
Fontstruct is sponsored by FontShop.
|
||||||
|
Visit them at https://fontshop.com
|
||||||
|
FontShop is the original independent font retailer. We’ve been around since
|
||||||
|
the dawn of digital type. Whether you need the right font or need to create the
|
||||||
|
right font from scratch, let our 26 years of experience work for you.
|
||||||
|
|
||||||
|
Fontstruct is copyright ©2017 Rob Meek
|
||||||
|
|
||||||
|
LEGAL NOTICE:
|
||||||
|
In using this font you must comply with the licensing terms described in the
|
||||||
|
file “license.txt” included with this archive.
|
||||||
|
If you redistribute the font file in this archive, it must be accompanied by all
|
||||||
|
the other files from this archive, including this one.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
The FontStruction “MS Sans Serif”
|
||||||
|
(https://fontstruct.com/fontstructions/show/1384746) by “lou” is licensed
|
||||||
|
under a Creative Commons Attribution Share Alike license
|
||||||
|
(http://creativecommons.org/licenses/by-sa/3.0/).
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
The font file in this archive was created using Fontstruct the free, online
|
||||||
|
font-building tool.
|
||||||
|
This font was created by “lou”.
|
||||||
|
This font has a homepage where this archive and other versions may be found:
|
||||||
|
https://fontstruct.com/fontstructions/show/1384746
|
||||||
|
|
||||||
|
Try Fontstruct at http://fontstruct.com
|
||||||
|
It’s easy and it’s fun.
|
||||||
|
|
||||||
|
NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash.
|
||||||
|
If the font in this archive is a pixel font, it is best displayed at a font-size
|
||||||
|
of 11.
|
||||||
|
|
||||||
|
Fontstruct is sponsored by FontShop.
|
||||||
|
Visit them at https://fontshop.com
|
||||||
|
FontShop is the original independent font retailer. We’ve been around since
|
||||||
|
the dawn of digital type. Whether you need the right font or need to create the
|
||||||
|
right font from scratch, let our 26 years of experience work for you.
|
||||||
|
|
||||||
|
Fontstruct is copyright ©2017 Rob Meek
|
||||||
|
|
||||||
|
LEGAL NOTICE:
|
||||||
|
In using this font you must comply with the licensing terms described in the
|
||||||
|
file “license.txt” included with this archive.
|
||||||
|
If you redistribute the font file in this archive, it must be accompanied by all
|
||||||
|
the other files from this archive, including this one.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H15H16V17H15H0V16V1V0ZM1 16H15V1H1V16Z" fill="#808080"/>
|
||||||
|
<rect x="1" y="1" width="14" height="15" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 7H5V8H6V9H7V10H8V11H9V10H10V9H11V8H12V7Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 381 B |
8
packages/webapp/public/98.css/icon/button-down.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 0H0V1V16H1V1H15V0Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1H1V15H2V2H14V1H2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 17H15H0V16H15V0H16V17Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 1H14V15H1V16H14H15V1Z" fill="#808080"/>
|
||||||
|
<rect x="2" y="2" width="12" height="13" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 6H4V7H5V8H6V9H7V10H8V9H9V8H10V7H11V6Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 630 B |
8
packages/webapp/public/98.css/icon/button-left.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 0H0V1V16H1V1H15V0Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1H1V15H2V2H14V1H2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 17H15H0V16H15V0H16V17Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 1H14V15H1V16H14H15V1Z" fill="#808080"/>
|
||||||
|
<rect x="2" y="2" width="12" height="13" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 4H8V5H7V6H6V7H5V8H6V9H7V10H8V11H9V4Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 628 B |
8
packages/webapp/public/98.css/icon/button-right.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 0H0V1V16H1V1H15V0Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1H1V15H2V2H14V1H2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 17H15H0V16H15V0H16V17Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 1H14V15H1V16H14H15V1Z" fill="#808080"/>
|
||||||
|
<rect x="2" y="2" width="12" height="13" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 4H6V11H7V10H8V9H9V8H10V7H9V6H8V5H7V4Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 629 B |
8
packages/webapp/public/98.css/icon/button-up.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 0H0V1V16H1V1H15V0Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1H1V15H2V2H14V1H2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 17H15H0V16H15V0H16V17Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 1H14V15H1V16H14H15V1Z" fill="#808080"/>
|
||||||
|
<rect x="2" y="2" width="12" height="13" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 6H7V7H6V8H5V9H4V10H11V9H10V8H9V7H8V6Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="7" height="7" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z" fill="#808080"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 228 B |
3
packages/webapp/public/98.css/icon/checkmark.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="7" height="7" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 226 B |
3
packages/webapp/public/98.css/icon/close.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="8" height="7" viewBox="0 0 8 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H1H2V1H3V2H4H5V1H6V0H7H8V1H7V2H6V3H5V4H6V5H7V6H8V7H7H6V6H5V5H4H3V6H2V7H1H0V6H1V5H2V4H3V3H2V2H1V1H0V0Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 270 B |
4
packages/webapp/public/98.css/icon/groupbox-border.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="5" height="5" viewBox="0 0 5 5" fill="grey" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H5V5H0V2H2V3H3V2H0" fill="white" />
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H4V4H0V1H1V3H3V1H0" fill="#808080" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 279 B |
8
packages/webapp/public/98.css/icon/help.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="6" height="9" viewBox="0 0 6 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect y="1" width="2" height="2" fill="black"/>
|
||||||
|
<rect x="1" width="4" height="1" fill="black"/>
|
||||||
|
<rect x="4" y="1" width="2" height="2" fill="black"/>
|
||||||
|
<rect x="3" y="3" width="2" height="1" fill="black"/>
|
||||||
|
<rect x="2" y="4" width="2" height="2" fill="black"/>
|
||||||
|
<rect x="2" y="7" width="2" height="2" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 411 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="11" height="21" viewBox="0 0 11 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0V16H2V18H4V20H5V19H3V17H1V1H10V0Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1V16H2V17H3V18H4V19H6V18H7V17H8V16H9V1Z" fill="#C0C7C8"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 1H10V16H8V18H6V20H5V19H7V17H9Z" fill="#87888F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 0H11V16H9V18H7V20H5V21H6V19H8V17H10Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 523 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="11" height="21" viewBox="0 0 11 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0V20H1V1H10V0Z" fill="white"/>
|
||||||
|
<rect x="1" y="1" width="8" height="18" fill="#C0C7C8"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 1H10V20H1V19H9Z" fill="#87888F"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 0H11V21H0V20H10Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 415 B |
4
packages/webapp/public/98.css/icon/maximize-disabled.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 1H1V3V9V10H2H9H10V9V3V1ZM9 3H2V9H9V3Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 0H0V2V8V9H1H8H9V8V2V0ZM8 2H1V8H8V2Z" fill="#808080"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 319 B |
3
packages/webapp/public/98.css/icon/maximize.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 0H0V2V8V9H1H8H9V8V2V0ZM8 2H1V8H8V2Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 203 B |
3
packages/webapp/public/98.css/icon/minimize.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="6" height="2" viewBox="0 0 6 2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="6" height="2" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 141 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z" fill="#808080"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z" fill="#C0C0C0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 744 B |
8
packages/webapp/public/98.css/icon/radio-border.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z" fill="#808080"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z" fill="#DFDFDF"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z" fill="white"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 743 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="4" height="4" viewBox="0 0 4 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z" fill="#808080"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 200 B |
3
packages/webapp/public/98.css/icon/radio-dot.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="4" height="4" viewBox="0 0 4 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 198 B |
10
packages/webapp/public/98.css/icon/restore.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="8" height="9" viewBox="0 0 8 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="2" width="6" height="2" fill="black"/>
|
||||||
|
<rect x="7" y="2" width="1" height="4" fill="black"/>
|
||||||
|
<rect x="2" y="2" width="1" height="1" fill="black"/>
|
||||||
|
<rect x="6" y="5" width="1" height="1" fill="black"/>
|
||||||
|
<rect y="3" width="6" height="2" fill="black"/>
|
||||||
|
<rect x="5" y="5" width="1" height="4" fill="black"/>
|
||||||
|
<rect y="5" width="1" height="4" fill="black"/>
|
||||||
|
<rect x="1" y="8" width="4" height="1" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 513 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="2" height="2" viewBox="0 0 2 2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0H0V1H1V2H2V1H1V0Z" fill="#C0C0C0"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 0H1V1H0V2H1V1H2V0Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 275 B |
10
packages/webapp/public/98.css/icon/sunken-panel-border.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg width="5" height="5" viewBox="0 0 5 5" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="4" height="1" x="0" y="0" fill="#808080"/>
|
||||||
|
<rect width="1" height="4" x="0" y="0" fill="#808080"/>
|
||||||
|
<rect width="2" height="1" x="1" y="1" fill="#0a0a0a"/>
|
||||||
|
<rect width="1" height="2" x="1" y="1" fill="#0a0a0a"/>
|
||||||
|
<rect width="5" height="1" x="0" y="4" fill="#fff"/>
|
||||||
|
<rect width="1" height="5" x="4" y="0" fill="#fff"/>
|
||||||
|
<rect width="1" height="3" x="3" y="1" fill="#dfdfdf"/>
|
||||||
|
<rect width="3" height="1" x="1" y="3" fill="#dfdfdf"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 545 B |
4
packages/webapp/public/98.css/now.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"public": true
|
||||||
|
}
|
||||||
45
packages/webapp/public/98.css/package.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "98.css",
|
||||||
|
"version": "0.1.21",
|
||||||
|
"description": "A design system for building faithful recreations of old UIs",
|
||||||
|
"main": "dist/98.css",
|
||||||
|
"directories": {
|
||||||
|
"doc": "docs"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "node build.js",
|
||||||
|
"deploy:docs": "npm run build && gh-pages -d dist",
|
||||||
|
"release": "npm run build && npm publish"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jdan/98.css.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"windows98"
|
||||||
|
],
|
||||||
|
"author": "Jordan Scales <scalesjordan@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jdan/98.css/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/jdan/98.css",
|
||||||
|
"devDependencies": {
|
||||||
|
"chokidar": "^3.3.1",
|
||||||
|
"cssnano": "^5.0.1",
|
||||||
|
"dedent": "^0.7.0",
|
||||||
|
"ejs": "^3.0.2",
|
||||||
|
"gh-pages": "^6.0.0",
|
||||||
|
"glob": "^7.1.6",
|
||||||
|
"highlight.js": "^10.4.1",
|
||||||
|
"live-server": "^1.2.1",
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"postcss": "^8.2.12",
|
||||||
|
"postcss-calc": "^7.0.2",
|
||||||
|
"postcss-copy": "^7.1.0",
|
||||||
|
"postcss-css-variables": "^0.19.0",
|
||||||
|
"postcss-inline": "^1.2.0",
|
||||||
|
"postcss-inline-svg": "^4.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
packages/webapp/public/98.css/server.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const chokidar = require("chokidar");
|
||||||
|
const build = require("./build");
|
||||||
|
|
||||||
|
chokidar
|
||||||
|
.watch(["style.css", "build.js", "docs", "fonts", "icon"], {
|
||||||
|
usePolling: true,
|
||||||
|
})
|
||||||
|
.on("change", (file) => {
|
||||||
|
console.log(
|
||||||
|
`[${new Date().toLocaleTimeString()}] ${file} changed -- rebuilding...`
|
||||||
|
);
|
||||||
|
build();
|
||||||
|
});
|
||||||
|
|
||||||
|
var liveServer = require("live-server");
|
||||||
|
liveServer.start({ port: 3000, root: "dist" });
|
||||||
994
packages/webapp/public/98.css/style.css
Normal file
@@ -0,0 +1,994 @@
|
|||||||
|
/**
|
||||||
|
* 98.css
|
||||||
|
* Copyright (c) 2020 Jordan Scales <thatjdanisso.cool>
|
||||||
|
* https://github.com/jdan/98.css/blob/main/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Color */
|
||||||
|
--text-color: #222222;
|
||||||
|
--surface: #c0c0c0;
|
||||||
|
--button-highlight: #ffffff;
|
||||||
|
--button-face: #dfdfdf;
|
||||||
|
--button-shadow: #808080;
|
||||||
|
--window-frame: #0a0a0a;
|
||||||
|
--dialog-blue: #000080;
|
||||||
|
--dialog-blue-light: #1084d0;
|
||||||
|
--dialog-gray: #808080;
|
||||||
|
--dialog-gray-light: #b5b5b5;
|
||||||
|
--link-blue: #0000ff;
|
||||||
|
|
||||||
|
/* Spacing */
|
||||||
|
--element-spacing: 8px;
|
||||||
|
--grouped-button-spacing: 4px;
|
||||||
|
--grouped-element-spacing: 6px;
|
||||||
|
--radio-width: 12px;
|
||||||
|
--checkbox-width: 13px;
|
||||||
|
--radio-label-spacing: 6px;
|
||||||
|
--range-track-height: 4px;
|
||||||
|
--range-spacing: 10px;
|
||||||
|
|
||||||
|
/* Some detailed computations for radio buttons and checkboxes */
|
||||||
|
--radio-total-width-precalc: var(--radio-width) + var(--radio-label-spacing);
|
||||||
|
--radio-total-width: calc(var(--radio-total-width-precalc));
|
||||||
|
--radio-left: calc(-1 * var(--radio-total-width-precalc));
|
||||||
|
--radio-dot-width: 4px;
|
||||||
|
--radio-dot-top: calc(var(--radio-width) / 2 - var(--radio-dot-width) / 2);
|
||||||
|
--radio-dot-left: calc(
|
||||||
|
-1 * (var(--radio-total-width-precalc)) + var(--radio-width) / 2 - var(
|
||||||
|
--radio-dot-width
|
||||||
|
) / 2
|
||||||
|
);
|
||||||
|
|
||||||
|
--checkbox-total-width-precalc: var(--checkbox-width) +
|
||||||
|
var(--radio-label-spacing);
|
||||||
|
--checkbox-total-width: calc(var(--checkbox-total-width-precalc));
|
||||||
|
--checkbox-left: calc(-1 * var(--checkbox-total-width-precalc));
|
||||||
|
--checkmark-width: 7px;
|
||||||
|
--checkmark-left: 3px;
|
||||||
|
|
||||||
|
/* Borders */
|
||||||
|
--border-width: 1px;
|
||||||
|
--border-raised-outer: inset -1px -1px var(--window-frame),
|
||||||
|
inset 1px 1px var(--button-highlight);
|
||||||
|
--border-raised-inner: inset -2px -2px var(--button-shadow),
|
||||||
|
inset 2px 2px var(--button-face);
|
||||||
|
--border-sunken-outer: inset -1px -1px var(--button-highlight),
|
||||||
|
inset 1px 1px var(--window-frame);
|
||||||
|
--border-sunken-inner: inset -2px -2px var(--button-face),
|
||||||
|
inset 2px 2px var(--button-shadow);
|
||||||
|
--default-button-border-raised-outer: inset -2px -2px var(--window-frame), inset 1px 1px var(--window-frame);
|
||||||
|
--default-button-border-raised-inner: inset 2px 2px var(--button-highlight), inset -3px -3px var(--button-shadow), inset 3px 3px var(--button-face);
|
||||||
|
--default-button-border-sunken-outer: inset 2px 2px var(--window-frame), inset -1px -1px var(--window-frame);
|
||||||
|
--default-button-border-sunken-inner: inset -2px -2px var(--button-highlight), inset 3px 3px var(--button-shadow), inset -3px -3px var(--button-face);
|
||||||
|
|
||||||
|
|
||||||
|
/* Window borders flip button-face and button-highlight */
|
||||||
|
--border-window-outer: inset -1px -1px var(--window-frame),
|
||||||
|
inset 1px 1px var(--button-face);
|
||||||
|
--border-window-inner: inset -2px -2px var(--button-shadow),
|
||||||
|
inset 2px 2px var(--button-highlight);
|
||||||
|
|
||||||
|
/* Field borders (checkbox, input, etc) flip window-frame and button-shadow */
|
||||||
|
--border-field: inset -1px -1px var(--button-highlight),
|
||||||
|
inset 1px 1px var(--button-shadow), inset -2px -2px var(--button-face),
|
||||||
|
inset 2px 2px var(--window-frame);
|
||||||
|
--border-status-field: inset -1px -1px var(--button-face), inset 1px 1px var(--button-shadow);
|
||||||
|
|
||||||
|
/* Tabs */
|
||||||
|
--border-tab: inset -1px 0 var(--window-frame),
|
||||||
|
inset 1px 1px var(--button-face),
|
||||||
|
inset -2px 0 var(--button-shadow),
|
||||||
|
inset 2px 2px var(--button-highlight)
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Pixelated MS Sans Serif";
|
||||||
|
src: url("fonts/converted/ms_sans_serif.woff") format("woff");
|
||||||
|
src: url("fonts/converted/ms_sans_serif.woff2") format("woff2");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Pixelated MS Sans Serif";
|
||||||
|
src: url("fonts/converted/ms_sans_serif_bold.woff") format("woff");
|
||||||
|
src: url("fonts/converted/ms_sans_serif_bold.woff2") format("woff2");
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
label,
|
||||||
|
input,
|
||||||
|
legend,
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
option,
|
||||||
|
table,
|
||||||
|
ul.tree-view,
|
||||||
|
.window,
|
||||||
|
.title-bar,
|
||||||
|
li[role=tab] {
|
||||||
|
font-family: "Pixelated MS Sans Serif", Arial;
|
||||||
|
-webkit-font-smoothing: none;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
u {
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 0.5px solid #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="reset"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: none;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0 0 var(--text-color);
|
||||||
|
background: var(--surface);
|
||||||
|
box-shadow: var(--border-raised-outer), var(--border-raised-inner);
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
min-width: 75px;
|
||||||
|
min-height: 23px;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.default,
|
||||||
|
input[type="submit"].default,
|
||||||
|
input[type="reset"].default {
|
||||||
|
box-shadow: var(--default-button-border-raised-outer), var(--default-button-border-raised-inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-bar {
|
||||||
|
width: 4px;
|
||||||
|
height: 20px;
|
||||||
|
background: #c0c0c0;
|
||||||
|
box-shadow: var(--border-raised-outer), var(--border-raised-inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled):active,
|
||||||
|
input[type="submit"]:not(:disabled):active,
|
||||||
|
input[type="reset"]:not(:disabled):active {
|
||||||
|
box-shadow: var(--border-sunken-outer), var(--border-sunken-inner);
|
||||||
|
text-shadow: 1px 1px var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.default:not(:disabled):active,
|
||||||
|
input[type="submit"].default:not(:disabled):active,
|
||||||
|
input[type="reset"].default:not(:disabled):active {
|
||||||
|
box-shadow: var(--default-button-border-sunken-outer), var(--default-button-border-sunken-inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (not(hover)) {
|
||||||
|
button:not(:disabled):hover,
|
||||||
|
input[type="submit"]:not(:disabled):hover,
|
||||||
|
input[type="reset"]:not(:disabled):hover {
|
||||||
|
box-shadow: var(--border-sunken-outer), var(--border-sunken-inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus,
|
||||||
|
input[type="submit"]:focus,
|
||||||
|
input[type="reset"]:focus {
|
||||||
|
outline: 1px dotted #000000;
|
||||||
|
outline-offset: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input[type="submit"]::-moz-focus-inner,
|
||||||
|
input[type="reset"]::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:disabled,
|
||||||
|
:disabled + label,
|
||||||
|
input[readonly],
|
||||||
|
input[readonly] + label {
|
||||||
|
color: var(--button-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled,
|
||||||
|
input[type="submit"]:disabled,
|
||||||
|
input[type="reset"]:disabled,
|
||||||
|
:disabled + label {
|
||||||
|
text-shadow: 1px 1px 0 var(--button-highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.window {
|
||||||
|
box-shadow: var(--border-window-outer), var(--border-window-inner);
|
||||||
|
background: var(--surface);
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar {
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--dialog-blue),
|
||||||
|
var(--dialog-blue-light)
|
||||||
|
);
|
||||||
|
padding: 3px 2px 3px 3px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar.inactive {
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--dialog-gray),
|
||||||
|
var(--dialog-gray-light)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-text {
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
letter-spacing: 0;
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button {
|
||||||
|
padding: 0;
|
||||||
|
display: block;
|
||||||
|
min-width: 16px;
|
||||||
|
min-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button:active {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Minimize"],
|
||||||
|
.title-bar-controls button[aria-label].minimize {
|
||||||
|
background-image: svg-load("./icon/minimize.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: bottom 3px left 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Maximize"],
|
||||||
|
.title-bar-controls button[aria-label].maximize {
|
||||||
|
background-image: svg-load("./icon/maximize.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top 2px left 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Maximize"]:disabled,
|
||||||
|
.title-bar-controls button[aria-label].maximize:disabled {
|
||||||
|
background-image: svg-load("./icon/maximize-disabled.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top 2px left 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Restore"],
|
||||||
|
.title-bar-controls button[aria-label].restore {
|
||||||
|
background-image: svg-load("./icon/restore.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top 2px left 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Help"],
|
||||||
|
.title-bar-controls button[aria-label].help {
|
||||||
|
background-image: svg-load("./icon/help.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top 2px left 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar-controls button[aria-label="Close"],
|
||||||
|
.title-bar-controls button[aria-label].close {
|
||||||
|
margin-left: 2px;
|
||||||
|
background-image: svg-load("./icon/close.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top 3px left 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
margin: 0px 1px;
|
||||||
|
display: flex;
|
||||||
|
gap: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-bar-field {
|
||||||
|
box-shadow: var(--border-status-field);
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 2px 3px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-body {
|
||||||
|
margin: var(--element-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border-image: svg-load("./icon/groupbox-border.svg") 2;
|
||||||
|
padding: calc(2 * var(--border-width) + var(--element-spacing));
|
||||||
|
padding-block-start: var(--element-spacing);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="field-row"] + [class^="field-row"] {
|
||||||
|
margin-top: var(--grouped-element-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row > * + * {
|
||||||
|
margin-left: var(--grouped-element-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row-stacked {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row-stacked * + * {
|
||||||
|
margin-top: var(--grouped-element-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
background: 0;
|
||||||
|
position: fixed;
|
||||||
|
opacity: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] + label,
|
||||||
|
input[type="checkbox"] + label {
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] + label {
|
||||||
|
position: relative;
|
||||||
|
margin-left: var(--radio-total-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] + label::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(-1 * (var(--radio-total-width-precalc)));
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--radio-width);
|
||||||
|
height: var(--radio-width);
|
||||||
|
margin-right: var(--radio-label-spacing);
|
||||||
|
background: svg-load("./icon/radio-border.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"]:active + label::before {
|
||||||
|
background: svg-load("./icon/radio-border-disabled.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"]:checked + label::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: var(--radio-dot-width);
|
||||||
|
height: var(--radio-dot-width);
|
||||||
|
top: var(--radio-dot-top);
|
||||||
|
left: var(--radio-dot-left);
|
||||||
|
position: absolute;
|
||||||
|
background: svg-load("./icon/radio-dot.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"]:focus + label,
|
||||||
|
input[type="checkbox"]:focus + label {
|
||||||
|
outline: 1px dotted #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"][disabled] + label::before {
|
||||||
|
background: svg-load("./icon/radio-border-disabled.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"][disabled]:checked + label::after {
|
||||||
|
background: svg-load("./icon/radio-dot-disabled.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] + label {
|
||||||
|
position: relative;
|
||||||
|
margin-left: var(--checkbox-total-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] + label::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: calc(-1 * (var(--checkbox-total-width-precalc)));
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--checkbox-width);
|
||||||
|
height: var(--checkbox-width);
|
||||||
|
background: var(--button-highlight);
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
margin-right: var(--radio-label-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:active + label::before {
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked + label::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: var(--checkmark-width);
|
||||||
|
height: var(--checkmark-width);
|
||||||
|
position: absolute;
|
||||||
|
left: calc(
|
||||||
|
-1 * (var(--checkbox-total-width-precalc)) + var(--checkmark-left)
|
||||||
|
);
|
||||||
|
background: svg-load("./icon/checkmark.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"][disabled] + label::before {
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"][disabled]:checked + label::after {
|
||||||
|
background: svg-load("./icon/checkmark-disabled.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="search"],
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
padding: 3px 4px;
|
||||||
|
border: none;
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
background-color: var(--button-highlight);
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="search"],
|
||||||
|
select {
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
input[type="number"] {
|
||||||
|
/* need this 1 pixel to fit the spinner controls in box */
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
/* clears the ‘X’ from Internet Explorer */
|
||||||
|
input[type=search]::-ms-clear { display: none; width : 0; height: 0; }
|
||||||
|
input[type=search]::-ms-reveal { display: none; width : 0; height: 0; }
|
||||||
|
/* clears the ‘X’ from Chrome */
|
||||||
|
input[type="search"]::-webkit-search-decoration,
|
||||||
|
input[type="search"]::-webkit-search-cancel-button,
|
||||||
|
input[type="search"]::-webkit-search-results-button,
|
||||||
|
input[type="search"]::-webkit-search-results-decoration { display: none; }
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="search"] {
|
||||||
|
/* For some reason descenders are getting cut off without this */
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="email"]:disabled,
|
||||||
|
input[type="url"]:disabled,
|
||||||
|
input[type="tel"]:disabled,
|
||||||
|
input[type="password"]:disabled,
|
||||||
|
input[type="text"]:disabled,
|
||||||
|
input[type="number"]:disabled,
|
||||||
|
input[type="search"]:disabled,
|
||||||
|
input[type="email"]:read-only,
|
||||||
|
input[type="url"]:read-only,
|
||||||
|
input[type="tel"]:read-only,
|
||||||
|
input[type="password"]:read-only,
|
||||||
|
input[type="text"]:read-only,
|
||||||
|
input[type="number"]:read-only,
|
||||||
|
input[type="search"]:read-only,
|
||||||
|
textarea:disabled {
|
||||||
|
background-color: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 32px;
|
||||||
|
background-image: svg-load("./icon/button-down.svg");
|
||||||
|
background-position: top 2px right 2px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus,
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="password"]:focus,
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="url"]:focus,
|
||||||
|
input[type="tel"]:focus,
|
||||||
|
input[type="number"]:focus,
|
||||||
|
input[type="search"]:focus,
|
||||||
|
textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 21px;
|
||||||
|
width: 11px;
|
||||||
|
background: svg-load("./icon/indicator-horizontal.svg");
|
||||||
|
transform: translateY(-8px);
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"].has-box-indicator::-webkit-slider-thumb {
|
||||||
|
background: svg-load("./icon/indicator-rectangle-horizontal.svg");
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-thumb {
|
||||||
|
height: 21px;
|
||||||
|
width: 11px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: svg-load("./icon/indicator-horizontal.svg");
|
||||||
|
transform: translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"].has-box-indicator::-moz-range-thumb {
|
||||||
|
background: svg-load("./icon/indicator-rectangle-horizontal.svg");
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: black;
|
||||||
|
border-right: 1px solid grey;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey,
|
||||||
|
-1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: black;
|
||||||
|
border-right: 1px solid grey;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey,
|
||||||
|
-1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical {
|
||||||
|
display: inline-block;
|
||||||
|
width: 4px;
|
||||||
|
height: 150px;
|
||||||
|
transform: translateY(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"] {
|
||||||
|
width: 150px;
|
||||||
|
height: 4px;
|
||||||
|
margin: 0 calc(var(--grouped-element-spacing) + var(--range-spacing)) 0
|
||||||
|
var(--range-spacing);
|
||||||
|
transform-origin: left;
|
||||||
|
transform: rotate(270deg) translateX(calc(-50% + var(--element-spacing)));
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
border-left: 1px solid grey;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey,
|
||||||
|
1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"]::-moz-range-track {
|
||||||
|
border-left: 1px solid grey;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey,
|
||||||
|
1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"]::-webkit-slider-thumb {
|
||||||
|
transform: translateY(-8px) scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"].has-box-indicator::-webkit-slider-thumb {
|
||||||
|
transform: translateY(-10px) scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"]::-moz-range-thumb {
|
||||||
|
transform: translateY(2px) scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-vertical > input[type="range"].has-box-indicator::-moz-range-thumb {
|
||||||
|
transform: translateY(0px) scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus {
|
||||||
|
color: var(--button-highlight);
|
||||||
|
background-color: var(--dialog-blue);
|
||||||
|
}
|
||||||
|
select:focus option {
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:active {
|
||||||
|
background-image: svg-load("./icon/button-down-active.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--link-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
outline: 1px dotted var(--link-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view {
|
||||||
|
display: block;
|
||||||
|
background: var(--button-highlight);
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
padding: 6px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view a:focus {
|
||||||
|
background-color: var(--dialog-blue);
|
||||||
|
color: var(--button-highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view ul,
|
||||||
|
ul.tree-view li {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view ul {
|
||||||
|
margin-left: 16px;
|
||||||
|
padding-left: 16px;
|
||||||
|
/* Goes down too far */
|
||||||
|
border-left: 1px dotted #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view ul > li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
ul.tree-view ul > li::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: -16px;
|
||||||
|
top: 6px;
|
||||||
|
width: 12px;
|
||||||
|
border-bottom: 1px dotted #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cover the bottom of the left dotted border */
|
||||||
|
ul.tree-view ul > li:last-child::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: -20px;
|
||||||
|
top: 7px;
|
||||||
|
bottom: 0px;
|
||||||
|
width: 8px;
|
||||||
|
background: var(--button-highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view details {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view details[open] summary {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view ul details > summary:before {
|
||||||
|
margin-left: -22px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view details > summary:before {
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
content: "+";
|
||||||
|
border: 1px solid #808080;
|
||||||
|
width: 8px;
|
||||||
|
height: 9px;
|
||||||
|
line-height: 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
padding-left: 1px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view details[open] > summary:before {
|
||||||
|
content: "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.tree-view details > summary::marker,
|
||||||
|
ul.tree-view details > summary::-webkit-details-marker {
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
background: var(--button-highlight);
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
padding: 12px 8px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
code * {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary:focus {
|
||||||
|
outline: 1px dotted #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar:horizontal {
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
background: var(--button-face);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background-image: svg-load("./icon/scrollbar-background.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: var(--button-face);
|
||||||
|
box-shadow: var(--border-raised-outer), var(--border-raised-inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-button:horizontal:start:decrement,
|
||||||
|
::-webkit-scrollbar-button:horizontal:end:increment,
|
||||||
|
::-webkit-scrollbar-button:vertical:start:decrement,
|
||||||
|
::-webkit-scrollbar-button:vertical:end:increment {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-button:vertical:start {
|
||||||
|
height: 17px;
|
||||||
|
background-image: svg-load("./icon/button-up.svg");
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-button:vertical:end {
|
||||||
|
height: 17px;
|
||||||
|
background-image: svg-load("./icon/button-down.svg");
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-button:horizontal:start {
|
||||||
|
width: 16px;
|
||||||
|
background-image: svg-load("./icon/button-left.svg");
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-button:horizontal:end {
|
||||||
|
width: 16px;
|
||||||
|
background-image: svg-load("./icon/button-right.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.window[role=tabpanel] {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[role=tablist] {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 0 -2px 0;
|
||||||
|
text-indent: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
display: flex;
|
||||||
|
padding-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[role=tablist] > li {
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
box-shadow: var(--border-tab);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[role=tablist] > li[aria-selected=true] {
|
||||||
|
padding-bottom: 2px;
|
||||||
|
margin-top: -2px;
|
||||||
|
background-color: var(--surface);
|
||||||
|
position: relative;
|
||||||
|
z-index: 8;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[role=tablist] > li > a {
|
||||||
|
display: block;
|
||||||
|
color: #222;
|
||||||
|
margin: 6px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
menu[role=tablist] > li[aria-selected=true] > a:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
menu[role=tablist] > li > a:focus {
|
||||||
|
outline: 1px dotted #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[role=tablist].multirows > li {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.sunken-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 2px groove transparent;
|
||||||
|
border-image: svg-load("./icon/sunken-panel-border.svg") 2;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > thead > tr > * {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
height: 17px;
|
||||||
|
box-shadow: var(--border-raised-outer), var(--border-raised-inner);
|
||||||
|
background: var(--surface);
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 0 var(--grouped-element-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.interactive > tbody > tr {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > tbody > tr.highlighted {
|
||||||
|
color: #fff;
|
||||||
|
background-color: var(--dialog-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
table > tbody > tr > * {
|
||||||
|
padding: 0 var(--grouped-element-spacing);
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-indicator {
|
||||||
|
height: 32px;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: var(--border-sunken-inner);
|
||||||
|
padding: 4px 4px;
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.progress-indicator > .progress-indicator-bar {
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: var(--dialog-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-indicator.segmented > .progress-indicator-bar {
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent; /* resets the background color which is set to blue in the non-segmented selector */
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--dialog-blue) 0 16px,
|
||||||
|
transparent 0 2px
|
||||||
|
);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-size: 18px 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-border {
|
||||||
|
background: var(--button-highlight);
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-border-disabled {
|
||||||
|
background: var(--surface);
|
||||||
|
box-shadow: var(--border-field);
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-field-border {
|
||||||
|
background: var(--surface);
|
||||||
|
box-shadow: var(--border-status-field);
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
10
packages/webapp/src/@types/i18next.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { defaultNS, resources } from "@/i18n"
|
||||||
|
|
||||||
|
|
||||||
|
declare module "i18next" {
|
||||||
|
interface CustomTypeOptions {
|
||||||
|
enableSelector: true
|
||||||
|
defaultNS: typeof defaultNS
|
||||||
|
resources: typeof resources["en"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export function App() {
|
|
||||||
return <p>WIP</p>
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.0 KiB |
56
packages/webapp/src/components/ui/button.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import type * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"inline-flex items-center justify-center whitespace-nowrap rounded-base text-sm font-base ring-offset-white transition-all gap-2 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
"text-main-foreground bg-main border-2 border-border shadow-shadow hover:translate-x-boxShadowX hover:translate-y-boxShadowY hover:shadow-none",
|
||||||
|
noShadow: "text-main-foreground bg-main border-2 border-border",
|
||||||
|
neutral:
|
||||||
|
"bg-secondary-background text-foreground border-2 border-border shadow-shadow hover:translate-x-boxShadowX hover:translate-y-boxShadowY hover:shadow-none",
|
||||||
|
reverse:
|
||||||
|
"text-main-foreground bg-main border-2 border-border hover:translate-x-reverseBoxShadowX hover:translate-y-reverseBoxShadowY hover:shadow-shadow",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-4 py-2",
|
||||||
|
sm: "h-9 px-3",
|
||||||
|
lg: "h-11 px-8",
|
||||||
|
icon: "size-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
function Button({
|
||||||
|
className,
|
||||||
|
variant,
|
||||||
|
size,
|
||||||
|
asChild = false,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"button"> &
|
||||||
|
VariantProps<typeof buttonVariants> & {
|
||||||
|
asChild?: boolean
|
||||||
|
}) {
|
||||||
|
const Comp = asChild ? Slot : "button"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
data-slot="button"
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
92
packages/webapp/src/components/ui/card.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import type * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card"
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col gap-6 rounded-base border-2 border-border bg-background py-6 font-base text-foreground shadow-shadow",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-header"
|
||||||
|
className={cn(
|
||||||
|
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-[data-slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-title"
|
||||||
|
className={cn("font-heading leading-none", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-description"
|
||||||
|
className={cn("font-base text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-content"
|
||||||
|
className={cn("px-6", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-footer"
|
||||||
|
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
CardAction,
|
||||||
|
}
|
||||||
50
packages/webapp/src/components/ui/tooltip.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||||
|
|
||||||
|
import type * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function TooltipProvider({
|
||||||
|
delayDuration = 0,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||||||
|
return (
|
||||||
|
<TooltipPrimitive.Provider
|
||||||
|
data-slot="tooltip-provider"
|
||||||
|
delayDuration={delayDuration}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tooltip({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||||||
|
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooltipTrigger({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||||||
|
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooltipContent({
|
||||||
|
className,
|
||||||
|
sideOffset = 4,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<TooltipPrimitive.Content
|
||||||
|
data-slot="tooltip-content"
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
"fade-in-0 zoom-in-95 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 origin-(--radix-tooltip-content-transform-origin) animate-in overflow-hidden rounded-base border-2 border-border bg-main px-3 py-1.5 font-base text-main-foreground text-sm data-[state=closed]:animate-out",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
||||||
14
packages/webapp/src/i18n/en.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export const en = {
|
||||||
|
common: {},
|
||||||
|
|
||||||
|
nav: {
|
||||||
|
gitRepos: {
|
||||||
|
title: "Git Repos",
|
||||||
|
tooltip: "All the public repositories on my Git server",
|
||||||
|
},
|
||||||
|
sourceCode: {
|
||||||
|
title: "Source code",
|
||||||
|
tooltip: "Source code for this website",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
16
packages/webapp/src/i18n/fr.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import type { en } from "./en"
|
||||||
|
|
||||||
|
|
||||||
|
export const fr = {
|
||||||
|
common: {},
|
||||||
|
nav: {
|
||||||
|
gitRepos: {
|
||||||
|
title: "Dépôts Git",
|
||||||
|
tooltip: "Tous les dépôts publics de mon serveur Git",
|
||||||
|
},
|
||||||
|
sourceCode: {
|
||||||
|
title: "Code source",
|
||||||
|
tooltip: "Code source de ce site",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies typeof en
|
||||||
24
packages/webapp/src/i18n/index.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import i18n from "i18next"
|
||||||
|
import LanguageDetector from "i18next-browser-languagedetector"
|
||||||
|
import { initReactI18next } from "react-i18next"
|
||||||
|
import { en } from "./en"
|
||||||
|
import { fr } from "./fr"
|
||||||
|
|
||||||
|
|
||||||
|
export const defaultNS = "common"
|
||||||
|
export const resources = { en, fr } as const
|
||||||
|
|
||||||
|
await i18n
|
||||||
|
.use(initReactI18next)
|
||||||
|
.use(LanguageDetector)
|
||||||
|
.init({
|
||||||
|
fallbackLng: "en",
|
||||||
|
supportedLngs: ["en", "fr"],
|
||||||
|
defaultNS,
|
||||||
|
resources,
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export { i18n }
|
||||||
58
packages/webapp/src/index.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/** biome-ignore-all lint/suspicious/noUnknownAtRules: Tailwind */
|
||||||
|
@import "tailwindcss";
|
||||||
|
@import "tw-animate-css";
|
||||||
|
@import "@fontsource/work-sans";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: hsl(220 23% 95%);
|
||||||
|
--secondary-background: oklch(100% 0 0);
|
||||||
|
--foreground: oklch(0% 0 0);
|
||||||
|
--main-foreground: oklch(0% 0 0);
|
||||||
|
--main: hsl(220 23% 95%);
|
||||||
|
--border: oklch(0% 0 0);
|
||||||
|
--ring: oklch(0% 0 0);
|
||||||
|
--overlay: oklch(0% 0 0 / 0.8);
|
||||||
|
--shadow: 4px 4px 0px 0px var(--border);
|
||||||
|
--chart-1: #FF7A05;
|
||||||
|
--chart-2: #0099FF;
|
||||||
|
--chart-3: #FFBF00;
|
||||||
|
--chart-4: #00D696;
|
||||||
|
--chart-5: #7A83FF;
|
||||||
|
--chart-active-dot: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-main: var(--main);
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-secondary-background: var(--secondary-background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--color-main-foreground: var(--main-foreground);
|
||||||
|
--color-border: var(--border);
|
||||||
|
--color-overlay: var(--overlay);
|
||||||
|
--color-ring: var(--ring);
|
||||||
|
--color-chart-1: var(--chart-1);
|
||||||
|
--color-chart-2: var(--chart-2);
|
||||||
|
--color-chart-3: var(--chart-3);
|
||||||
|
--color-chart-4: var(--chart-4);
|
||||||
|
--color-chart-5: var(--chart-5);
|
||||||
|
|
||||||
|
--spacing-boxShadowX: 4px;
|
||||||
|
--spacing-boxShadowY: 4px;
|
||||||
|
--spacing-reverseBoxShadowX: -4px;
|
||||||
|
--spacing-reverseBoxShadowY: -4px;
|
||||||
|
--radius-base: 5px;
|
||||||
|
--shadow-shadow: var(--shadow);
|
||||||
|
--font-weight-base: 500;
|
||||||
|
--font-weight-heading: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
@apply text-foreground font-base bg-background;
|
||||||
|
font-family: "Work Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6{
|
||||||
|
@apply font-heading;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
packages/webapp/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
|
import { createRouter, RouterProvider } from "@tanstack/react-router"
|
||||||
import { StrictMode } from "react"
|
import { StrictMode } from "react"
|
||||||
import { createRoot } from "react-dom/client"
|
import { createRoot } from "react-dom/client"
|
||||||
import { App } from "./App"
|
import "./i18n"
|
||||||
|
import "./index.css"
|
||||||
|
import { routeTree } from "./routeTree.gen"
|
||||||
|
|
||||||
|
|
||||||
|
const router = createRouter({ routeTree })
|
||||||
|
|
||||||
|
declare module "@tanstack/react-router" {
|
||||||
|
interface Register {
|
||||||
|
router: typeof router
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// biome-ignore lint/style/noNonNullAssertion: React entrypoint
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<RouterProvider router={router} />
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
)
|
)
|
||||||
|
|||||||
59
packages/webapp/src/routeTree.gen.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
|
||||||
|
// This file was automatically generated by TanStack Router.
|
||||||
|
// You should NOT make any changes in this file as it will be overwritten.
|
||||||
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||||
|
|
||||||
|
import { Route as rootRouteImport } from './routes/__root'
|
||||||
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
|
|
||||||
|
const IndexRoute = IndexRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
export interface FileRoutesByFullPath {
|
||||||
|
'/': typeof IndexRoute
|
||||||
|
}
|
||||||
|
export interface FileRoutesByTo {
|
||||||
|
'/': typeof IndexRoute
|
||||||
|
}
|
||||||
|
export interface FileRoutesById {
|
||||||
|
__root__: typeof rootRouteImport
|
||||||
|
'/': typeof IndexRoute
|
||||||
|
}
|
||||||
|
export interface FileRouteTypes {
|
||||||
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
|
fullPaths: '/'
|
||||||
|
fileRoutesByTo: FileRoutesByTo
|
||||||
|
to: '/'
|
||||||
|
id: '__root__' | '/'
|
||||||
|
fileRoutesById: FileRoutesById
|
||||||
|
}
|
||||||
|
export interface RootRouteChildren {
|
||||||
|
IndexRoute: typeof IndexRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@tanstack/react-router' {
|
||||||
|
interface FileRoutesByPath {
|
||||||
|
'/': {
|
||||||
|
id: '/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/'
|
||||||
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
|
IndexRoute: IndexRoute,
|
||||||
|
}
|
||||||
|
export const routeTree = rootRouteImport
|
||||||
|
._addFileChildren(rootRouteChildren)
|
||||||
|
._addFileTypes<FileRouteTypes>()
|
||||||
99
packages/webapp/src/routes/__root.tsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { createRootRoute, Outlet } from "@tanstack/react-router"
|
||||||
|
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { DiGit } from "react-icons/di"
|
||||||
|
import { FaCode } from "react-icons/fa"
|
||||||
|
import root from "react-shadow"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
||||||
|
|
||||||
|
|
||||||
|
export const Route = createRootRoute({
|
||||||
|
component: RootComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
function RootComponent() {
|
||||||
|
const { t, i18n } = useTranslation()
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className="flex flex-row items-center justify-center gap-2 p-2">
|
||||||
|
<Button
|
||||||
|
variant={i18n.language !== "en" ? "default" : "noShadow"}
|
||||||
|
onClick={() => i18n.changeLanguage("en")}
|
||||||
|
>
|
||||||
|
🇬🇧 English
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant={i18n.language !== "fr" ? "default" : "noShadow"}
|
||||||
|
onClick={() => i18n.changeLanguage("fr")}
|
||||||
|
>
|
||||||
|
🇫🇷 Français
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mt-20 mr-auto ml-auto">
|
||||||
|
<div className="mr-auto ml-auto flex w-fit flex-row items-start justify-around gap-10">
|
||||||
|
<root.div>
|
||||||
|
<link rel="stylesheet" href="/98.css/dist/98.css" />
|
||||||
|
|
||||||
|
<div className="window" style={{ width: 300 }}>
|
||||||
|
<div className="title-bar">
|
||||||
|
<div className="title-bar-text">Julien Valverde</div>
|
||||||
|
</div>
|
||||||
|
<div className="window-body">
|
||||||
|
<p>There's so much room for activities!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</root.div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Ingénieur Full Stack • Entrepreneur</h1>
|
||||||
|
|
||||||
|
<p className="mt-2">
|
||||||
|
I am passionate about integrating functionality and design in applications to create intuitive, user-friendly experiences.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex w-fit flex-row items-center justify-center gap-2 mt-4">
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button asChild>
|
||||||
|
<a href="https://git.valverde.cloud"><DiGit /> {t($ => $.gitRepos.title, { ns: "nav" })}</a>
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
|
||||||
|
<TooltipContent><p>{t($ => $.gitRepos.tooltip, { ns: "nav" })}</p></TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button asChild>
|
||||||
|
<a href="https://git.valverde.cloud/thilawyn/website"><FaCode /> {t($ => $.sourceCode.title, { ns: "nav" })}</a>
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
|
||||||
|
<TooltipContent><p>{t($ => $.sourceCode.tooltip, { ns: "nav" })}</p></TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
|
||||||
|
<Button>Resumé</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mx-auto w-[750px] max-w-full px-5 pt-28 pb-10 text-foreground">
|
||||||
|
<Card>
|
||||||
|
<CardContent>
|
||||||
|
<Outlet />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TanStackRouterDevtools />
|
||||||
|
</>
|
||||||
|
}
|
||||||
10
packages/webapp/src/routes/index.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
|
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/")({
|
||||||
|
component: RouteComponent,
|
||||||
|
})
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return <p className="text-center">Coming soon!</p>
|
||||||
|
}
|
||||||
@@ -23,6 +23,11 @@
|
|||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
|
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
},
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{ "name": "@effect/language-service" }
|
{ "name": "@effect/language-service" }
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,5 +3,11 @@
|
|||||||
"references": [
|
"references": [
|
||||||
{ "path": "./tsconfig.app.json" },
|
{ "path": "./tsconfig.app.json" },
|
||||||
{ "path": "./tsconfig.node.json" }
|
{ "path": "./tsconfig.node.json" }
|
||||||
]
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,6 @@
|
|||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"include": ["vite.config.ts"]
|
"include": ["vite.config.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
|
import tailwind from "@tailwindcss/vite"
|
||||||
|
import { tanstackRouter } from "@tanstack/router-plugin/vite"
|
||||||
import react from "@vitejs/plugin-react"
|
import react from "@vitejs/plugin-react"
|
||||||
|
import path from "node:path"
|
||||||
import { defineConfig } from "vite"
|
import { defineConfig } from "vite"
|
||||||
|
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [
|
||||||
|
tanstackRouter({
|
||||||
|
target: "react",
|
||||||
|
autoCodeSplitting: true,
|
||||||
|
}),
|
||||||
|
react(),
|
||||||
|
tailwind(),
|
||||||
|
],
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
host: true,
|
host: true,
|
||||||
port: 80,
|
port: 80,
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["config:recommended"],
|
||||||
"config:recommended"
|
"baseBranchPatterns": ["next"],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchManagers": ["bun", "npm"],
|
||||||
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
|
"groupName": "bun minor+patch updates",
|
||||||
|
"groupSlug": "bun-minor-patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchManagers": ["dockerfile", "docker-compose"],
|
||||||
|
"matchUpdateTypes": ["minor", "patch", "digest"],
|
||||||
|
"groupName": "docker minor+patch+digest updates",
|
||||||
|
"groupSlug": "docker-minor-patch-digest"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,12 @@
|
|||||||
"lint:tsc": {
|
"lint:tsc": {
|
||||||
"cache": false
|
"cache": false
|
||||||
},
|
},
|
||||||
"lint:eslint": {
|
"lint:biome": {
|
||||||
|
"cache": false
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"inputs": ["src/**"],
|
||||||
|
"outputs": ["dist/**"],
|
||||||
"cache": false
|
"cache": false
|
||||||
},
|
},
|
||||||
"clean:dist": {
|
"clean:dist": {
|
||||||
|
|||||||