feat: update design

This commit is contained in:
2026-06-11 12:48:42 +05:00
parent fad4d81c52
commit 3a8c9fe47a
9 changed files with 269 additions and 329 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
// @ts-check // @ts-check
import { defineConfig } from 'astro/config'; import tailwindcss from "@tailwindcss/vite";
import tailwindcss from '@tailwindcss/vite'; import { defineConfig } from "astro/config";
export default defineConfig({ export default defineConfig({
vite: { vite: {
+5 -4
View File
@@ -1,6 +1,8 @@
<footer class="mt-16 border-t border-foreground/25 bg-card/60"> <footer class="mt-16 border-t border-foreground/25 bg-card/60">
<div class="mx-auto max-w-5xl px-4 py-8 sm:px-6"> <div class="mx-auto max-w-5xl px-4 py-8 sm:px-6">
<div class="flex flex-col justify-between gap-4 text-[0.7rem] uppercase tracking-wider text-muted-foreground sm:flex-row"> <div
class="flex flex-col justify-between gap-4 text-[0.7rem] uppercase tracking-wider text-muted-foreground sm:flex-row"
>
<p> <p>
© <span class="text-foreground">Дачно-Наблюдательный Трибунал №7</span> © <span class="text-foreground">Дачно-Наблюдательный Трибунал №7</span>
· Кооператив «Заря-9» · Кооператив «Заря-9»
@@ -8,9 +10,8 @@
<p>Форма А-13 · Хранить вечно · Не выносить за периметр</p> <p>Форма А-13 · Хранить вечно · Не выносить за периметр</p>
</div> </div>
<p class="mt-4 max-w-2xl text-[0.7rem] leading-relaxed text-muted-foreground"> <p class="mt-4 max-w-2xl text-[0.7rem] leading-relaxed text-muted-foreground">
Все материалы являются художественным вымыслом. Любое совпадение с Все материалы являются художественным вымыслом. Любое совпадение с реальными грядками, соседями и небесными телами
реальными грядками, соседями и небесными телами случайно. Разглашение случайно. Разглашение преследуется лишением талона на интернет.
преследуется лишением компоста.
</p> </p>
</div> </div>
</footer> </footer>
+34 -30
View File
@@ -1,16 +1,16 @@
--- ---
import BaseLayout from './base.astro' import Perforation from "../components/Perforation.astro";
import SiteHeader from '../components/SiteHeader.astro' import SiteFooter from "../components/SiteFooter.astro";
import SiteFooter from '../components/SiteFooter.astro' import SiteHeader from "../components/SiteHeader.astro";
import Perforation from '../components/Perforation.astro' import BaseLayout from "./base.astro";
interface Props { interface Props {
title: string title: string;
description?: string description?: string;
code?: string code?: string;
} }
const { title, description, code } = Astro.props as Props const { title, description, code } = Astro.props as Props;
--- ---
<BaseLayout title={`${title} // Архив ДНТ-7`} description={description}> <BaseLayout title={`${title} // Архив ДНТ-7`} description={description}>
@@ -18,9 +18,11 @@ const { title, description, code } = Astro.props as Props
<SiteHeader /> <SiteHeader />
<div class="banner-classified border-y border-foreground/30"> <div class="banner-classified border-y border-foreground/30">
<div class="mx-auto flex max-w-4xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"> <div
class="mx-auto flex max-w-4xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"
>
<span>Для служебного пользования</span> <span>Для служебного пользования</span>
<span class="hidden sm:inline">{code || 'МДС'}</span> <span class="hidden sm:inline">{code || "МДС"}</span>
<span>Экз. № 1</span> <span>Экз. № 1</span>
</div> </div>
</div> </div>
@@ -34,7 +36,7 @@ const { title, description, code } = Astro.props as Props
</a> </a>
<article class="paper relative mt-4 -rotate-[0.3deg] p-6 sm:p-10"> <article class="paper relative mt-4 -rotate-[0.3deg] p-6 sm:p-10">
<span class="tape -top-3 left-1/2 hidden -translate-x-1/2 rotate-1 sm:block" aria-hidden="true" /> <span class="tape -top-3 left-1/2 hidden -translate-x-1/2 rotate-1 sm:block" aria-hidden="true"></span>
<div class="pointer-events-none absolute right-4 top-4 sm:right-8 sm:top-10"> <div class="pointer-events-none absolute right-4 top-4 sm:right-8 sm:top-10">
<img <img
@@ -47,7 +49,9 @@ const { title, description, code } = Astro.props as Props
</div> </div>
<header class="pb-5"> <header class="pb-5">
<h1 class="max-w-2xl text-balance font-heading text-3xl font-700 uppercase leading-[0.95] tracking-tight sm:text-5xl"> <h1
class="max-w-2xl text-balance font-heading text-3xl font-700 uppercase leading-[0.95] tracking-tight sm:text-5xl"
>
{title} {title}
</h1> </h1>
<hr class="rule rule-red mt-5" /> <hr class="rule rule-red mt-5" />
@@ -69,8 +73,8 @@ const { title, description, code } = Astro.props as Props
<style> <style>
.doc-content { .doc-content {
font-size: 0.875rem; font-size: 0.9375rem;
line-height: 1.625; line-height: 1.75;
color: oklch(0.28 0.03 52 / 0.9); color: oklch(0.28 0.03 52 / 0.9);
} }
.doc-content h2 { .doc-content h2 {
@@ -78,19 +82,19 @@ const { title, description, code } = Astro.props as Props
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 1.125rem; font-size: 1.25rem;
margin-top: 2.5rem; margin-top: 3rem;
margin-bottom: 1rem; margin-bottom: 1.25rem;
padding-bottom: 0.25rem; padding-bottom: 0.35rem;
border-bottom: 1px solid oklch(0.45 0.04 56 / 0.3); border-bottom: 1px solid oklch(0.45 0.04 56 / 0.3);
} }
.doc-content h3 { .doc-content h3 {
font-family: var(--font-heading); font-family: var(--font-heading);
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
font-size: 0.9375rem; font-size: 1rem;
margin-top: 1.5rem; margin-top: 2rem;
margin-bottom: 0.75rem; margin-bottom: 1rem;
color: var(--primary); color: var(--primary);
} }
.doc-content h2:first-child { .doc-content h2:first-child {
@@ -101,7 +105,7 @@ const { title, description, code } = Astro.props as Props
margin-top: 0; margin-top: 0;
} }
.doc-content p { .doc-content p {
margin-bottom: 0.75rem; margin-bottom: 1.25rem;
} }
.doc-content strong { .doc-content strong {
font-weight: 700; font-weight: 700;
@@ -109,8 +113,8 @@ const { title, description, code } = Astro.props as Props
} }
.doc-content ol, .doc-content ol,
.doc-content ul { .doc-content ul {
margin-left: 1.25rem; margin-left: 1.5rem;
margin-bottom: 0.75rem; margin-bottom: 1.25rem;
} }
.doc-content ol { .doc-content ol {
list-style: decimal; list-style: decimal;
@@ -119,7 +123,7 @@ const { title, description, code } = Astro.props as Props
list-style: disc; list-style: disc;
} }
.doc-content li { .doc-content li {
margin-bottom: 0.35rem; margin-bottom: 0.5rem;
} }
.doc-content ol ::marker, .doc-content ol ::marker,
.doc-content ul ::marker { .doc-content ul ::marker {
@@ -130,18 +134,18 @@ const { title, description, code } = Astro.props as Props
border: 0; border: 0;
border-top: 1px solid oklch(0.45 0.04 56 / 0.5); border-top: 1px solid oklch(0.45 0.04 56 / 0.5);
box-shadow: 0 3px 0 -2px oklch(0.45 0.04 56 / 0.5); box-shadow: 0 3px 0 -2px oklch(0.45 0.04 56 / 0.5);
margin: 1.5rem 0; margin: 2.5rem 0;
} }
.doc-content table { .doc-content table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
margin-bottom: 1rem; margin-bottom: 1.25rem;
font-size: 0.8125rem; font-size: 0.875rem;
} }
.doc-content th, .doc-content th,
.doc-content td { .doc-content td {
border: 1px solid oklch(0.5 0.04 56 / 0.35); border: 1px solid oklch(0.5 0.04 56 / 0.35);
padding: 0.5rem 0.75rem; padding: 0.625rem 0.875rem;
text-align: left; text-align: left;
vertical-align: top; vertical-align: top;
} }
@@ -149,7 +153,7 @@ const { title, description, code } = Astro.props as Props
font-family: var(--font-heading); font-family: var(--font-heading);
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
font-size: 0.7rem; font-size: 0.75rem;
letter-spacing: 0.05em; letter-spacing: 0.05em;
background: oklch(0.5 0.04 56 / 0.08); background: oklch(0.5 0.04 56 / 0.08);
} }
-87
View File
@@ -1,87 +0,0 @@
export type Classification = 'СОВ. СЕКРЕТНО' | 'СЕКРЕТНО' | 'ДСП' | 'РАССЕКРЕЧЕНО'
export type Dossier = {
slug: string
code: string
name: string
fullName: string
category: 'ИНВЕНТАРЬ' | 'ПЕРСОНА' | 'ОБЪЕКТ' | 'ДИРЕКТИВА'
classification: Classification
threat: string
summary: string
}
export const DOSSIERS: Dossier[] = [
{
slug: 'lopata-bs-3000',
code: 'ИНВ-001',
name: 'Л.О.П.А.Т.А.',
fullName:
'Локализатор Органических Признаков Анунаков Трансгрессивного Адаптера',
category: 'ИНВЕНТАРЬ',
classification: 'СОВ. СЕКРЕТНО',
threat: 'КАТ. III',
summary:
'Модель БС-3000 (Садово-Боевая). Обнуление маскировочных био-голограмм и принудительное заземление внеземных агентов в полевых условиях.',
},
{
slug: 'subject-ogurec',
code: 'ОБЪ-014',
name: 'СУБЪЕКТ «ОГУРЕЦ»',
fullName: 'Биомаскировочная единица класса «Парниковый»',
category: 'ОБЪЕКТ',
classification: 'СЕКРЕТНО',
threat: 'КАТ. II',
summary:
'Рептилоидный агент, выявленный при инвентаризации теплицы участка №6. Демаскирован при пониженной температуре грунта.',
},
{
slug: 'directive-kompot',
code: 'ДИР-007',
name: 'ДИРЕКТИВА «КОМПОТ»',
fullName: 'Устав полевого противодействия чешуйчатому личному составу',
category: 'ДИРЕКТИВА',
classification: 'ДСП',
threat: 'КАТ. I',
summary:
'Свод обязательных предписаний для дачников-наблюдателей при контакте с предполагаемым агентом планеты Нибиру.',
},
{
slug: 'agent-baba-zina',
code: 'ПЕР-003',
name: 'АГЕНТ «БАБА ЗИНА»',
fullName: 'Старший полевой оператор, участок №3, кооператив «Заря-9»',
category: 'ПЕРСОНА',
classification: 'РАССЕКРЕЧЕНО',
threat: '—',
summary:
'Кавалер ордена Трудовой Грядки. Лично заземлила 14 (четырнадцать) подтверждённых рептилоидных единиц. Личность охраняется.',
},
{
slug: 'object-nibiru',
code: 'ОБЪ-000',
name: 'ПЛАНЕТА НИБИРУ',
fullName: 'Источник трансгрессивной угрозы садоводческим территориям',
category: 'ОБЪЕКТ',
classification: 'СОВ. СЕКРЕТНО',
threat: 'КАТ. IV',
summary:
'Внесистемное тело. Период сближения совпадает с пиком урожайности. Координаты [ДАННЫЕ ИЗЪЯТЫ].',
},
{
slug: 'equipment-vedro',
code: 'ИНВ-022',
name: 'В.Е.Д.Р.О.',
fullName:
'Высокочастотный Экранирующий Дезинтегратор Рептилоидных Оболочек',
category: 'ИНВЕНТАРЬ',
classification: 'СЕКРЕТНО',
threat: 'КАТ. II',
summary:
'Оцинкованный контур-ловушка. Накрывается на голову агента для блокировки телепатического канала с орбитой.',
},
]
export function getDossier(slug: string) {
return DOSSIERS.find((d) => d.slug === slug)
}
+65 -68
View File
@@ -1,125 +1,122 @@
export type RegistryEntry = { export type RegistryEntry = {
id: string | null id: string | null;
title: string title: string;
annotation: string annotation: string;
status: 'open' | 'deleted' | 'restricted' | 'lost' | 'classified' | 'password' | 'danger' status: "open" | "deleted" | "restricted" | "lost" | "classified" | "password" | "danger";
slug?: string slug?: string;
} };
export const REGISTRY: RegistryEntry[] = [ export const REGISTRY: RegistryEntry[] = [
{ {
id: 'МДС-ТП-2024', id: "МДС-ТП-2024",
title: 'Инструкция по боевому применению системы Л.О.П.А.Т.А.', title: "Технический паспорт изделия Л.О.П.А.Т.А. (Модель БС-3000).",
annotation: 'Пользовательская инструкция по базовому боевому применению системы', annotation:
status: 'open', "Полное инженерное описание устройства, волнового стального резонатора и диэлектрического березового интерфейса.",
slug: 'user-manual', status: "open",
slug: "datasheet",
},
{
id: "МДС-ТП-2024",
title: "Инструкция по боевому применению системы Л.О.П.А.Т.А.",
annotation: "Пользовательская инструкция по базовому боевому применению системы",
status: "open",
slug: "user-manual",
}, },
{ {
id: null, id: null,
title: 'Боевой устав применения системы Л.О.П.А.Т.А.', title: "Боевой устав применения системы Л.О.П.А.Т.А.",
annotation: annotation:
'Основной тактический документ Сопротивления. Содержит базовые принципы обнуления трансгрессивных адаптеров и 6 фундаментальных шагов ведения полевой демаскировки.', "Основной тактический документ Сопротивления. Содержит базовые принципы обнуления трансгрессивных адаптеров и 6 фундаментальных шагов ведения полевой демаскировки.",
status: 'deleted', status: "deleted",
}, },
{ {
id: 'МДС-ПП-11', id: "МДС-ПП-11",
title: 'Приложение №1: Тактика ближнего боя в ограниченных ионосферных пространствах.', title: "Приложение №1: Тактика ближнего боя в ограниченных ионосферных пространствах.",
annotation: annotation:
'Практическое руководство по ликвидации анунаков в замкнутых локациях типа «Лифт», «Офисный коридор» и «Кустарниковая зона».', "Практическое руководство по ликвидации анунаков в замкнутых локациях типа «Лифт», «Офисный коридор» и «Кустарниковая зона».",
status: 'open', status: "open",
slug: 'appendix-1', slug: "appendix-1",
}, },
{ {
id: null, id: null,
title: 'Приложение №2: Тактика ведения боя в условиях плотной городской застройки (Метод «Двор-Метро»).', title: "Приложение №2: Тактика ведения боя в условиях плотной городской застройки (Метод «Двор-Метро»).",
annotation: annotation:
'Инструкция по нейтрализации замаскированных агентов на асфальтовом и бетонном покрытии. Описывает приём «Искра из-под подошвы» и метод маскировки Л.О.П.А.Т.Ы. под обычный строительный инструмент дорожного рабочего.', "Инструкция по нейтрализации замаскированных агентов на асфальтовом и бетонном покрытии. Описывает приём «Искра из-под подошвы» и метод маскировки Л.О.П.А.Т.Ы. под обычный строительный инструмент дорожного рабочего.",
status: 'deleted', status: "deleted",
}, },
{ {
id: null, id: null,
title: 'Приложение №3: Тактика зимнего противостояния (Протокол «Белая Иллюзия»).', title: "Приложение №3: Тактика зимнего противостояния (Протокол «Белая Иллюзия»).",
annotation: annotation:
'Руководство по ведению боя в условиях отрицательных температур. При низких температурах трансгрессивный адаптер пришельцев начинает сильно греться, выдавая их локацию паром из ушей.', "Руководство по ведению боя в условиях отрицательных температур. При низких температурах трансгрессивный адаптер пришельцев начинает сильно греться, выдавая их локацию паром из ушей.",
status: 'deleted', status: "deleted",
}, },
{ {
id: null, id: null,
title: 'Приложение №4: Тактика ведения боя на воде и в прибрежных зонах (Операция «Чешуя в камышах»).', title: "Приложение №4: Тактика ведения боя на воде и в прибрежных зонах (Операция «Чешуя в камышах»).",
annotation: annotation:
'Анунаки обожают маскироваться под рыбаков или отдыхающих на пляжах, чтобы восстанавливать гидро-баланс. Документ содержит тактику «Весло-Трансформер».', "Анунаки обожают маскироваться под рыбаков или отдыхающих на пляжах, чтобы восстанавливать гидро-баланс. Документ содержит тактику «Весло-Трансформер».",
status: 'deleted', status: "deleted",
}, },
{ {
id: null, id: null,
title: 'Приложение №5: Тактика ведения боя в условиях общественного транспорта (Инструкция «Час Пик»).', title: "Приложение №5: Тактика ведения боя в условиях общественного транспорта (Инструкция «Час Пик»).",
annotation: annotation: "Особенности применения БС-3000 в переполненных автобусах, трамваях и вагонах электричек.",
'Особенности применения БС-3000 в переполненных автобусах, трамваях и вагонах электричек.', status: "deleted",
status: 'deleted',
}, },
{ {
id: null, id: null,
title: 'Приложение №6: Тактика ночного боя и противодействие тепловизионному зрению (Протокол «Слепое пятно»).', title: "Приложение №6: Тактика ночного боя и противодействие тепловизионному зрению (Протокол «Слепое пятно»).",
annotation: annotation:
'Рептилоиды прекрасно видят в темноте инфракрасный спектр. Документ обучает использованию разогретого стального полотна Л.О.П.А.Т.Ы. в качестве теплового экрана.', "Рептилоиды прекрасно видят в темноте инфракрасный спектр. Документ обучает использованию разогретого стального полотна Л.О.П.А.Т.Ы. в качестве теплового экрана.",
status: 'deleted', status: "deleted",
},
{
id: 'МДС-ТП-2024',
title: 'Технический паспорт изделия Л.О.П.А.Т.А. (Модель БС-3000).',
annotation:
'Полное инженерное описание устройства, волнового стального резонатора и диэлектрического березового интерфейса.',
status: 'open',
slug: 'datasheet',
}, },
{ {
id: null, id: null,
title: 'Памятка по перехвату ментальных IT-сигналов.', title: "Памятка по перехвату ментальных IT-сигналов.",
annotation: annotation:
'Инструкция для гражданских лиц, объясняющая, как отличить системный сбой нано-костюма ящерицы от обычного человеческого переутомления.', "Инструкция для гражданских лиц, объясняющая, как отличить системный сбой нано-костюма ящерицы от обычного человеческого переутомления.",
status: 'deleted', status: "deleted",
}, },
{ {
id: null, id: null,
title: 'Регламент экстренной связи с мобильной группой «Бабушка с лопатой».', title: "Регламент экстренной связи с мобильной группой «Бабушка с лопатой».",
annotation: annotation:
'Описание радиочастотных кодов (Канал 13) и звуковых маркеров для вызова тяжелой дачной артиллерии в зону прорыва.', "Описание радиочастотных кодов (Канал 13) и звуковых маркеров для вызова тяжелой дачной артиллерии в зону прорыва.",
status: 'lost', status: "lost",
}, },
{ {
id: null, id: null,
title: 'Приложение №2: Система распознавания «Свой-Чужой» при контакте с председателями СНТ.', title: "Приложение №2: Система распознавания «Свой-Чужой» при контакте с председателями СНТ.",
annotation: annotation: "Статус: Засекречено Советом Земли из-за высокого риска междоусобных войн за чернозём.",
'Статус: Засекречено Советом Земли из-за высокого риска междоусобных войн за чернозём.', status: "deleted",
status: 'deleted',
}, },
{ {
id: null, id: null,
title: 'Схемы скрытого ношения БС-3000 в городских условиях под видом элементов складного самоката или моноколеса.', title: "Схемы скрытого ношения БС-3000 в городских условиях под видом элементов складного самоката или моноколеса.",
annotation: annotation: "Статус: Ожидает верификации инженерным отделом на предмет электромагнитной совместимости.",
'Статус: Ожидает верификации инженерным отделом на предмет электромагнитной совместимости.', status: "restricted",
status: 'restricted',
}, },
{ {
id: null, id: null,
title: 'Стенограмма допроса пленного Анунака 4-го ранга, пойманного на краже элитных семян томатов «Бычье сердце».', title: "Стенограмма допроса пленного Анунака 4-го ранга, пойманного на краже элитных семян томатов «Бычье сердце».",
annotation: 'Статус: Файл засекречен Межгалактическим Комитетом Рептилоидов', annotation: "Статус: Файл засекречен Межгалактическим Комитетом Рептилоидов",
status: 'classified', status: "classified",
}, },
{ {
id: null, id: null,
title: 'Сценарий операции «ДАЧНЫЙ СЕЗОН»', title: "Сценарий операции «ДАЧНЫЙ СЕЗОН»",
annotation: annotation:
'Описание сценария глобального перехвата и заземления ночного десанта тарелок Нибиру с помощью одновременного удара плашмя 10 000 операторов Л.О.П.А.Т.', "Описание сценария глобального перехвата и заземления ночного десанта тарелок Нибиру с помощью одновременного удара плашмя 10 000 операторов Л.О.П.А.Т.",
status: 'password', status: "password",
}, },
{ {
id: null, id: null,
title: 'Химический анализ зелёной люминесцентной субстанции (хладагента).', title: "Химический анализ зелёной люминесцентной субстанции (хладагента).",
annotation: annotation:
'Статус: Заблокировано Минздравом. Документ содержит незацензуренные рецепты приготовления противоядия на основе рассола.', "Статус: Заблокировано Минздравом. Документ содержит незацензуренные рецепты приготовления противоядия на основе рассола.",
status: 'danger', status: "danger",
}, },
] ];
export const OPEN_SLUGS = REGISTRY.filter((e) => e.status === 'open').map((e) => e.slug!) export const OPEN_SLUGS = REGISTRY.filter((e) => e.status === "open").map((e) => e.slug!);
+15 -17
View File
@@ -1,9 +1,9 @@
--- ---
import BaseLayout from '../layouts/base.astro' import OverlayStamp from "../components/OverlayStamp.astro";
import SiteHeader from '../components/SiteHeader.astro' import Perforation from "../components/Perforation.astro";
import SiteFooter from '../components/SiteFooter.astro' import SiteFooter from "../components/SiteFooter.astro";
import Perforation from '../components/Perforation.astro' import SiteHeader from "../components/SiteHeader.astro";
import OverlayStamp from '../components/OverlayStamp.astro' import BaseLayout from "../layouts/base.astro";
--- ---
<BaseLayout title="Доступ запрещён // Архив ДНТ-7"> <BaseLayout title="Доступ запрещён // Архив ДНТ-7">
@@ -11,7 +11,9 @@ import OverlayStamp from '../components/OverlayStamp.astro'
<SiteHeader /> <SiteHeader />
<div class="banner-classified border-y border-foreground/30"> <div class="banner-classified border-y border-foreground/30">
<div class="mx-auto flex max-w-4xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"> <div
class="mx-auto flex max-w-4xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"
>
<span>СОВ. СЕКРЕТНО</span> <span>СОВ. СЕКРЕТНО</span>
<span class="hidden sm:inline">Гриф особой важности</span> <span class="hidden sm:inline">Гриф особой важности</span>
<span>Доступ закрыт</span> <span>Доступ закрыт</span>
@@ -20,7 +22,7 @@ import OverlayStamp from '../components/OverlayStamp.astro'
<main class="mx-auto flex max-w-4xl px-4 py-24 sm:px-6"> <main class="mx-auto flex max-w-4xl px-4 py-24 sm:px-6">
<article class="paper relative mx-auto w-full max-w-lg -rotate-[0.3deg] p-10 text-center"> <article class="paper relative mx-auto w-full max-w-lg -rotate-[0.3deg] p-10 text-center">
<span class="tape -top-3 left-1/2 -translate-x-1/2 rotate-2" aria-hidden="true" /> <span class="tape -top-3 left-1/2 -translate-x-1/2 rotate-2" aria-hidden="true"></span>
<div class="pointer-events-none absolute right-6 top-6 rotate-[12deg]"> <div class="pointer-events-none absolute right-6 top-6 rotate-[12deg]">
<OverlayStamp class="text-3xl sm:text-4xl">ЗАПРЕЩЕНО</OverlayStamp> <OverlayStamp class="text-3xl sm:text-4xl">ЗАПРЕЩЕНО</OverlayStamp>
@@ -37,24 +39,20 @@ import OverlayStamp from '../components/OverlayStamp.astro'
<hr class="rule rule-red mx-auto my-6 w-32" /> <hr class="rule rule-red mx-auto my-6 w-32" />
<p class="text-sm leading-relaxed text-foreground/90"> <p class="text-sm leading-relaxed text-foreground/90">
Запрашиваемый документ находится под грифом особой важности и не Запрашиваемый документ находится под грифом особой важности и не подлежит разглашению лицам без ментального
подлежит разглашению лицам без ментального допуска 3-го уровня. допуска 3-го уровня.
</p> </p>
<p class="mt-3 text-sm leading-relaxed text-foreground/90"> <p class="mt-3 text-sm leading-relaxed text-foreground/90">
Ожидайте следующую партию рассекреченных документов. Сроки Ожидайте следующую партию рассекреченных документов. Сроки рассекречивания будут объявлены дополнительным
рассекречивания будут объявлены дополнительным циркуляром. циркуляром.
</p> </p>
<div class="mt-8"> <div class="mt-8">
<span class="stamp stamp-skew mx-auto inline-flex px-4 py-2 text-sm"> <span class="stamp stamp-skew mx-auto inline-flex px-4 py-2 text-sm"> Доступ запрещён </span>
Доступ запрещён
</span>
</div> </div>
<p class="mt-8 text-[0.65rem] uppercase tracking-wider text-muted-foreground"> <p class="mt-8 text-[0.65rem] uppercase tracking-wider text-muted-foreground">Форма А-13 · Хранить вечно</p>
Форма А-13 · Хранить вечно
</p>
</article> </article>
</main> </main>
+1 -1
View File
@@ -16,7 +16,7 @@ code: МДС-ТП-2024
## 1. ТЕХНИЧЕСКИЕ ХАРАКТЕРИСТИКИ ## 1. ТЕХНИЧЕСКИЕ ХАРАКТЕРИСТИКИ
| Параметр | Значение / Описание | | Параметр | Значение / Описание |
| --- | --- | | -------------------- | -------------------------------------------------------------------------------- |
| Интерфейс управления | Деревянный цилиндрический черенок (берёза/ясень, класс защиты от телепатии IP68) | | Интерфейс управления | Деревянный цилиндрический черенок (берёза/ясень, класс защиты от телепатии IP68) |
| Рабочий орган | Сверхпрочная углеродистая сталь с анти-чешуйчатым напылением | | Рабочий орган | Сверхпрочная углеродистая сталь с анти-чешуйчатым напылением |
| Радиус поражения | Длина черенка + длина вытянутой руки патриота Земли (приблизительно 1.5–2 метра) | | Радиус поражения | Длина черенка + длина вытянутой руки патриота Земли (приблизительно 1.5–2 метра) |
+71 -59
View File
@@ -1,33 +1,33 @@
--- ---
import BaseLayout from '../layouts/base.astro' import OverlayStamp from "../components/OverlayStamp.astro";
import SiteHeader from '../components/SiteHeader.astro' import Perforation from "../components/Perforation.astro";
import SiteFooter from '../components/SiteFooter.astro' import SiteFooter from "../components/SiteFooter.astro";
import Stamp from '../components/Stamp.astro' import SiteHeader from "../components/SiteHeader.astro";
import OverlayStamp from '../components/OverlayStamp.astro' import Stamp from "../components/Stamp.astro";
import Perforation from '../components/Perforation.astro' import BaseLayout from "../layouts/base.astro";
import { REGISTRY } from '../lib/registry' import { REGISTRY } from "../lib/registry";
const statusLabel: Record<string, string> = { const statusLabel: Record<string, string> = {
open: 'ОТКРЫТ', open: "ОТКРЫТ",
deleted: 'ДАННЫЕ УДАЛЕНЫ', deleted: "ДАННЫЕ УДАЛЕНЫ",
restricted: 'ДОСТУП ОГРАНИЧЕН', restricted: "ДОСТУП ОГРАНИЧЕН",
lost: 'ДАННЫЕ ПОТЕРЯНЫ', lost: "ДАННЫЕ ПОТЕРЯНЫ",
classified: 'ЗАСЕКРЕЧЕНО', classified: "ЗАСЕКРЕЧЕНО",
password: 'ДОСТУП ПО ПАРОЛЮ', password: "ДОСТУП ПО ПАРОЛЮ",
danger: 'ОПАСНОСТЬ ЗАРАЖЕНИЯ', danger: "ОПАСНОСТЬ ЗАРАЖЕНИЯ",
} };
const statusColor: Record<string, string> = { const statusColor: Record<string, string> = {
open: 'text-primary', open: "text-primary",
deleted: 'text-muted-foreground opacity-60', deleted: "text-muted-foreground opacity-60",
restricted: 'text-muted-foreground opacity-70', restricted: "text-muted-foreground opacity-70",
lost: 'text-muted-foreground opacity-50', lost: "text-muted-foreground opacity-50",
classified: 'text-primary', classified: "text-primary",
password: 'text-foreground', password: "text-foreground",
danger: 'text-primary', danger: "text-primary",
} };
const tilts = ['-0.6deg', '0.5deg', '-0.4deg'] const tilts = ["-0.6deg", "0.5deg", "-0.4deg"];
--- ---
<BaseLayout title="РЕЕСТР ДОКУМЕНТОВ // Архив ДНТ-7"> <BaseLayout title="РЕЕСТР ДОКУМЕНТОВ // Архив ДНТ-7">
@@ -35,7 +35,9 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
<SiteHeader /> <SiteHeader />
<div class="banner-classified border-y border-foreground/30"> <div class="banner-classified border-y border-foreground/30">
<div class="mx-auto flex max-w-5xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"> <div
class="mx-auto flex max-w-5xl items-center justify-between gap-4 px-4 py-1.5 text-[0.65rem] font-700 uppercase tracking-[0.2em] sm:px-6"
>
<span>Сов. Секретно</span> <span>Сов. Секретно</span>
<span class="hidden sm:inline">Реестр МДС</span> <span class="hidden sm:inline">Реестр МДС</span>
<span>Хранить вечно</span> <span>Хранить вечно</span>
@@ -45,8 +47,8 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
<main class="mx-auto max-w-5xl px-4 py-10 sm:px-6"> <main class="mx-auto max-w-5xl px-4 py-10 sm:px-6">
<!-- Hero --> <!-- Hero -->
<section class="paper relative mb-12 -rotate-[0.4deg] p-6 sm:p-10"> <section class="paper relative mb-12 -rotate-[0.4deg] p-6 sm:p-10">
<span class="tape -top-3 left-10 rotate-3" aria-hidden="true" /> <span class="tape -top-3 left-10 rotate-3" aria-hidden="true"></span>
<span class="tape -top-3 right-12 -rotate-2" aria-hidden="true" /> <span class="tape -top-3 right-12 -rotate-2" aria-hidden="true"></span>
<div class="pointer-events-none absolute right-4 top-4 sm:right-8 sm:top-8"> <div class="pointer-events-none absolute right-4 top-4 sm:right-8 sm:top-8">
<img <img
@@ -61,13 +63,14 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
<p class="font-mono text-xs uppercase tracking-[0.3em] text-muted-foreground"> <p class="font-mono text-xs uppercase tracking-[0.3em] text-muted-foreground">
Межгалактическое Дачное Сопротивление · Архив ДНТ-7 Межгалактическое Дачное Сопротивление · Архив ДНТ-7
</p> </p>
<h1 class="mt-3 max-w-2xl text-balance font-heading text-3xl font-700 uppercase leading-[0.95] tracking-tight sm:text-5xl"> <h1
class="mt-3 max-w-2xl text-balance font-heading text-3xl font-700 uppercase leading-[0.95] tracking-tight sm:text-5xl"
>
Реестр документов МДС Реестр документов МДС
</h1> </h1>
<p class="mt-4 max-w-xl text-pretty text-sm leading-relaxed text-foreground/90"> <p class="mt-4 max-w-xl text-pretty text-sm leading-relaxed text-foreground/90">
Рассекреченный реестр документов Межгалактического Дачного Сопротивления. Рассекреченный реестр документов Межгалактического Дачного Сопротивления. Статус базы данных: доступ
Статус базы данных: доступ ограничен. Требуется ментальный допуск 3-го уровня ограничен. Требуется ментальный допуск 3-го уровня и шапочка из фольги марки А1.
и шапочка из фольги марки А1.
</p> </p>
<div class="mt-6 flex flex-wrap items-center gap-3"> <div class="mt-6 flex flex-wrap items-center gap-3">
@@ -87,9 +90,7 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
<section class="mb-12"> <section class="mb-12">
<div class="mb-6 flex items-end justify-between"> <div class="mb-6 flex items-end justify-between">
<div> <div>
<h2 class="font-heading text-xl font-700 uppercase tracking-wide"> <h2 class="font-heading text-xl font-700 uppercase tracking-wide">Открытые дела</h2>
Открытые дела
</h2>
<hr class="rule rule-red mt-2 w-32" /> <hr class="rule rule-red mt-2 w-32" />
</div> </div>
<p class="font-mono text-[0.65rem] uppercase tracking-wider text-muted-foreground"> <p class="font-mono text-[0.65rem] uppercase tracking-wider text-muted-foreground">
@@ -98,16 +99,15 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
</div> </div>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3"> <div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
{REGISTRY.filter((e) => e.status === 'open').map((e, i) => ( {
REGISTRY.filter((e) => e.status === "open").map((e, i) => (
<a <a
href={`/docs/${e.slug}`} href={`/docs/${e.slug}`}
class="paper group relative flex flex-col gap-2 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-[0_26px_50px_-22px_rgba(40,25,15,0.7)]" class="paper group relative flex flex-col gap-2 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-[0_26px_50px_-22px_rgba(40,25,15,0.7)]"
style={{ rotate: tilts[i] }} style={{ rotate: tilts[i] }}
> >
<span class="tape -top-3 left-1/2 -translate-x-1/2 -rotate-2" aria-hidden="true" /> <span class="tape -top-3 left-1/2 -translate-x-1/2 -rotate-2" aria-hidden="true" />
<p class="font-heading text-[0.7rem] font-600 uppercase tracking-wider text-primary"> <p class="font-heading text-[0.7rem] font-600 uppercase tracking-wider text-primary">{e.id}</p>
{e.id}
</p>
<h3 class="font-heading text-base font-700 uppercase leading-tight tracking-tight transition-colors group-hover:text-primary"> <h3 class="font-heading text-base font-700 uppercase leading-tight tracking-tight transition-colors group-hover:text-primary">
{e.title} {e.title}
</h3> </h3>
@@ -118,7 +118,8 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
</span> </span>
</div> </div>
</a> </a>
))} ))
}
</div> </div>
</section> </section>
@@ -126,9 +127,7 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
<section> <section>
<div class="mb-6 flex items-end justify-between"> <div class="mb-6 flex items-end justify-between">
<div> <div>
<h2 class="font-heading text-xl font-700 uppercase tracking-wide"> <h2 class="font-heading text-xl font-700 uppercase tracking-wide">Полный реестр</h2>
Полный реестр
</h2>
<hr class="rule mt-2 w-40" /> <hr class="rule mt-2 w-40" />
</div> </div>
<p class="font-mono text-[0.65rem] uppercase tracking-wider text-muted-foreground"> <p class="font-mono text-[0.65rem] uppercase tracking-wider text-muted-foreground">
@@ -137,40 +136,53 @@ const tilts = ['-0.6deg', '0.5deg', '-0.4deg']
</div> </div>
<div class="space-y-3"> <div class="space-y-3">
{REGISTRY.map((entry, i) => { {
const isOpen = entry.status === 'open' REGISTRY.map((entry, i) => {
const href = isOpen ? `/docs/${entry.slug}` : '/404' const isOpen = entry.status === "open";
const href = isOpen ? `/docs/${entry.slug}` : undefined;
const Tag = isOpen ? "a" : "div";
return ( return (
<a <Tag
href={href} href={href}
class:list={[ class:list={[
'paper flex items-start justify-between gap-4 px-4 py-3 text-sm transition-all', "flex items-start justify-between gap-4 px-4 py-3 text-sm transition-all",
isOpen && 'hover:-translate-y-0.5 hover:shadow-[0_12px_30px_-16px_rgba(40,25,15,0.5)]', isOpen
? "paper border-l-4 border-l-primary hover:-translate-y-0.5 hover:shadow-[0_12px_30px_-16px_rgba(40,25,15,0.5)]"
: "border border-border/30 bg-card/50 opacity-50 cursor-default",
]} ]}
style={{ rotate: i % 2 === 0 ? '-0.2deg' : '0.2deg' }} style={{ rotate: i % 2 === 0 ? "-0.2deg" : "0.2deg" }}
> >
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<span class="font-mono text-[0.65rem] uppercase tracking-wider text-muted-foreground"> <span
{entry.id ? `[${entry.id}]` : '[ДАННЫЕ УДАЛЕНЫ]'} class:list={[
"font-mono text-[0.65rem] uppercase tracking-wider",
isOpen ? "text-primary" : "text-muted-foreground",
]}
>
{entry.id ? `[${entry.id}]` : "[ДАННЫЕ УДАЛЕНЫ]"}
</span> </span>
<p class="mt-0.5 font-heading text-sm font-600 uppercase leading-snug tracking-tight"> <p
class:list={[
"mt-0.5 font-heading text-sm font-600 uppercase leading-snug tracking-tight",
!isOpen && "line-through",
]}
>
{entry.title} {entry.title}
</p> </p>
<p class="mt-1 text-xs leading-relaxed text-muted-foreground"> <p class="mt-1 text-xs leading-relaxed text-muted-foreground">{entry.annotation}</p>
{entry.annotation}
</p>
</div> </div>
<span <span
class:list={[ class:list={[
'shrink-0 font-heading text-[0.6rem] font-600 uppercase tracking-wider', "shrink-0 font-heading text-[0.65rem] font-600 uppercase tracking-wider",
statusColor[entry.status], statusColor[entry.status],
]} ]}
> >
{statusLabel[entry.status]} {statusLabel[entry.status]}
</span> </span>
</a> </Tag>
) );
})} })
}
</div> </div>
</section> </section>
+34 -19
View File
@@ -1,11 +1,11 @@
@import 'tailwindcss'; @import "tailwindcss";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@theme inline { @theme inline {
--font-heading: 'Oswald', sans-serif; --font-heading: "Oswald", sans-serif;
--font-sans: 'IBM Plex Mono', monospace; --font-sans: "IBM Plex Mono", monospace;
--font-mono: 'IBM Plex Mono', monospace; --font-mono: "IBM Plex Mono", monospace;
--color-sidebar-ring: var(--sidebar-ring); --color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border); --color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -91,20 +91,25 @@
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
background-image: background-image:
radial-gradient( radial-gradient(130% 120% at 50% 0%, transparent 55%, oklch(0.3 0.04 52 / 0.12) 100%),
130% 120% at 50% 0%,
transparent 55%,
oklch(0.3 0.04 52 / 0.12) 100%
),
radial-gradient(oklch(0.3 0.03 52 / 0.05) 1px, transparent 1.4px), radial-gradient(oklch(0.3 0.03 52 / 0.05) 1px, transparent 1.4px),
radial-gradient(oklch(0.3 0.03 52 / 0.04) 1px, transparent 1.4px), radial-gradient(oklch(0.3 0.03 52 / 0.04) 1px, transparent 1.4px),
linear-gradient(180deg, oklch(0.91 0.03 80), oklch(0.88 0.03 76)); linear-gradient(180deg, oklch(0.91 0.03 80), oklch(0.88 0.03 76));
background-size: 100% 100%, 16px 16px, 22px 22px, 100% 100%; background-size:
background-position: 0 0, 0 0, 8px 11px, 0 0; 100% 100%,
16px 16px,
22px 22px,
100% 100%;
background-position:
0 0,
0 0,
8px 11px,
0 0;
background-attachment: fixed; background-attachment: fixed;
} }
html { html {
@apply font-mono; @apply font-mono;
font-size: 18px;
} }
} }
@@ -117,12 +122,11 @@
position: relative; position: relative;
background-color: var(--card); background-color: var(--card);
background-image: background-image:
linear-gradient( linear-gradient(oklch(0.5 0.03 56 / 0.05) 1px, transparent 1px),
oklch(0.5 0.03 56 / 0.05) 1px,
transparent 1px
),
radial-gradient(oklch(0.3 0.03 52 / 0.04) 1px, transparent 1.3px); radial-gradient(oklch(0.3 0.03 52 / 0.04) 1px, transparent 1.3px);
background-size: 100% 30px, 18px 18px; background-size:
100% 30px,
18px 18px;
border: 1px solid oklch(0.5 0.04 56 / 0.35); border: 1px solid oklch(0.5 0.04 56 / 0.35);
box-shadow: box-shadow:
0 1px 0 oklch(1 0 0 / 0.4) inset, 0 1px 0 oklch(1 0 0 / 0.4) inset,
@@ -167,7 +171,8 @@
box-shadow: inset 0 0 0 1.5px var(--c); box-shadow: inset 0 0 0 1.5px var(--c);
opacity: 0.78; opacity: 0.78;
mix-blend-mode: multiply; mix-blend-mode: multiply;
-webkit-mask-image: radial-gradient(oklch(0 0 0) 60%, transparent 62%), -webkit-mask-image:
radial-gradient(oklch(0 0 0) 60%, transparent 62%),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.4 1.1'/%3E%3C/filter%3E%3Crect width='80' height='40' filter='url(%23n)'/%3E%3C/svg%3E"); url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.4 1.1'/%3E%3C/filter%3E%3Crect width='80' height='40' filter='url(%23n)'/%3E%3C/svg%3E");
-webkit-mask-composite: source-over; -webkit-mask-composite: source-over;
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.4 1.1'/%3E%3C/filter%3E%3Crect width='80' height='40' filter='url(%23n)'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1.4 1.1'/%3E%3C/filter%3E%3Crect width='80' height='40' filter='url(%23n)'/%3E%3C/svg%3E");
@@ -202,8 +207,7 @@
} }
.banner-classified { .banner-classified {
background: background: repeating-linear-gradient(
repeating-linear-gradient(
45deg, 45deg,
oklch(0.42 0.16 30), oklch(0.42 0.16 30),
oklch(0.42 0.16 30) 14px, oklch(0.42 0.16 30) 14px,
@@ -213,3 +217,14 @@
color: var(--primary-foreground); color: var(--primary-foreground);
} }
} }
.doc-content {
& p {
margin-top: 0.5rem;
}
& h1,
h2 {
margin-top: 2rem;
margin-bottom: 1rem;
}
}