chore: добавить SLM-каркас admin

- добавлен app entrypoint, main layout и dashboard screen\n- настроены алиасы SLM-слоёв и PostCSS для CSS Modules\n- перенесены глобальные стили в shared/styles
This commit is contained in:
2026-05-05 14:28:17 +03:00
parent 2c88cc3eca
commit 72f9386f57
29 changed files with 575 additions and 163 deletions

View File

@@ -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

View File

@@ -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 (
<section {...rootAttrs} className={cl(styles.root, className)}>
<div className={styles.hero}>
<p className={styles.eyebrow}>Image Platform Admin</p>
<h1 className={styles.title}>Control plane для image delivery</h1>
<p className={styles.lead}>
Админка будет управлять allowed hosts, assets, source versions, presets и variant
generation без прямого доступа к storage-слою.
</p>
</div>
<div className={styles.grid} aria-label="Будущие разделы admin">
{DASHBOARD_CARDS.map((card) => (
<article className={styles.card} key={card.title}>
<h2 className={styles.cardTitle}>{card.title}</h2>
<p className={styles.cardDescription}>{card.description}</p>
</article>
))}
</div>
<div className={styles.pipeline} aria-label="Пайплайн генерации изображений">
{DASHBOARD_PIPELINE.map((step) => (
<span className={styles.pipelineStep} key={step}>
{step}
</span>
))}
</div>
</section>
)
}

View File

@@ -0,0 +1,2 @@
export { DashboardScreen } from "./dashboard.screen"
export type { DashboardScreenProps } from "./types/dashboard.type"

View File

@@ -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;
}

View File

@@ -0,0 +1,4 @@
import type { ComponentPropsWithoutRef } from "react"
/** Параметры экрана Dashboard. */
export type DashboardScreenProps = ComponentPropsWithoutRef<"section">