@bleedingdev/modern-js-create 3.2.0-ultramodern.101 → 3.2.0-ultramodern.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +317 -3
- package/dist/types/locale/index.d.ts +117 -2
- package/package.json +3 -3
- package/template/README.md +6 -0
- package/template/config/favicon.svg +5 -0
- package/template/config/public/assets/ultramodern-logo.svg +6 -0
- package/template/config/public/locales/cs/translation.json +5 -0
- package/template/config/public/locales/en/translation.json +5 -0
- package/template/modern.config.ts.handlebars +6 -0
- package/template/scripts/validate-ultramodern.mjs.handlebars +93 -0
- package/template/src/routes/[lang]/page.tsx.handlebars +39 -41
- package/template/src/routes/index.css.handlebars +192 -55
- package/template/tests/ultramodern.contract.test.ts.handlebars +57 -0
- package/template/tsconfig.json +1 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="UltraModern.js">
|
|
2
|
+
<rect width="64" height="64" rx="12" fill="#111827"/>
|
|
3
|
+
<path fill="#35d399" d="M14 17h9v21c0 5 3 8 9 8s9-3 9-8V17h9v22c0 11-8 18-18 18s-18-7-18-18V17Z"/>
|
|
4
|
+
<path fill="#ffffff" d="M28 17h8v25h-8z"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" role="img" aria-label="UltraModern.js logo">
|
|
2
|
+
<rect width="160" height="160" rx="28" fill="#111827"/>
|
|
3
|
+
<path fill="#35d399" d="M42 36h22v56c0 22 14 34 36 34s36-12 36-34V36h22v57c0 35-24 57-58 57S42 128 42 93V36Z"/>
|
|
4
|
+
<path fill="#ffffff" d="M76 36h20v74H76z"/>
|
|
5
|
+
<path fill="#8be8ff" d="M112 36h18v74h-18z"/>
|
|
6
|
+
</svg>
|
|
@@ -33,7 +33,12 @@
|
|
|
33
33
|
"switcher": "Jazyk"
|
|
34
34
|
},
|
|
35
35
|
"logoAlt": "Logo UltraModern.js",
|
|
36
|
+
"meta": {
|
|
37
|
+
"description": "Lokalizovany starter aplikace UltraModern.js se silnymi vychozimi hodnotami pro komplexni produkty.",
|
|
38
|
+
"title": "UltraModern.js Starter"
|
|
39
|
+
},
|
|
36
40
|
"name": "Jednoduchy starter aplikace",
|
|
41
|
+
"skipLink": "Preskocit na obsah",
|
|
37
42
|
"title": "UltraModern.js Starter"
|
|
38
43
|
}
|
|
39
44
|
}
|
|
@@ -33,7 +33,12 @@
|
|
|
33
33
|
"switcher": "Language"
|
|
34
34
|
},
|
|
35
35
|
"logoAlt": "UltraModern.js Logo",
|
|
36
|
+
"meta": {
|
|
37
|
+
"description": "A localized UltraModern.js app starter with strong defaults for complex products.",
|
|
38
|
+
"title": "UltraModern.js Starter"
|
|
39
|
+
},
|
|
36
40
|
"name": "Simple app starter",
|
|
41
|
+
"skipLink": "Skip to content",
|
|
37
42
|
"title": "UltraModern.js Starter"
|
|
38
43
|
}
|
|
39
44
|
}
|
|
@@ -53,6 +53,12 @@ export default defineConfig(
|
|
|
53
53
|
{{/if}}{{#if enableBff}}
|
|
54
54
|
bffPlugin(),
|
|
55
55
|
{{/if}} ],
|
|
56
|
+
html: {
|
|
57
|
+
title: 'UltraModern.js Starter',
|
|
58
|
+
meta: {
|
|
59
|
+
viewport: 'width=device-width, initial-scale=1.0, viewport-fit=cover',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
56
62
|
source: {
|
|
57
63
|
globalVars: {
|
|
58
64
|
ULTRAMODERN_SITE_URL: siteUrl,
|
|
@@ -8,6 +8,9 @@ const packageSourcePath = path.resolve(
|
|
|
8
8
|
process.cwd(),
|
|
9
9
|
'.modernjs/ultramodern-package-source.json',
|
|
10
10
|
);
|
|
11
|
+
const readText = (relativePath) =>
|
|
12
|
+
fs.readFileSync(path.resolve(process.cwd(), relativePath), 'utf-8');
|
|
13
|
+
const readJson = (relativePath) => JSON.parse(readText(relativePath));
|
|
11
14
|
const readPnpmConfig = (key) => {
|
|
12
15
|
const env = Object.fromEntries(
|
|
13
16
|
Object.entries(process.env).filter(
|
|
@@ -109,6 +112,8 @@ const requiredPaths = [
|
|
|
109
112
|
{{/if}}
|
|
110
113
|
'config/public/locales/en/translation.json',
|
|
111
114
|
'config/public/locales/cs/translation.json',
|
|
115
|
+
'config/favicon.svg',
|
|
116
|
+
'config/public/assets/ultramodern-logo.svg',
|
|
112
117
|
'src/modern-app-env.d.ts',
|
|
113
118
|
'src/routes/index.css',
|
|
114
119
|
'src/routes/layout.tsx',
|
|
@@ -241,6 +246,11 @@ const packageJson = JSON.parse(
|
|
|
241
246
|
fs.readFileSync(path.resolve(process.cwd(), 'package.json'), 'utf-8'),
|
|
242
247
|
);
|
|
243
248
|
const packageSource = JSON.parse(fs.readFileSync(packageSourcePath, 'utf-8'));
|
|
249
|
+
const routePage = readText('src/routes/[lang]/page.tsx');
|
|
250
|
+
const routeCss = readText('src/routes/index.css');
|
|
251
|
+
const modernConfig = readText('modern.config.ts');
|
|
252
|
+
const enLocale = readJson('config/public/locales/en/translation.json');
|
|
253
|
+
const csLocale = readJson('config/public/locales/cs/translation.json');
|
|
244
254
|
const unresolvedTemplateMarker = String.fromCodePoint(123, 123);
|
|
245
255
|
if (JSON.stringify(packageJson).includes(unresolvedTemplateMarker)) {
|
|
246
256
|
console.error('package.json contains unresolved template markers');
|
|
@@ -250,6 +260,89 @@ if (JSON.stringify(packageSource).includes(unresolvedTemplateMarker)) {
|
|
|
250
260
|
console.error('package source metadata contains unresolved template markers');
|
|
251
261
|
process.exit(1);
|
|
252
262
|
}
|
|
263
|
+
|
|
264
|
+
for (const [fileName, text] of [
|
|
265
|
+
['src/routes/[lang]/page.tsx', routePage],
|
|
266
|
+
['src/routes/index.css', routeCss],
|
|
267
|
+
['modern.config.ts', modernConfig],
|
|
268
|
+
]) {
|
|
269
|
+
if (text.includes('lf3-static.bytednsdoc.com')) {
|
|
270
|
+
console.error(`${fileName} must not depend on remote starter assets`);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
for (const requiredSnippet of [
|
|
276
|
+
'<Helmet',
|
|
277
|
+
'htmlAttributes={{',
|
|
278
|
+
'dir: languageDirections[currentLanguage]',
|
|
279
|
+
'lang: currentLanguage',
|
|
280
|
+
'<title>{pageTitle}</title>',
|
|
281
|
+
'<meta name="description" content={pageDescription} />',
|
|
282
|
+
'<main id="starter-main" className="starter-main">',
|
|
283
|
+
'<h1 id="starter-heading" className="title">',
|
|
284
|
+
'src="/assets/ultramodern-logo.svg"',
|
|
285
|
+
'height={96}',
|
|
286
|
+
'width={96}',
|
|
287
|
+
'<span aria-hidden="true" className="arrow-right" />',
|
|
288
|
+
]) {
|
|
289
|
+
if (!routePage.includes(requiredSnippet)) {
|
|
290
|
+
console.error(`Generated route page must retain starter correctness snippet: ${requiredSnippet}`);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (const forbiddenSnippet of ['src="https://', '<div className="title">']) {
|
|
296
|
+
if (routePage.includes(forbiddenSnippet)) {
|
|
297
|
+
console.error(`Generated route page must not contain ${forbiddenSnippet}`);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (const requiredSnippet of [
|
|
303
|
+
'width=device-width, initial-scale=1.0, viewport-fit=cover',
|
|
304
|
+
"title: 'UltraModern.js Starter'",
|
|
305
|
+
]) {
|
|
306
|
+
if (!modernConfig.includes(requiredSnippet)) {
|
|
307
|
+
console.error(`modern.config.ts must retain ${requiredSnippet}`);
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (modernConfig.includes('user-scalable=no') || modernConfig.includes('maximum-scale')) {
|
|
312
|
+
console.error('modern.config.ts must not disable user zoom');
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
for (const requiredSnippet of [
|
|
317
|
+
'min-block-size: 100dvh',
|
|
318
|
+
'grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr))',
|
|
319
|
+
':focus-visible',
|
|
320
|
+
'@media (prefers-reduced-motion: reduce)',
|
|
321
|
+
'.skip-link',
|
|
322
|
+
]) {
|
|
323
|
+
if (!routeCss.includes(requiredSnippet)) {
|
|
324
|
+
console.error(`Starter CSS must retain ${requiredSnippet}`);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (routeCss.includes('width: 1100px') || /\.card:focus(?!-visible)/u.test(routeCss)) {
|
|
329
|
+
console.error('Starter CSS must not reintroduce fixed grid width or focus transform styling');
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
for (const [localeName, locale] of [
|
|
334
|
+
['en', enLocale],
|
|
335
|
+
['cs', csLocale],
|
|
336
|
+
]) {
|
|
337
|
+
if (
|
|
338
|
+
typeof locale.home?.meta?.title !== 'string' ||
|
|
339
|
+
typeof locale.home?.meta?.description !== 'string' ||
|
|
340
|
+
typeof locale.home?.skipLink !== 'string'
|
|
341
|
+
) {
|
|
342
|
+
console.error(`${localeName} locale must include starter metadata and skip-link copy`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
253
346
|
{{#unless isSubproject}}
|
|
254
347
|
const skillsLock = JSON.parse(
|
|
255
348
|
fs.readFileSync(path.resolve(process.cwd(), '.agents/skills-lock.json'), 'utf-8'),
|
|
@@ -13,6 +13,10 @@ import { useTranslation } from 'react-i18next';
|
|
|
13
13
|
const fallbackLanguage = 'en';
|
|
14
14
|
const supportedLanguages = ['en', 'cs'] as const;
|
|
15
15
|
type SupportedLanguage = (typeof supportedLanguages)[number];
|
|
16
|
+
const languageDirections: Record<SupportedLanguage, 'ltr'> = {
|
|
17
|
+
cs: 'ltr',
|
|
18
|
+
en: 'ltr',
|
|
19
|
+
};
|
|
16
20
|
|
|
17
21
|
const isSupportedLanguage = (value: string): value is SupportedLanguage =>
|
|
18
22
|
supportedLanguages.includes(value as SupportedLanguage);
|
|
@@ -52,6 +56,8 @@ const Index = () => {
|
|
|
52
56
|
const { language } = useModernI18n();
|
|
53
57
|
const location = useLocation();
|
|
54
58
|
const currentLanguage = isSupportedLanguage(language) ? language : fallbackLanguage;
|
|
59
|
+
const pageTitle = t('home.meta.title');
|
|
60
|
+
const pageDescription = t('home.meta.description');
|
|
55
61
|
const canonicalPath = localizedPath(location.pathname, currentLanguage);
|
|
56
62
|
const suffix = locationSuffix(location);
|
|
57
63
|
const languageOptions = supportedLanguages.map((code) => ({
|
|
@@ -81,12 +87,9 @@ const Index = () => {
|
|
|
81
87
|
{{/if}}
|
|
82
88
|
return (
|
|
83
89
|
<div className="container-box">
|
|
84
|
-
<Helmet>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
type="image/x-icon"
|
|
88
|
-
href="https://lf3-static.bytednsdoc.com/obj/eden-cn/uhbfnupenuhf/favicon.ico"
|
|
89
|
-
/>
|
|
90
|
+
<Helmet htmlAttributes={{ dir: languageDirections[currentLanguage], lang: currentLanguage }}>
|
|
91
|
+
<title>{pageTitle}</title>
|
|
92
|
+
<meta name="description" content={pageDescription} />
|
|
90
93
|
<link rel="canonical" href={absoluteUrl(canonicalPath)} />
|
|
91
94
|
{supportedLanguages.map((code) => (
|
|
92
95
|
<link
|
|
@@ -102,7 +105,10 @@ const Index = () => {
|
|
|
102
105
|
rel="alternate"
|
|
103
106
|
/>
|
|
104
107
|
</Helmet>
|
|
105
|
-
<main>
|
|
108
|
+
<a className="skip-link" href="#starter-main">
|
|
109
|
+
{t('home.skipLink')}
|
|
110
|
+
</a>
|
|
111
|
+
<header className="starter-header">
|
|
106
112
|
<nav className="language-switcher" aria-label={t('home.language.switcher')}>
|
|
107
113
|
{languageOptions.map((option) => (
|
|
108
114
|
<a
|
|
@@ -114,24 +120,32 @@ const Index = () => {
|
|
|
114
120
|
</a>
|
|
115
121
|
))}
|
|
116
122
|
</nav>
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
</header>
|
|
124
|
+
<main id="starter-main" className="starter-main">
|
|
125
|
+
<section className="hero" aria-labelledby="starter-heading">
|
|
119
126
|
<img
|
|
120
127
|
alt={t('home.logoAlt')}
|
|
121
128
|
className="logo"
|
|
122
|
-
|
|
129
|
+
height={96}
|
|
130
|
+
src="/assets/ultramodern-logo.svg"
|
|
131
|
+
width={96}
|
|
123
132
|
/>
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
<div className="hero-copy">
|
|
134
|
+
<p className="name">{t('home.name')}</p>
|
|
135
|
+
<h1 id="starter-heading" className="title">
|
|
136
|
+
{t('home.title')}
|
|
137
|
+
</h1>
|
|
138
|
+
<p className="description{{#if enableTailwind}} text-emerald-700 font-semibold{{/if}}">
|
|
139
|
+
{t('home.description.intro')}{' '}
|
|
140
|
+
<code className="code">presetUltramodern(...)</code>{' '}
|
|
141
|
+
{t('home.description.afterPreset')}{' '}
|
|
142
|
+
<code className="code">modern.config.ts</code>{' '}
|
|
143
|
+
{t('home.description.afterConfig')}{' '}
|
|
144
|
+
<code className="code">pnpm run ultramodern:check</code>{' '}
|
|
145
|
+
{t('home.description.end')}
|
|
146
|
+
</p>
|
|
147
|
+
</div>
|
|
148
|
+
</section>
|
|
135
149
|
{{#if useEffectBff}}
|
|
136
150
|
<p className="description effect-message{{#if enableTailwind}} text-emerald-700 font-semibold{{/if}}">
|
|
137
151
|
{t('home.bff.response')} <code className="code">{effectMessage}</code>
|
|
@@ -146,11 +160,7 @@ const Index = () => {
|
|
|
146
160
|
>
|
|
147
161
|
<h2>
|
|
148
162
|
{t('home.cards.guide.title')}
|
|
149
|
-
<
|
|
150
|
-
alt=""
|
|
151
|
-
className="arrow-right"
|
|
152
|
-
src="https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/arrow-right.svg"
|
|
153
|
-
/>
|
|
163
|
+
<span aria-hidden="true" className="arrow-right" />
|
|
154
164
|
</h2>
|
|
155
165
|
<p>{t('home.cards.guide.body')}</p>
|
|
156
166
|
</a>
|
|
@@ -162,11 +172,7 @@ const Index = () => {
|
|
|
162
172
|
>
|
|
163
173
|
<h2>
|
|
164
174
|
{t('home.cards.config.title')}
|
|
165
|
-
<
|
|
166
|
-
alt=""
|
|
167
|
-
className="arrow-right"
|
|
168
|
-
src="https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/arrow-right.svg"
|
|
169
|
-
/>
|
|
175
|
+
<span aria-hidden="true" className="arrow-right" />
|
|
170
176
|
</h2>
|
|
171
177
|
<p>{t('home.cards.config.body')}</p>
|
|
172
178
|
</a>
|
|
@@ -178,11 +184,7 @@ const Index = () => {
|
|
|
178
184
|
>
|
|
179
185
|
<h2>
|
|
180
186
|
{t('home.cards.gates.title')}
|
|
181
|
-
<
|
|
182
|
-
alt=""
|
|
183
|
-
className="arrow-right"
|
|
184
|
-
src="https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/arrow-right.svg"
|
|
185
|
-
/>
|
|
187
|
+
<span aria-hidden="true" className="arrow-right" />
|
|
186
188
|
</h2>
|
|
187
189
|
<p>{t('home.cards.gates.body')}</p>
|
|
188
190
|
</a>
|
|
@@ -194,11 +196,7 @@ const Index = () => {
|
|
|
194
196
|
>
|
|
195
197
|
<h2>
|
|
196
198
|
{t('home.cards.bff.title')}
|
|
197
|
-
<
|
|
198
|
-
alt=""
|
|
199
|
-
className="arrow-right"
|
|
200
|
-
src="https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/arrow-right.svg"
|
|
201
|
-
/>
|
|
199
|
+
<span aria-hidden="true" className="arrow-right" />
|
|
202
200
|
</h2>
|
|
203
201
|
<p>{t('home.cards.bff.body')}</p>
|
|
204
202
|
</a>
|
|
@@ -1,129 +1,266 @@
|
|
|
1
1
|
{{#if enableTailwind}}@import 'tailwindcss';
|
|
2
2
|
|
|
3
|
-
{{/if}}
|
|
3
|
+
{{/if}}:root {
|
|
4
|
+
color-scheme: light;
|
|
5
|
+
--starter-bg: #f3f6f4;
|
|
6
|
+
--starter-surface: #ffffff;
|
|
7
|
+
--starter-text: #14201b;
|
|
8
|
+
--starter-muted: #52625b;
|
|
9
|
+
--starter-border: #cfdad4;
|
|
10
|
+
--starter-accent: #087f5b;
|
|
11
|
+
--starter-accent-strong: #075f48;
|
|
12
|
+
--starter-focus: #0b7285;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
html {
|
|
16
|
+
scroll-behavior: smooth;
|
|
17
|
+
}
|
|
18
|
+
|
|
4
19
|
body {
|
|
5
|
-
padding: 0;
|
|
6
20
|
margin: 0;
|
|
7
21
|
font-family:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
22
|
+
Inter,
|
|
23
|
+
ui-sans-serif,
|
|
24
|
+
system-ui,
|
|
25
|
+
-apple-system,
|
|
26
|
+
BlinkMacSystemFont,
|
|
27
|
+
Segoe UI,
|
|
11
28
|
Arial,
|
|
12
29
|
sans-serif;
|
|
13
|
-
|
|
30
|
+
color: var(--starter-text);
|
|
31
|
+
background: linear-gradient(180deg, #ffffff 0%, var(--starter-bg) 100%);
|
|
14
32
|
}
|
|
15
33
|
|
|
16
34
|
p {
|
|
17
35
|
margin: 0;
|
|
18
36
|
}
|
|
19
37
|
|
|
20
|
-
|
|
38
|
+
.container-box,
|
|
39
|
+
.container-box *,
|
|
40
|
+
.container-box *::before,
|
|
41
|
+
.container-box *::after {
|
|
21
42
|
-webkit-font-smoothing: antialiased;
|
|
22
43
|
-moz-osx-font-smoothing: grayscale;
|
|
23
44
|
box-sizing: border-box;
|
|
24
45
|
}
|
|
25
46
|
|
|
26
47
|
.container-box {
|
|
27
|
-
min-
|
|
28
|
-
|
|
48
|
+
min-block-size: 100dvh;
|
|
49
|
+
inline-size: 100%;
|
|
29
50
|
display: flex;
|
|
30
51
|
flex-direction: column;
|
|
31
|
-
|
|
32
|
-
align-items: center;
|
|
33
|
-
padding-top: 10px;
|
|
52
|
+
padding: 1.25rem;
|
|
34
53
|
}
|
|
35
54
|
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
.skip-link {
|
|
56
|
+
position: fixed;
|
|
57
|
+
inset-block-start: 1rem;
|
|
58
|
+
inset-inline-start: 1rem;
|
|
59
|
+
z-index: 1;
|
|
60
|
+
padding: 0.65rem 0.9rem;
|
|
61
|
+
color: #ffffff;
|
|
62
|
+
background: var(--starter-accent-strong);
|
|
63
|
+
border-radius: 6px;
|
|
64
|
+
transform: translateY(-150%);
|
|
65
|
+
transition: transform 0.15s ease;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.skip-link:focus-visible {
|
|
69
|
+
transform: translateY(0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.starter-header {
|
|
73
|
+
inline-size: min(100%, 72rem);
|
|
74
|
+
margin-inline: auto;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.language-switcher {
|
|
38
78
|
display: flex;
|
|
39
|
-
flex-
|
|
40
|
-
|
|
79
|
+
flex-wrap: wrap;
|
|
80
|
+
gap: 0.5rem;
|
|
81
|
+
justify-content: flex-end;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.language-switcher a {
|
|
85
|
+
min-block-size: 2.25rem;
|
|
86
|
+
padding: 0.55rem 0.8rem;
|
|
87
|
+
color: var(--starter-muted);
|
|
88
|
+
text-decoration: none;
|
|
89
|
+
border: 1px solid transparent;
|
|
90
|
+
border-radius: 999px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.language-switcher a:hover {
|
|
94
|
+
color: var(--starter-text);
|
|
95
|
+
border-color: var(--starter-border);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.language-switcher a[aria-current='page'] {
|
|
99
|
+
color: var(--starter-accent-strong);
|
|
100
|
+
background: rgb(8 127 91 / 10%);
|
|
101
|
+
border-color: rgb(8 127 91 / 24%);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.starter-main {
|
|
105
|
+
flex: 1;
|
|
106
|
+
inline-size: min(100%, 72rem);
|
|
107
|
+
margin-inline: auto;
|
|
108
|
+
padding-block: 4rem 2rem;
|
|
109
|
+
display: grid;
|
|
110
|
+
gap: 3rem;
|
|
111
|
+
align-content: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.hero {
|
|
115
|
+
display: grid;
|
|
116
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
117
|
+
gap: 1.5rem;
|
|
41
118
|
align-items: center;
|
|
42
119
|
}
|
|
43
120
|
|
|
44
121
|
.title {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
font-
|
|
49
|
-
|
|
122
|
+
margin: 0.35rem 0 0;
|
|
123
|
+
font-size: 3.5rem;
|
|
124
|
+
line-height: 1;
|
|
125
|
+
font-weight: 750;
|
|
126
|
+
letter-spacing: 0;
|
|
127
|
+
text-wrap: balance;
|
|
50
128
|
}
|
|
51
129
|
|
|
52
130
|
.logo {
|
|
53
|
-
|
|
54
|
-
|
|
131
|
+
inline-size: 6rem;
|
|
132
|
+
block-size: 6rem;
|
|
133
|
+
border-radius: 1.25rem;
|
|
134
|
+
filter: drop-shadow(0 1rem 1.5rem rgb(17 24 39 / 18%));
|
|
55
135
|
}
|
|
56
136
|
|
|
57
137
|
.name {
|
|
58
|
-
color:
|
|
138
|
+
color: var(--starter-accent-strong);
|
|
139
|
+
font-size: 0.95rem;
|
|
140
|
+
font-weight: 700;
|
|
141
|
+
line-height: 1.4;
|
|
59
142
|
}
|
|
60
143
|
|
|
61
144
|
.description {
|
|
62
|
-
text-align: center;
|
|
63
145
|
line-height: 1.5;
|
|
64
|
-
font-size: 1.
|
|
65
|
-
color:
|
|
66
|
-
|
|
146
|
+
font-size: 1.15rem;
|
|
147
|
+
color: var(--starter-muted);
|
|
148
|
+
max-inline-size: 54rem;
|
|
149
|
+
margin-block-start: 1rem;
|
|
150
|
+
text-wrap: pretty;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.effect-message {
|
|
154
|
+
padding: 1rem;
|
|
155
|
+
background: var(--starter-surface);
|
|
156
|
+
border: 1px solid var(--starter-border);
|
|
157
|
+
border-radius: 8px;
|
|
67
158
|
}
|
|
68
159
|
|
|
69
160
|
.code {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
161
|
+
display: inline-block;
|
|
162
|
+
padding: 0.15rem 0.35rem;
|
|
163
|
+
color: var(--starter-accent-strong);
|
|
164
|
+
background: rgb(8 127 91 / 10%);
|
|
165
|
+
border-radius: 6px;
|
|
166
|
+
font-size: 0.95em;
|
|
74
167
|
font-family:
|
|
168
|
+
ui-monospace,
|
|
169
|
+
SFMono-Regular,
|
|
75
170
|
Menlo,
|
|
76
171
|
Monaco,
|
|
77
|
-
Lucida Console,
|
|
78
|
-
Liberation Mono,
|
|
79
|
-
DejaVu Sans Mono,
|
|
80
|
-
Bitstream Vera Sans Mono,
|
|
81
|
-
Courier New,
|
|
82
172
|
monospace;
|
|
83
173
|
}
|
|
84
174
|
|
|
85
175
|
.container-box .grid {
|
|
86
|
-
display:
|
|
176
|
+
display: grid;
|
|
177
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
|
|
87
178
|
align-items: center;
|
|
88
|
-
|
|
89
|
-
width: 1100px;
|
|
90
|
-
margin-top: 3rem;
|
|
179
|
+
gap: 1rem;
|
|
91
180
|
}
|
|
92
181
|
|
|
93
182
|
.card {
|
|
94
|
-
padding: 1.5rem;
|
|
95
183
|
display: flex;
|
|
96
184
|
flex-direction: column;
|
|
97
|
-
|
|
98
|
-
|
|
185
|
+
gap: 0.75rem;
|
|
186
|
+
min-block-size: 9rem;
|
|
187
|
+
padding: 1.25rem;
|
|
99
188
|
color: inherit;
|
|
100
189
|
text-decoration: none;
|
|
101
|
-
|
|
102
|
-
|
|
190
|
+
background: var(--starter-surface);
|
|
191
|
+
border: 1px solid var(--starter-border);
|
|
192
|
+
border-radius: 8px;
|
|
193
|
+
transition:
|
|
194
|
+
border-color 0.15s ease,
|
|
195
|
+
transform 0.15s ease;
|
|
103
196
|
}
|
|
104
197
|
|
|
105
|
-
.card:hover
|
|
106
|
-
|
|
107
|
-
transform:
|
|
198
|
+
.card:hover {
|
|
199
|
+
border-color: rgb(8 127 91 / 45%);
|
|
200
|
+
transform: translateY(-0.125rem);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.skip-link:focus-visible,
|
|
204
|
+
.language-switcher a:focus-visible,
|
|
205
|
+
.card:focus-visible {
|
|
206
|
+
outline: 3px solid var(--starter-focus);
|
|
207
|
+
outline-offset: 3px;
|
|
108
208
|
}
|
|
109
209
|
|
|
110
210
|
.card h2 {
|
|
111
211
|
display: flex;
|
|
112
212
|
align-items: center;
|
|
113
|
-
|
|
213
|
+
gap: 0.55rem;
|
|
214
|
+
font-size: 1.25rem;
|
|
215
|
+
line-height: 1.2;
|
|
114
216
|
margin: 0;
|
|
115
217
|
padding: 0;
|
|
116
218
|
}
|
|
117
219
|
|
|
118
220
|
.card p {
|
|
119
|
-
opacity: 0.
|
|
221
|
+
opacity: 0.7;
|
|
120
222
|
font-size: 0.9rem;
|
|
121
223
|
line-height: 1.5;
|
|
122
|
-
margin-top: 1rem;
|
|
123
224
|
}
|
|
124
225
|
|
|
125
226
|
.arrow-right {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
227
|
+
flex: none;
|
|
228
|
+
inline-size: 0.65rem;
|
|
229
|
+
block-size: 0.65rem;
|
|
230
|
+
border-block-start: 2px solid currentColor;
|
|
231
|
+
border-inline-end: 2px solid currentColor;
|
|
232
|
+
transform: rotate(45deg);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@media (max-width: 44rem) {
|
|
236
|
+
.container-box {
|
|
237
|
+
padding: 1rem;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.starter-main {
|
|
241
|
+
padding-block: 2rem 1rem;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.hero {
|
|
245
|
+
grid-template-columns: 1fr;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.title {
|
|
249
|
+
font-size: 2.5rem;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@media (prefers-reduced-motion: reduce) {
|
|
254
|
+
html {
|
|
255
|
+
scroll-behavior: auto;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.skip-link,
|
|
259
|
+
.card {
|
|
260
|
+
transition: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.card:hover {
|
|
264
|
+
transform: none;
|
|
265
|
+
}
|
|
129
266
|
}
|