@dontfeedmachines/fieldkit 0.0.0-stage → 0.4.2
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/CHANGELOG.md +11 -0
- package/LICENSE +203 -0
- package/NOTICE +131 -0
- package/README.md +12 -2
- package/config/menu.default.json +6 -0
- package/config/wiki.default.json +32 -0
- package/css/base.css +150 -0
- package/package.json +44 -3
- package/pouches/sutures/astro/AnsiLogo.astro +51 -0
- package/pouches/sutures/astro/Barcode.astro +19 -0
- package/pouches/sutures/astro/BomTable.astro +44 -0
- package/pouches/sutures/astro/Breadcrumb.astro +56 -0
- package/pouches/sutures/astro/BuildStep.astro +42 -0
- package/pouches/sutures/astro/BuildSteps.astro +63 -0
- package/pouches/sutures/astro/Button.astro +5 -0
- package/pouches/sutures/astro/CTA.astro +58 -0
- package/pouches/sutures/astro/Difficulty.astro +27 -0
- package/pouches/sutures/astro/Footer.astro +80 -0
- package/pouches/sutures/astro/Glossary.astro +64 -0
- package/pouches/sutures/astro/Grid.astro +54 -0
- package/pouches/sutures/astro/Header.astro +270 -0
- package/pouches/sutures/astro/Hero.astro +38 -0
- package/pouches/sutures/astro/ImageMod.astro +66 -0
- package/pouches/sutures/astro/InteractiveCircuit.astro +192 -0
- package/pouches/sutures/astro/LegalWarning.astro +18 -0
- package/pouches/sutures/astro/MobileMenuToggle.astro +105 -0
- package/pouches/sutures/astro/PageFrame.astro +166 -0
- package/pouches/sutures/astro/Search.astro +541 -0
- package/pouches/sutures/astro/Section.astro +14 -0
- package/pouches/sutures/astro/SidebarNav.astro +106 -0
- package/pouches/sutures/astro/SidebarRestorePoint.astro +10 -0
- package/pouches/sutures/astro/SidebarSublist.astro +257 -0
- package/pouches/sutures/astro/SiteTitle.astro +65 -0
- package/pouches/sutures/astro/SpecTable.astro +64 -0
- package/pouches/sutures/astro/TeletextChar.astro +51 -0
- package/pouches/sutures/astro/ThemeSwitch.astro +93 -0
- package/pouches/sutures/astro/ThreatLevel.astro +77 -0
- package/pouches/sutures/astro/ThreatModel.astro +32 -0
- package/pouches/sutures/astro/TwoColumnContent.astro +84 -0
- package/pouches/sutures/astro/Win.astro +13 -0
- package/pouches/sutures/astro/index.ts +21 -0
- package/src/elements.ts +404 -0
- package/src/lib/scrapeview.ts +61 -0
- package/src/lib/seal.ts +157 -0
- package/src/lib/teletext-chars.ts +723 -0
- package/src/node/astro.ts +121 -0
- package/src/node/registry.ts +221 -0
- package/src/node/seal.ts +7 -0
- package/src/node/wiki.ts +45 -0
- package/src/wiki/ansi.ts +15 -0
- package/src/wiki/config.ts +5 -0
- package/src/wiki/teletext.ts +21 -0
- package/src/wiki/textConverter.ts +16 -0
- package/src/wiki/virtual.d.ts +7 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
export interface Props {
|
|
4
|
+
items: Array<{
|
|
5
|
+
name: string;
|
|
6
|
+
qty: number;
|
|
7
|
+
cost?: string;
|
|
8
|
+
link?: string;
|
|
9
|
+
notes?: string;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
const { items } = Astro.props;
|
|
13
|
+
---
|
|
14
|
+
<div class="not-content overflow-x-auto my-6 border border-zinc-800 rounded-lg">
|
|
15
|
+
<table class="w-full text-left border-collapse text-sm">
|
|
16
|
+
<thead>
|
|
17
|
+
<tr class="bg-zinc-900/50 border-b border-zinc-800">
|
|
18
|
+
<th class="p-3 font-semibold text-zinc-300">Component</th>
|
|
19
|
+
<th class="p-3 font-semibold text-zinc-300 w-16 text-center">Qty</th>
|
|
20
|
+
<th class="p-3 font-semibold text-zinc-300 w-24">Est. Cost</th>
|
|
21
|
+
<th class="p-3 font-semibold text-zinc-300">Notes</th>
|
|
22
|
+
</tr>
|
|
23
|
+
</thead>
|
|
24
|
+
<tbody class="divide-y divide-zinc-800/50 bg-zinc-900/20">
|
|
25
|
+
{items.map(item => (
|
|
26
|
+
<tr class="hover:bg-zinc-800/30 transition-colors">
|
|
27
|
+
<td class="p-3">
|
|
28
|
+
{item.link ? (
|
|
29
|
+
<a href={item.link} target="_blank" rel="noopener noreferrer" class="text-blue-400 hover:text-blue-300 hover:underline flex items-center gap-1">
|
|
30
|
+
{item.name}
|
|
31
|
+
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
|
|
32
|
+
</a>
|
|
33
|
+
) : (
|
|
34
|
+
<span class="text-zinc-200">{item.name}</span>
|
|
35
|
+
)}
|
|
36
|
+
</td>
|
|
37
|
+
<td class="p-3 text-center text-zinc-400">{item.qty}</td>
|
|
38
|
+
<td class="p-3 text-zinc-400 font-mono text-xs">{item.cost || '-'}</td>
|
|
39
|
+
<td class="p-3 text-zinc-500 text-xs">{item.notes || '-'}</td>
|
|
40
|
+
</tr>
|
|
41
|
+
))}
|
|
42
|
+
</tbody>
|
|
43
|
+
</table>
|
|
44
|
+
</div>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
const url = Astro.url;
|
|
3
|
+
const pathSegments = url.pathname.split("/").filter((segment) => segment);
|
|
4
|
+
const breadcrumbItems = pathSegments.map((segment, index) => {
|
|
5
|
+
const href = "/" + pathSegments.slice(0, index + 1).join("/");
|
|
6
|
+
const text = decodeURIComponent(segment.replace(/-/g, " "));
|
|
7
|
+
return { href, text };
|
|
8
|
+
});
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<div class="breadcrumb">
|
|
12
|
+
<ul>
|
|
13
|
+
{breadcrumbItems.map((item) => <li>{item.text}</li>)}
|
|
14
|
+
</ul>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<style>
|
|
18
|
+
@layer starlight.core {
|
|
19
|
+
.breadcrumb {
|
|
20
|
+
padding:0 2.4rem;
|
|
21
|
+
padding-top: 0px;
|
|
22
|
+
}
|
|
23
|
+
ul {
|
|
24
|
+
list-style: none;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
font-size: 0.875rem;
|
|
28
|
+
color: var(--sl-color-text);
|
|
29
|
+
padding-left: 0px;
|
|
30
|
+
}
|
|
31
|
+
li {
|
|
32
|
+
position: relative;
|
|
33
|
+
text-transform: capitalize;
|
|
34
|
+
}
|
|
35
|
+
li::after {
|
|
36
|
+
content: '';
|
|
37
|
+
display: inline-block;
|
|
38
|
+
width: 8px;
|
|
39
|
+
height: 10px;
|
|
40
|
+
margin-left: 0.5rem;
|
|
41
|
+
margin-right: 0.5rem;
|
|
42
|
+
background-image: url('data:image/svg+xml;utf8,<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.50004 1L6.5 6L1.5 11" stroke="%23999999" stroke-width="1.5" stroke-miterlimit="16" stroke-linecap="round" stroke-linejoin="round"/></svg>');
|
|
43
|
+
background-repeat: no-repeat;
|
|
44
|
+
background-position: center;
|
|
45
|
+
background-size: contain;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
li:last-child {
|
|
50
|
+
color: var(--sl-color-white);
|
|
51
|
+
}
|
|
52
|
+
li:last-child::after {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
export interface Props {
|
|
4
|
+
title: string;
|
|
5
|
+
stepNumber: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { title, stepNumber } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
<div class="build-step" data-step="{stepNumber}">
|
|
11
|
+
<details open={stepNumber === 1}>
|
|
12
|
+
<summary>
|
|
13
|
+
<div class="step-header">
|
|
14
|
+
<div class="step-checkbox">
|
|
15
|
+
<input type="checkbox" id={`step-${stepNumber}`} />
|
|
16
|
+
<label for={`step-${stepNumber}`}></label>
|
|
17
|
+
</div>
|
|
18
|
+
<span class="step-number">{stepNumber}.</span>
|
|
19
|
+
<span class="step-title">{title}</span>
|
|
20
|
+
<span class="step-toggle">▼</span>
|
|
21
|
+
</div>
|
|
22
|
+
</summary>
|
|
23
|
+
<div class="step-content">
|
|
24
|
+
<slot />
|
|
25
|
+
</div>
|
|
26
|
+
</details>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.build-step { border: 1px solid var(--sl-color-gray-5, #444); border-radius: 0.5rem; background: var(--sl-color-gray-6, #1a1a1a); transition: all 0.2s ease; }
|
|
31
|
+
.build-step.completed { opacity: 0.7; border-color: var(--sl-color-green, #4ade80); }
|
|
32
|
+
.build-step details > summary { list-style: none; cursor: pointer; }
|
|
33
|
+
.build-step details > summary::-webkit-details-marker { display: none; }
|
|
34
|
+
.step-header { display: flex; align-items: center; gap: 1rem; padding: 1rem; user-select: none; }
|
|
35
|
+
.step-checkbox { display: flex; align-items: center; }
|
|
36
|
+
.step-checkbox input { width: 1.25rem; height: 1.25rem; cursor: pointer; accent-color: var(--sl-color-green, #4ade80); }
|
|
37
|
+
.step-number { font-weight: 700; color: var(--sl-color-gray-3, #999); }
|
|
38
|
+
.step-title { font-weight: 600; flex: 1; color: var(--sl-color-white, #fff); }
|
|
39
|
+
.step-toggle { color: var(--sl-color-gray-3, #999); transition: transform 0.2s ease; }
|
|
40
|
+
details[open] .step-toggle { transform: rotate(180deg); }
|
|
41
|
+
.step-content { padding: 0 1rem 1rem 3.5rem; color: var(--sl-color-gray-2, #ccc); }
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
// expects <BuildStep> components as children
|
|
4
|
+
---
|
|
5
|
+
<div class="build-steps-container">
|
|
6
|
+
<div class="progress-bar">
|
|
7
|
+
<div class="progress-fill" id="build-progress"></div>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="steps-list">
|
|
10
|
+
<slot />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
class BuildSteps {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.init();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
init() {
|
|
21
|
+
const steps = document.querySelectorAll('.build-step');
|
|
22
|
+
const progress = document.getElementById('build-progress');
|
|
23
|
+
|
|
24
|
+
if (!steps.length || !progress) return;
|
|
25
|
+
|
|
26
|
+
const updateProgress = () => {
|
|
27
|
+
const completed = document.querySelectorAll('.build-step input[type="checkbox"]:checked').length;
|
|
28
|
+
const percent = (completed / steps.length) * 100;
|
|
29
|
+
progress.style.width = `${percent}%`;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
steps.forEach((step, index) => {
|
|
33
|
+
const checkbox = step.querySelector('input[type="checkbox"]');
|
|
34
|
+
if (checkbox) {
|
|
35
|
+
checkbox.addEventListener('change', (e) => {
|
|
36
|
+
if (e.target.checked) {
|
|
37
|
+
step.classList.add('completed');
|
|
38
|
+
const nextStep = steps[index + 1];
|
|
39
|
+
if (nextStep) {
|
|
40
|
+
const details = nextStep.querySelector('details');
|
|
41
|
+
if (details) details.open = true;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
step.classList.remove('completed');
|
|
45
|
+
}
|
|
46
|
+
updateProgress();
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
updateProgress();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
document.addEventListener('DOMContentLoaded', () => new BuildSteps());
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<style>
|
|
59
|
+
.build-steps-container { margin: 2rem 0; }
|
|
60
|
+
.progress-bar { height: 8px; background: var(--sl-color-gray-5, #333); border-radius: 4px; margin-bottom: 1.5rem; overflow: hidden; }
|
|
61
|
+
.progress-fill { height: 100%; width: 0%; background: var(--sl-color-accent, #3b82f6); transition: width 0.3s ease; }
|
|
62
|
+
.steps-list { display: flex; flex-direction: column; gap: 1rem; }
|
|
63
|
+
</style>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { config } from "../../../src/wiki/config.ts";
|
|
3
|
+
import Button from "./Button.astro";
|
|
4
|
+
import Section from "./Section.astro";
|
|
5
|
+
|
|
6
|
+
const { title, description, enable, fill_button, outline_button, background } = config.cta ?? {};
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
enable && (
|
|
11
|
+
<div class="cta-container" style={background ? `--fk-cta-bg: url(${background})` : undefined}>
|
|
12
|
+
<Section title={title} description={description}>
|
|
13
|
+
{fill_button?.enable && (
|
|
14
|
+
<Button
|
|
15
|
+
label={fill_button.label || "Get Started"}
|
|
16
|
+
link={fill_button.link || "/getting-started/introduction/overview/"}
|
|
17
|
+
variant="primary"
|
|
18
|
+
/>
|
|
19
|
+
)}
|
|
20
|
+
{outline_button?.enable && (
|
|
21
|
+
<Button
|
|
22
|
+
label={outline_button.label || "Get a live demo"}
|
|
23
|
+
link={
|
|
24
|
+
outline_button.link || "/getting-started/introduction/overview/"
|
|
25
|
+
}
|
|
26
|
+
variant="outline-primary"
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
</Section>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
<style>
|
|
35
|
+
:global([data-theme="light"]) .cta-container {
|
|
36
|
+
background-blend-mode: multiply;
|
|
37
|
+
background-color: #f9fafb;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:global([data-theme="dark"]) .cta-container {
|
|
41
|
+
background: var(--fk-cta-bg, none) no-repeat center;
|
|
42
|
+
background-size: cover;
|
|
43
|
+
padding: 1rem;
|
|
44
|
+
position: relative;
|
|
45
|
+
}
|
|
46
|
+
</style>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
const ctaContainerButton = document.querySelector(".cta-container a");
|
|
50
|
+
|
|
51
|
+
const buttonParent = ctaContainerButton?.parentElement;
|
|
52
|
+
|
|
53
|
+
if (buttonParent) {
|
|
54
|
+
buttonParent.style.display = "flex";
|
|
55
|
+
buttonParent.style.justifyContent = "center";
|
|
56
|
+
buttonParent.style.gap = "1rem";
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
export interface Props {
|
|
4
|
+
level: 1 | 2 | 3 | 4 | 5;
|
|
5
|
+
label?: string;
|
|
6
|
+
}
|
|
7
|
+
const { level, label } = Astro.props;
|
|
8
|
+
const max = 5;
|
|
9
|
+
---
|
|
10
|
+
<div class="not-content flex items-center gap-4 my-4 p-3 bg-zinc-800/50 rounded-lg border border-zinc-700">
|
|
11
|
+
<div class="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
|
12
|
+
{label || "Assembly Difficulty"}
|
|
13
|
+
</div>
|
|
14
|
+
<div class="flex gap-1">
|
|
15
|
+
{Array.from({ length: max }).map((_, i) => (
|
|
16
|
+
<svg
|
|
17
|
+
class={`w-5 h-5 ${i < level ? 'text-amber-500' : 'text-zinc-600'}`}
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
|
|
19
|
+
>
|
|
20
|
+
<path fill-rule="evenodd" d="M14.615 1.595a.75.75 0 01.359.852L12.982 9.75h7.268a.75.75 0 01.548 1.262l-10.5 11.25a.75.75 0 01-1.272-.71l1.992-7.302H3.75a.75.75 0 01-.548-1.262l10.5-11.25a.75.75 0 01.913-.143z" clip-rule="evenodd" />
|
|
21
|
+
</svg>
|
|
22
|
+
))}
|
|
23
|
+
</div>
|
|
24
|
+
<div class="text-xs text-zinc-500">
|
|
25
|
+
{level} / 5
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { config, getTranslations } from "../../../src/wiki/config.ts";
|
|
3
|
+
import { markdownify } from "../../../src/wiki/textConverter.ts";
|
|
4
|
+
import { teletextPages } from "../../../src/wiki/teletext.ts";
|
|
5
|
+
|
|
6
|
+
type Link = { name: string; url: string; page?: string };
|
|
7
|
+
type Group = { title: string; links: Link[] };
|
|
8
|
+
|
|
9
|
+
const menu = await getTranslations(Astro.currentLocale || "en");
|
|
10
|
+
// numbered from the sidebar the same way the home index is, so the two never disagree
|
|
11
|
+
const wiki: Group = {
|
|
12
|
+
title: "THIS WIKI",
|
|
13
|
+
links: teletextPages(Astro.locals.starlightRoute.sidebar).map((p) => ({ name: p.label, url: p.href, page: String(p.page) })),
|
|
14
|
+
};
|
|
15
|
+
const groups = [wiki, ...(Object.values(menu.footer ?? {}) as Group[])];
|
|
16
|
+
const bands = ["red", "green", "yellow", "cyan"];
|
|
17
|
+
const external = (url: string) => /^https?:\/\//.test(url);
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<footer class="tt-footer">
|
|
21
|
+
<div class="container">
|
|
22
|
+
<div class="tt-footer-grid">
|
|
23
|
+
{
|
|
24
|
+
groups.map((g, i) => (
|
|
25
|
+
<nav aria-label={g.title}>
|
|
26
|
+
<h2 class={`tt-footer-band tt-fx-${bands[i % bands.length]}`}>{g.title}</h2>
|
|
27
|
+
<ul>
|
|
28
|
+
{g.links.map((l) => (
|
|
29
|
+
<li>
|
|
30
|
+
<a href={l.url} rel={external(l.url) ? "noopener" : undefined}>
|
|
31
|
+
{l.page && <span class="tt-footer-page">{l.page}</span>}
|
|
32
|
+
{l.name}
|
|
33
|
+
{external(l.url) && <span class="tt-footer-out" aria-hidden="true">↗</span>}
|
|
34
|
+
</a>
|
|
35
|
+
</li>
|
|
36
|
+
))}
|
|
37
|
+
</ul>
|
|
38
|
+
</nav>
|
|
39
|
+
))
|
|
40
|
+
}
|
|
41
|
+
</div>
|
|
42
|
+
<div class="tt-footer-bottom">
|
|
43
|
+
<p set:html={markdownify(config?.params?.copyright)} />
|
|
44
|
+
<p class="tt-footer-sign">P100 {config.site.status_name} // END OF PAGE</p>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</footer>
|
|
48
|
+
|
|
49
|
+
<style>
|
|
50
|
+
.tt-footer { border-top: 2px solid var(--tt-ink); margin-top: 48px; }
|
|
51
|
+
.tt-footer-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; padding: 0 0 40px; }
|
|
52
|
+
.tt-footer nav { min-width: 0; }
|
|
53
|
+
.tt-footer-band {
|
|
54
|
+
display: block; margin: 0 0 14px !important; padding: 9px 12px; color: #000 !important;
|
|
55
|
+
font: 400 15px/1.1 var(--tt-font-tele) !important; letter-spacing: 0.02em; text-transform: uppercase;
|
|
56
|
+
}
|
|
57
|
+
.tt-footer ul { list-style: none; margin: 0; padding: 0 12px; }
|
|
58
|
+
.tt-footer li { margin: 0 !important; }
|
|
59
|
+
.tt-footer li a {
|
|
60
|
+
display: flex; align-items: baseline; gap: 10px; padding: 5px 0; color: var(--tt-ink); text-decoration: none; font-size: 1rem;
|
|
61
|
+
}
|
|
62
|
+
.tt-footer li a:hover, .tt-footer li a:focus-visible { color: var(--tt-link); text-decoration: underline; }
|
|
63
|
+
.tt-footer-page { font: 400 14px/1 var(--tt-font-tele); color: var(--tt-yellow); }
|
|
64
|
+
:global(:root[data-theme="light"]) .tt-footer-page { color: var(--tt-blue); }
|
|
65
|
+
.tt-footer-out { font-size: 0.8em; color: var(--tt-muted); }
|
|
66
|
+
.tt-footer-bottom {
|
|
67
|
+
display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px 24px;
|
|
68
|
+
border-top: 2px dashed var(--tt-rule); padding: 18px 0 32px; font: 400 14px/1.4 var(--tt-font-tele); color: var(--tt-muted);
|
|
69
|
+
}
|
|
70
|
+
.tt-footer-bottom p { margin: 0; }
|
|
71
|
+
.tt-footer-bottom :global(a) { color: var(--tt-link); }
|
|
72
|
+
.tt-footer-sign { color: var(--tt-yellow); }
|
|
73
|
+
:global(:root[data-theme="light"]) .tt-footer-sign { color: #000; }
|
|
74
|
+
@media (max-width: 800px) {
|
|
75
|
+
.tt-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 28px; }
|
|
76
|
+
}
|
|
77
|
+
@media (max-width: 480px) {
|
|
78
|
+
.tt-footer-grid { grid-template-columns: 1fr; }
|
|
79
|
+
}
|
|
80
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
export interface Props {
|
|
4
|
+
term: string;
|
|
5
|
+
definition: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { term, definition } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
<span class="glossary-term" data-definition={definition}>
|
|
11
|
+
{term}
|
|
12
|
+
<span class="glossary-tooltip">{definition}</span>
|
|
13
|
+
</span>
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
.glossary-term {
|
|
17
|
+
position: relative;
|
|
18
|
+
border-bottom: 1px dotted var(--sl-color-text-accent, #60a5fa);
|
|
19
|
+
cursor: help;
|
|
20
|
+
color: var(--sl-color-text-accent, #60a5fa);
|
|
21
|
+
font-weight: 500;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.glossary-tooltip {
|
|
25
|
+
visibility: hidden;
|
|
26
|
+
opacity: 0;
|
|
27
|
+
width: max-content;
|
|
28
|
+
max-width: 250px;
|
|
29
|
+
background-color: var(--sl-color-black, #111);
|
|
30
|
+
color: var(--sl-color-white, #fff);
|
|
31
|
+
text-align: center;
|
|
32
|
+
border: 1px solid var(--sl-color-gray-5, #444);
|
|
33
|
+
border-radius: 6px;
|
|
34
|
+
padding: 0.75rem;
|
|
35
|
+
position: absolute;
|
|
36
|
+
z-index: 10;
|
|
37
|
+
bottom: 125%;
|
|
38
|
+
left: 50%;
|
|
39
|
+
transform: translateX(-50%) translateY(10px);
|
|
40
|
+
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
|
|
41
|
+
font-size: 0.85rem;
|
|
42
|
+
font-weight: normal;
|
|
43
|
+
line-height: 1.4;
|
|
44
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.glossary-tooltip::after {
|
|
48
|
+
content: "";
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: 100%;
|
|
51
|
+
left: 50%;
|
|
52
|
+
margin-left: -5px;
|
|
53
|
+
border-width: 5px;
|
|
54
|
+
border-style: solid;
|
|
55
|
+
border-color: var(--sl-color-gray-5, #444) transparent transparent transparent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.glossary-term:hover .glossary-tooltip,
|
|
59
|
+
.glossary-term:focus-within .glossary-tooltip {
|
|
60
|
+
visibility: visible;
|
|
61
|
+
opacity: 1;
|
|
62
|
+
transform: translateX(-50%) translateY(0);
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
// DFM custom components
|
|
3
|
+
interface Props {
|
|
4
|
+
columns?: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { columns = 2 } = Astro.props;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<div class="card-grid" style={`--columns: ${columns}`}><slot /></div>
|
|
11
|
+
|
|
12
|
+
<style>
|
|
13
|
+
@layer starlight.components {
|
|
14
|
+
.card-grid {
|
|
15
|
+
display: grid;
|
|
16
|
+
gap: 1rem;
|
|
17
|
+
grid-template-columns: 1fr;
|
|
18
|
+
margin-top: 1.4rem !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.card-grid > :global(*) {
|
|
22
|
+
margin-top: 0 !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@media (max-width: 767px) {
|
|
26
|
+
.card-grid {
|
|
27
|
+
grid-template-columns: 1fr !important;
|
|
28
|
+
gap: 1rem;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@media (min-width: 768px) and (max-width: 1023px) {
|
|
33
|
+
.card-grid {
|
|
34
|
+
grid-template-columns: repeat(min(var(--columns), 2), 1fr);
|
|
35
|
+
gap: 1.5rem;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@media (min-width: 1024px) {
|
|
40
|
+
.card-grid {
|
|
41
|
+
grid-template-columns: repeat(var(--columns), 1fr);
|
|
42
|
+
gap: 1.7rem;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@media (min-width: 1440px) {
|
|
47
|
+
.card-grid {
|
|
48
|
+
grid-template-columns: repeat(min(var(--columns), 4), 1fr);
|
|
49
|
+
gap: 1.8rem;
|
|
50
|
+
margin: 0 auto;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
</style>
|