diff --git a/apps/admin/index.html b/apps/admin/index.html index dc5b23f..227fea4 100644 --- a/apps/admin/index.html +++ b/apps/admin/index.html @@ -7,6 +7,6 @@
- + diff --git a/apps/admin/package.json b/apps/admin/package.json index 3eea7ff..0f01da9 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -10,14 +10,19 @@ "typecheck": "tsc -b" }, "dependencies": { + "clsx": "^2.1.1", "react": "^19.2.5", "react-dom": "^19.2.5" }, "devDependencies": { + "@csstools/postcss-global-data": "^4.0.0", "@types/node": "^24.12.2", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "autoprefixer": "^10.5.0", + "postcss-custom-media": "^12.0.1", + "postcss-nesting": "^14.0.0", "typescript": "^5.9.3", "vite": "^8.0.10" } diff --git a/apps/admin/postcss.config.mjs b/apps/admin/postcss.config.mjs new file mode 100644 index 0000000..856760f --- /dev/null +++ b/apps/admin/postcss.config.mjs @@ -0,0 +1,10 @@ +export default { + plugins: { + "@csstools/postcss-global-data": { + files: ["src/shared/styles/media.css"], + }, + "postcss-custom-media": {}, + "postcss-nesting": {}, + autoprefixer: {}, + }, +} diff --git a/apps/admin/src/App.css b/apps/admin/src/App.css deleted file mode 100644 index 7341438..0000000 --- a/apps/admin/src/App.css +++ /dev/null @@ -1,111 +0,0 @@ -:root { - color: #171411; - background: #f7f4ee; - font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -* { - box-sizing: border-box; -} - -body { - min-width: 320px; - min-height: 100vh; - margin: 0; - background: - radial-gradient(circle at 18% 18%, rgba(123, 76, 255, 0.18), transparent 30rem), - #f7f4ee; -} - -button, -input, -textarea, -select { - font: inherit; -} - -.app-shell { - min-height: 100vh; - padding: 48px 24px; -} - -.hero { - max-width: 960px; - margin: 0 auto; - padding: 40px; - border: 1px solid #e4ded4; - border-radius: 32px; - background: rgba(255, 255, 255, 0.82); - box-shadow: 0 22px 80px rgba(40, 32, 21, 0.08); -} - -.eyebrow { - margin: 0 0 16px; - color: #7b4cff; - font-size: 13px; - font-weight: 700; - letter-spacing: 0.22em; - text-transform: uppercase; -} - -h1 { - max-width: 760px; - margin: 0; - font-size: clamp(40px, 7vw, 76px); - line-height: 0.92; - letter-spacing: -0.06em; -} - -.lead { - max-width: 680px; - margin: 24px 0 0; - color: #73695d; - font-size: 18px; - line-height: 1.7; -} - -.cards { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 16px; - max-width: 960px; - margin: 24px auto 0; -} - -.card { - min-height: 150px; - padding: 24px; - border: 1px solid #e4ded4; - border-radius: 24px; - background: rgba(255, 255, 255, 0.76); -} - -.card h2 { - margin: 0; - font-size: 18px; -} - -.card p { - margin: 12px 0 0; - color: #73695d; - line-height: 1.55; -} - -@media (max-width: 720px) { - .app-shell { - padding: 24px 16px; - } - - .hero { - padding: 28px; - border-radius: 24px; - } - - .cards { - grid-template-columns: 1fr; - } -} diff --git a/apps/admin/src/App.tsx b/apps/admin/src/App.tsx deleted file mode 100644 index 0cb641f..0000000 --- a/apps/admin/src/App.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import "./App.css" - -const cards = [ - { - title: "Assets", - description: "Каталог исходных изображений и связанной metadata.", - }, - { - title: "Variants", - description: "Будущие AVIF/WebP/JPEG variants, presets и статусы генерации.", - }, - { - title: "Storage", - description: "PostgreSQL как source of truth, S3/MinIO как хранилище bytes.", - }, -] - -export function App() { - return ( -
-
-

Image Platform Admin

-

чистый Vite React TS app

-

- Это стартовая админка без UI-фреймворков. Дальше сюда добавим управление allowed hosts, - assets, variants и presets. -

-
- -
- {cards.map((card) => ( -
-

{card.title}

-

{card.description}

-
- ))} -
-
- ) -} diff --git a/apps/admin/src/app/app.tsx b/apps/admin/src/app/app.tsx new file mode 100644 index 0000000..66efbf4 --- /dev/null +++ b/apps/admin/src/app/app.tsx @@ -0,0 +1,10 @@ +import { MainLayout } from "layouts/main" +import { DashboardScreen } from "screens/dashboard" + +export function App() { + return ( + + + + ) +} diff --git a/apps/admin/src/app/main.tsx b/apps/admin/src/app/main.tsx new file mode 100644 index 0000000..46f6f77 --- /dev/null +++ b/apps/admin/src/app/main.tsx @@ -0,0 +1,18 @@ +import "shared/styles/global.css" + +import { StrictMode } from "react" +import { createRoot } from "react-dom/client" + +import { App } from "./app" + +const root = document.getElementById("root") + +if (!root) { + throw new Error("Root element #root not found") +} + +createRoot(root).render( + + + , +) diff --git a/apps/admin/src/business/.gitkeep b/apps/admin/src/business/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/admin/src/infra/.gitkeep b/apps/admin/src/infra/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/admin/src/layouts/main/index.ts b/apps/admin/src/layouts/main/index.ts new file mode 100644 index 0000000..6277ac1 --- /dev/null +++ b/apps/admin/src/layouts/main/index.ts @@ -0,0 +1,2 @@ +export { MainLayout } from "./main.layout" +export type { MainLayoutProps } from "./types/main.type" diff --git a/apps/admin/src/layouts/main/main.layout.tsx b/apps/admin/src/layouts/main/main.layout.tsx new file mode 100644 index 0000000..b1c8146 --- /dev/null +++ b/apps/admin/src/layouts/main/main.layout.tsx @@ -0,0 +1,30 @@ +import cl from "clsx" + +import styles from "./styles/main.module.css" +import type { MainLayoutProps } from "./types/main.type" + +/** + * Базовый layout админки: задаёт page shell и общую навигационную шапку. + * + * Используется для: + * - оборачивания экранов admin-приложения + * - подключения общей структуры страницы + */ +export const MainLayout = (props: MainLayoutProps) => { + const { children, className, ...rootAttrs } = props + + return ( +
+
+ + IP + Image Platform + + +

Admin MVP

+
+ +
{children}
+
+ ) +} diff --git a/apps/admin/src/layouts/main/styles/main.module.css b/apps/admin/src/layouts/main/styles/main.module.css new file mode 100644 index 0000000..00931c5 --- /dev/null +++ b/apps/admin/src/layouts/main/styles/main.module.css @@ -0,0 +1,66 @@ +.root { + min-height: 100vh; + padding: var(--space-4); + background: + radial-gradient(circle at 18% 18%, var(--color-accent-wash), transparent 30rem), + var(--color-page); + + @media (--md) { + padding: var(--space-6); + } +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; + max-width: var(--content-width); + margin: 0 auto var(--space-4); +} + +.brand { + display: inline-flex; + align-items: center; + gap: var(--space-3); + color: var(--color-text); + font-weight: 800; + letter-spacing: -0.03em; +} + +.brandMark { + display: grid; + width: 2.5rem; + height: 2.5rem; + place-items: center; + border: 1px solid var(--color-border); + border-radius: var(--radius-round); + background: var(--color-surface); + color: var(--color-accent); + box-shadow: var(--shadow-soft); + font-size: 0.8125rem; + letter-spacing: 0.08em; +} + +.brandText { + display: none; + + @media (--sm) { + display: inline; + } +} + +.status { + margin: 0; + padding: var(--space-2) var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--radius-round); + background: var(--color-surface-muted); + color: var(--color-text-muted); + font-size: 0.8125rem; + font-weight: 700; +} + +.content { + max-width: var(--content-width); + margin: 0 auto; +} diff --git a/apps/admin/src/layouts/main/types/main.type.ts b/apps/admin/src/layouts/main/types/main.type.ts new file mode 100644 index 0000000..5ac0d39 --- /dev/null +++ b/apps/admin/src/layouts/main/types/main.type.ts @@ -0,0 +1,14 @@ +import type { ComponentPropsWithoutRef, ReactNode } from "react" + +/** + * Параметры MainLayout. + */ +export type MainLayoutParams = { + /** Содержимое layout. */ + children?: ReactNode +} + +/** Атрибуты корневого элемента без children. */ +type RootAttrs = Omit, 'children'> + +export type MainLayoutProps = RootAttrs & MainLayoutParams diff --git a/apps/admin/src/main.tsx b/apps/admin/src/main.tsx deleted file mode 100644 index 2c97ca9..0000000 --- a/apps/admin/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from "react" -import { createRoot } from "react-dom/client" - -import { App } from "./App" - -createRoot(document.getElementById("root")!).render( - - - , -) diff --git a/apps/admin/src/screens/dashboard/config/dashboard.config.ts b/apps/admin/src/screens/dashboard/config/dashboard.config.ts new file mode 100644 index 0000000..6105836 --- /dev/null +++ b/apps/admin/src/screens/dashboard/config/dashboard.config.ts @@ -0,0 +1,16 @@ +export const DASHBOARD_CARDS = [ + { + title: "Assets", + description: "Каталог исходных изображений, версий и публичных identifiers.", + }, + { + title: "Variants", + description: "Статусы генерации AVIF/WebP/JPEG под presets и custom transforms.", + }, + { + title: "Storage", + description: "PostgreSQL как source of truth, S3/MinIO как хранилище готовых bytes.", + }, +] as const + +export const DASHBOARD_PIPELINE = ["Backend", "RabbitMQ", "Worker", "imgproxy", "S3"] as const diff --git a/apps/admin/src/screens/dashboard/dashboard.screen.tsx b/apps/admin/src/screens/dashboard/dashboard.screen.tsx new file mode 100644 index 0000000..3e80edd --- /dev/null +++ b/apps/admin/src/screens/dashboard/dashboard.screen.tsx @@ -0,0 +1,46 @@ +import cl from "clsx" + +import { DASHBOARD_CARDS, DASHBOARD_PIPELINE } from "./config/dashboard.config" +import styles from "./styles/dashboard.module.css" +import type { DashboardScreenProps } from "./types/dashboard.type" + +/** + * Стартовый dashboard admin-приложения. + * + * Используется для: + * - отображения стартового состояния admin MVP + * - обзора будущих разделов и пайплайна генерации + */ +export const DashboardScreen = (props: DashboardScreenProps) => { + const { className, ...rootAttrs } = props + + return ( +
+
+

Image Platform Admin

+

Control plane для image delivery

+

+ Админка будет управлять allowed hosts, assets, source versions, presets и variant + generation без прямого доступа к storage-слою. +

+
+ +
+ {DASHBOARD_CARDS.map((card) => ( +
+

{card.title}

+

{card.description}

+
+ ))} +
+ +
+ {DASHBOARD_PIPELINE.map((step) => ( + + {step} + + ))} +
+
+ ) +} diff --git a/apps/admin/src/screens/dashboard/index.ts b/apps/admin/src/screens/dashboard/index.ts new file mode 100644 index 0000000..4e99be1 --- /dev/null +++ b/apps/admin/src/screens/dashboard/index.ts @@ -0,0 +1,2 @@ +export { DashboardScreen } from "./dashboard.screen" +export type { DashboardScreenProps } from "./types/dashboard.type" diff --git a/apps/admin/src/screens/dashboard/styles/dashboard.module.css b/apps/admin/src/screens/dashboard/styles/dashboard.module.css new file mode 100644 index 0000000..31865d3 --- /dev/null +++ b/apps/admin/src/screens/dashboard/styles/dashboard.module.css @@ -0,0 +1,87 @@ +.root { + display: grid; + gap: var(--space-4); +} + +.hero { + padding: var(--space-6); + border: 1px solid var(--color-border); + border-radius: var(--radius-5); + background: var(--color-surface); + box-shadow: var(--shadow-panel); + + @media (--md) { + padding: var(--space-8); + } +} + +.eyebrow { + margin: 0 0 var(--space-4); + color: var(--color-accent); + font-size: 0.8125rem; + font-weight: 800; + letter-spacing: 0.22em; + text-transform: uppercase; +} + +.title { + max-width: 48rem; + margin: 0; + font-size: clamp(2.75rem, 7vw, 5.5rem); + line-height: 0.9; + letter-spacing: -0.07em; +} + +.lead { + max-width: 43rem; + margin: var(--space-5) 0 0; + color: var(--color-text-muted); + font-size: 1.0625rem; + line-height: 1.7; +} + +.grid { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-3); + + @media (--md) { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +.card { + min-height: 9.5rem; + padding: var(--space-5); + border: 1px solid var(--color-border); + border-radius: var(--radius-4); + background: var(--color-surface-muted); +} + +.cardTitle { + margin: 0; + font-size: 1.125rem; + letter-spacing: -0.03em; +} + +.cardDescription { + margin: var(--space-3) 0 0; + color: var(--color-text-muted); + line-height: 1.55; +} + +.pipeline { + display: flex; + flex-wrap: wrap; + gap: var(--space-2); +} + +.pipelineStep { + padding: var(--space-2) var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--radius-round); + background: var(--color-surface-muted); + color: var(--color-text-muted); + font-size: 0.8125rem; + font-weight: 700; +} diff --git a/apps/admin/src/screens/dashboard/types/dashboard.type.ts b/apps/admin/src/screens/dashboard/types/dashboard.type.ts new file mode 100644 index 0000000..8122cba --- /dev/null +++ b/apps/admin/src/screens/dashboard/types/dashboard.type.ts @@ -0,0 +1,4 @@ +import type { ComponentPropsWithoutRef } from "react" + +/** Параметры экрана Dashboard. */ +export type DashboardScreenProps = ComponentPropsWithoutRef<"section"> diff --git a/apps/admin/src/shared/styles/global.css b/apps/admin/src/shared/styles/global.css new file mode 100644 index 0000000..8bfa9ed --- /dev/null +++ b/apps/admin/src/shared/styles/global.css @@ -0,0 +1,2 @@ +@import "./variables.css"; +@import "./reset.css"; diff --git a/apps/admin/src/shared/styles/media.css b/apps/admin/src/shared/styles/media.css new file mode 100644 index 0000000..01a2e1d --- /dev/null +++ b/apps/admin/src/shared/styles/media.css @@ -0,0 +1,15 @@ +@custom-media --xs (max-width: 35.9375rem); +@custom-media --sm (min-width: 36rem); +@custom-media --md (min-width: 48rem); +@custom-media --lg (min-width: 62rem); +@custom-media --xl (min-width: 75rem); +@custom-media --2xl (min-width: 88rem); +@custom-media --3xl (min-width: 120rem); + +@custom-media --h-xs (min-height: 41.6875rem); +@custom-media --h-sm (min-height: 43.875rem); +@custom-media --h-md (min-height: 50.625rem); +@custom-media --h-lg (min-height: 56.25rem); +@custom-media --h-xl (min-height: 62.5rem); +@custom-media --h-2xl (min-height: 68.75rem); +@custom-media --h-3xl (min-height: 75rem); diff --git a/apps/admin/src/shared/styles/reset.css b/apps/admin/src/shared/styles/reset.css new file mode 100644 index 0000000..8962f59 --- /dev/null +++ b/apps/admin/src/shared/styles/reset.css @@ -0,0 +1,34 @@ +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + min-width: 320px; + min-height: 100vh; + margin: 0; + background: var(--color-page); + color: var(--color-text); + font-family: var(--font-sans); + font-synthesis: none; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; +} + +button, +input, +textarea, +select { + font: inherit; +} + +a { + color: inherit; + text-decoration: none; +} + +#root { + min-height: 100vh; +} diff --git a/apps/admin/src/shared/styles/variables.css b/apps/admin/src/shared/styles/variables.css new file mode 100644 index 0000000..22ec7c8 --- /dev/null +++ b/apps/admin/src/shared/styles/variables.css @@ -0,0 +1,24 @@ +:root { + --color-page: #f7f4ee; + --color-surface: rgb(255 255 255 / 82%); + --color-surface-muted: rgb(255 255 255 / 76%); + --color-border: #e4ded4; + --color-text: #171411; + --color-text-muted: #73695d; + --color-accent: #7b4cff; + --color-accent-wash: rgb(123 76 255 / 18%); + --font-sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --content-width: 60rem; + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --space-6: 1.75rem; + --space-8: 2.5rem; + --radius-4: 1.5rem; + --radius-5: 2rem; + --radius-round: 999px; + --shadow-soft: 0 0.75rem 2rem rgb(40 32 21 / 8%); + --shadow-panel: 0 1.375rem 5rem rgb(40 32 21 / 8%); +} diff --git a/apps/admin/src/ui/.gitkeep b/apps/admin/src/ui/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/admin/src/vite-env.d.ts b/apps/admin/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/apps/admin/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/admin/src/widgets/.gitkeep b/apps/admin/src/widgets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/admin/tsconfig.app.json b/apps/admin/tsconfig.app.json index 8fcfef4..185e86a 100644 --- a/apps/admin/tsconfig.app.json +++ b/apps/admin/tsconfig.app.json @@ -16,7 +16,18 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "app/*": ["src/app/*"], + "layouts/*": ["src/layouts/*"], + "screens/*": ["src/screens/*"], + "widgets/*": ["src/widgets/*"], + "business/*": ["src/business/*"], + "infra/*": ["src/infra/*"], + "ui/*": ["src/ui/*"], + "shared/*": ["src/shared/*"] + } }, "include": ["src"] } diff --git a/apps/admin/vite.config.ts b/apps/admin/vite.config.ts index 322f82f..1ca2f91 100644 --- a/apps/admin/vite.config.ts +++ b/apps/admin/vite.config.ts @@ -1,6 +1,22 @@ +import { fileURLToPath, URL } from "node:url" + import react from "@vitejs/plugin-react" import { defineConfig } from "vite" +const srcPath = (path: string) => fileURLToPath(new URL(`./src/${path}`, import.meta.url)) + export default defineConfig({ plugins: [react()], + resolve: { + alias: { + app: srcPath("app"), + layouts: srcPath("layouts"), + screens: srcPath("screens"), + widgets: srcPath("widgets"), + business: srcPath("business"), + infra: srcPath("infra"), + ui: srcPath("ui"), + shared: srcPath("shared"), + }, + }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 850c8aa..a68e9aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,9 @@ importers: apps/admin: dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 react: specifier: ^19.2.5 version: 19.2.5 @@ -17,6 +20,9 @@ importers: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) devDependencies: + '@csstools/postcss-global-data': + specifier: ^4.0.0 + version: 4.0.0(postcss@8.5.14) '@types/node': specifier: ^24.12.2 version: 24.12.2 @@ -29,6 +35,15 @@ importers: '@vitejs/plugin-react': specifier: ^6.0.1 version: 6.0.1(vite@8.0.10(@types/node@24.12.2)(esbuild@0.27.7)(terser@5.46.2)(tsx@4.21.0)) + autoprefixer: + specifier: ^10.5.0 + version: 10.5.0(postcss@8.5.14) + postcss-custom-media: + specifier: ^12.0.1 + version: 12.0.1(postcss@8.5.14) + postcss-nesting: + specifier: ^14.0.0 + version: 14.0.0(postcss@8.5.14) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -407,6 +422,48 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@csstools/cascade-layer-name-parser@3.0.0': + resolution: {integrity: sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@csstools/media-query-list-parser@5.0.0': + resolution: {integrity: sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/postcss-global-data@4.0.0': + resolution: {integrity: sha512-mPKrL3Tzt8k1V+hTkU8XTH6JKRekB97oKHv/MekC9nfmRa+gMf1swlHRt8YK722sYN4xOipl17FZst99jsScLA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-resolve-nested@4.0.0': + resolution: {integrity: sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 + + '@csstools/selector-specificity@6.0.0': + resolution: {integrity: sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 + '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} @@ -1696,6 +1753,13 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} + autoprefixer@10.5.0: + resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + avvio@9.2.0: resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} @@ -1803,6 +1867,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1865,6 +1933,11 @@ packages: typescript: optional: true + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2152,6 +2225,9 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -2586,6 +2662,25 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + postcss-custom-media@12.0.1: + resolution: {integrity: sha512-66syE14+VeqkUf0rRX0bvbTCbNRJF132jD+ceo8th1dap2YJEAqpdh5uG98CE3IbgHT7m9XM0GIlOazNWqQdeA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + postcss-nesting@14.0.0: + resolution: {integrity: sha512-YGFOfVrjxYfeGTS5XctP1WCI5hu8Lr9SmntjfRC+iX5hCihEO+QZl9Ra+pkjqkgoVdDKvb2JccpElcowhZtzpw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.14: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} @@ -3548,6 +3643,34 @@ snapshots: '@colors/colors@1.5.0': optional: true + '@csstools/cascade-layer-name-parser@3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-tokenizer@4.0.0': {} + + '@csstools/media-query-list-parser@5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/postcss-global-data@4.0.0(postcss@8.5.14)': + dependencies: + postcss: 8.5.14 + + '@csstools/selector-resolve-nested@4.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@6.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + '@drizzle-team/brocli@0.10.2': {} '@emnapi/core@1.10.0': @@ -4740,6 +4863,15 @@ snapshots: atomic-sleep@1.0.0: {} + autoprefixer@10.5.0(postcss@8.5.14): + dependencies: + browserslist: 4.28.2 + caniuse-lite: 1.0.30001791 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.14 + postcss-value-parser: 4.2.0 + avvio@9.2.0: dependencies: '@fastify/error': 4.2.0 @@ -4850,6 +4982,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4900,6 +5034,8 @@ snapshots: optionalDependencies: typescript: 5.9.3 + cssesc@3.0.0: {} + csstype@3.2.3: {} debug@4.4.3: @@ -5207,6 +5343,8 @@ snapshots: forwarded@0.2.0: {} + fraction.js@5.3.4: {} + fresh@2.0.0: {} fs-extra@10.1.0: @@ -5587,6 +5725,28 @@ snapshots: pluralize@8.0.0: {} + postcss-custom-media@12.0.1(postcss@8.5.14): + dependencies: + '@csstools/cascade-layer-name-parser': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/media-query-list-parser': 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.14 + + postcss-nesting@14.0.0(postcss@8.5.14): + dependencies: + '@csstools/selector-resolve-nested': 4.0.0(postcss-selector-parser@7.1.1) + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.14 + postcss-selector-parser: 7.1.1 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.5.14: dependencies: nanoid: 3.3.12