@kadal/theme-swiss 0.0.0-stage → 0.4.3
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/LICENSE +661 -0
- package/README.md +70 -2
- package/index.tsx +114 -0
- package/package.json +101 -4
- package/style.css +723 -0
package/README.md
CHANGED
|
@@ -1,3 +1,71 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kadal/theme-swiss
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Swiss**, a theme for [Kadal Deck](https://deck.kadal.cc). The International Typographic Style for design talks. Huge Inter Tight headings set tight and flush left on a twelve-column grid, heavy black rules, and one signal colour used sparingly. Facts, statements and quotes sit flush left, not centred; a section is the signal colour edge to edge; a running header carries the deck's title, the current section and the page.
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<img src="https://deck.kadal.cc/themes/swiss-light-1.webp" alt="Swiss: the cover, light" width="49%">
|
|
7
|
+
<img src="https://deck.kadal.cc/themes/swiss-dark-2.webp" alt="Swiss: a content slide, dark" width="49%">
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
[All 16 themes](https://deck.kadal.cc/themes/) · [Themes and backgrounds](https://deck.kadal.cc/docs/themes-and-backgrounds/) · [Writing a theme](https://deck.kadal.cc/docs/writing-a-theme/) · [Source](https://github.com/kadalcc/deck/tree/main/packages/theme-swiss)
|
|
11
|
+
|
|
12
|
+
## Use it
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @kadal/theme-swiss
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
---
|
|
20
|
+
theme: swiss
|
|
21
|
+
themeConfig: # all optional
|
|
22
|
+
header: true
|
|
23
|
+
signal: "#d70017"
|
|
24
|
+
signalDark: "#ff3b2f"
|
|
25
|
+
---
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The deck plugin brings the stylesheet and the module in; nothing to import. The prebuilt shell (the hosted builder, published decks) bundles this theme already. Schemes: light and dark. Fonts: Inter Tight (headings), Inter (text), JetBrains Mono (code), loaded through the theme's `config.fonts`. Code colours: Shiki's min-light / vesper. To show it beside other themes in the theme menu (<kbd>T</kbd>), list it: `themes: [swiss, minimal]`.
|
|
29
|
+
|
|
30
|
+
## themeConfig
|
|
31
|
+
|
|
32
|
+
Every key arrives on the deck root as a CSS variable (`accentDark` → `--theme-accent-dark`); the theme reads them with fallbacks, so set only what you change.
|
|
33
|
+
|
|
34
|
+
| key | type | default | what it does |
|
|
35
|
+
| --- | --- | --- | --- |
|
|
36
|
+
| `header` | boolean | `true` | The running header on content slides. `false` turns it off; `header: false` in a slide's frontmatter hides it on that slide. |
|
|
37
|
+
| `signal` | colour | `#d70017` | The one colour (light scheme), and the section slides' ground. |
|
|
38
|
+
| `signalDark` | colour | `#ff3b2f` | The signal on the dark page. Without it, a set `signal` is lifted towards white. |
|
|
39
|
+
|
|
40
|
+
## Layouts
|
|
41
|
+
|
|
42
|
+
Every built-in layout is styled (`default`, `center`, `cover`, `intro`, `section`, `end`, `fact`, `quote`, `statement`, `full`, `two-cols`, `two-cols-header`, `image`, `image-left`, `image-right`, `iframe`, `iframe-left`, `iframe-right`), and the theme adds:
|
|
43
|
+
|
|
44
|
+
| layout | what |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `poster` | One word or number as large as the slide allows (`size: 15em`, `signal: true` for the signal colour); `::meta::` is small print in the top right. |
|
|
47
|
+
| `index` | The slide's list as a grid of numbered cells (`columns:`, default 3). A **bold** opening is the cell's title. |
|
|
48
|
+
| `grid` | A header across, then each named slot a column under a heavy rule; the columns follow the number of slots (2 to 5), or `columns:`. |
|
|
49
|
+
|
|
50
|
+
## Components
|
|
51
|
+
|
|
52
|
+
| component | what |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `<Rule label right signal />` | A heavy rule with a label on the left and one on the right; `signal` colours it. |
|
|
55
|
+
|
|
56
|
+
## Preview
|
|
57
|
+
|
|
58
|
+
`preview/deck.mdx` walks through every layout and component (`theme: ../`). In this repository:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bun run --filter @kadal/theme-swiss dev # the preview deck, live
|
|
62
|
+
node tools/theme-shots.mjs swiss # screenshots in light and dark, contrast and overflow checks
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Accessibility and print
|
|
66
|
+
|
|
67
|
+
Body and muted text meet WCAG AA (4.5:1) on the page and on cards in every scheme the theme draws (checked by `tools/theme-shots.mjs`). Anything that moves stands still under `prefers-reduced-motion` and on a still copy; printed pages and exports drop shadows and glows.
|
|
68
|
+
|
|
69
|
+
## Licence
|
|
70
|
+
|
|
71
|
+
AGPL-3.0-or-later, like the engine (see LICENSE); a commercial licence is available — see [LICENSING](https://github.com/kadalcc/deck/blob/main/LICENSING.md).
|
package/index.tsx
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
|
|
3
|
+
import { type LayerProps, type LayoutProps, useDeck } from "@kadal/deck";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
* Swiss's module: a running header, three grid layouts and a rule.
|
|
8
|
+
*
|
|
9
|
+
* the header a slide-top layer on content slides: the deck's title, the current
|
|
10
|
+
* section (the last `layout: section` slide's heading) and the page, under a
|
|
11
|
+
* heavy rule. `themeConfig.header: false` turns it off; `header: false` in a
|
|
12
|
+
* slide's frontmatter hides it there.
|
|
13
|
+
* layout: poster one word or number as large as the slide allows (`size: 15em`,
|
|
14
|
+
* `signal: true` for the signal colour); `::meta::` is small print top right
|
|
15
|
+
* layout: index the slide's list as a grid of numbered cells (`columns: 3`)
|
|
16
|
+
* layout: grid a header across, then each `::slot::` a column under a heavy rule
|
|
17
|
+
* (`columns:` defaults to the number of slots)
|
|
18
|
+
* <Rule> a heavy rule with a label on the left and one on the right
|
|
19
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const HEADER_LAYOUTS = new Set([
|
|
23
|
+
"default",
|
|
24
|
+
"center",
|
|
25
|
+
"two-cols",
|
|
26
|
+
"two-cols-header",
|
|
27
|
+
"index",
|
|
28
|
+
"grid",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
function Header({ slide, page, total, layout, frontmatter }: LayerProps) {
|
|
32
|
+
const deck = useDeck();
|
|
33
|
+
if (deck.config.themeConfig.header === false || frontmatter.header === false) return null;
|
|
34
|
+
if (!HEADER_LAYOUTS.has(layout)) return null;
|
|
35
|
+
const index = slide?.index ?? 0;
|
|
36
|
+
const section = [...deck.manifest.slides]
|
|
37
|
+
.reverse()
|
|
38
|
+
.find((s) => s.index <= index && s.frontmatter.layout === "section");
|
|
39
|
+
const pad = (n: number) => String(n).padStart(2, "0");
|
|
40
|
+
return (
|
|
41
|
+
<div className="swiss-header" aria-hidden="true">
|
|
42
|
+
<span className="swiss-header-title">{deck.config.title}</span>
|
|
43
|
+
<span className="swiss-header-section">{section?.title ?? ""}</span>
|
|
44
|
+
<span className="swiss-header-page">
|
|
45
|
+
<b>{pad(page)}</b> / {pad(total)}
|
|
46
|
+
</span>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const num = (v: unknown) =>
|
|
52
|
+
typeof v === "number" ? v : typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : null;
|
|
53
|
+
const str = (v: unknown) => (typeof v === "string" && v.trim() ? v.trim() : null);
|
|
54
|
+
|
|
55
|
+
function Poster({ children, frontmatter }: LayoutProps) {
|
|
56
|
+
const size =
|
|
57
|
+
str(frontmatter.size) ?? (num(frontmatter.size) ? `${num(frontmatter.size)}em` : null);
|
|
58
|
+
return (
|
|
59
|
+
<div
|
|
60
|
+
className={`deck-layout deck-layout-poster${frontmatter.signal ? " is-signal" : ""}`}
|
|
61
|
+
style={size ? ({ "--swiss-poster-size": size } as CSSProperties) : undefined}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function Index({ children, frontmatter }: LayoutProps) {
|
|
69
|
+
const cols = num(frontmatter.columns);
|
|
70
|
+
return (
|
|
71
|
+
<div
|
|
72
|
+
className="deck-layout deck-layout-index"
|
|
73
|
+
style={cols ? ({ "--swiss-index-cols": cols } as CSSProperties) : undefined}
|
|
74
|
+
>
|
|
75
|
+
{children}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function Grid({ children, frontmatter }: LayoutProps) {
|
|
81
|
+
// Without `columns:`, style.css counts the slots (two to five) with :has().
|
|
82
|
+
const cols = num(frontmatter.columns);
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
className="deck-layout deck-layout-grid"
|
|
86
|
+
style={cols ? ({ "--swiss-grid-cols": cols } as CSSProperties) : undefined}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function Rule({
|
|
94
|
+
label,
|
|
95
|
+
right,
|
|
96
|
+
signal = false,
|
|
97
|
+
}: {
|
|
98
|
+
label?: string;
|
|
99
|
+
right?: string;
|
|
100
|
+
signal?: boolean;
|
|
101
|
+
}) {
|
|
102
|
+
return (
|
|
103
|
+
<div className={`swiss-rule${signal ? " is-signal" : ""}`} role="separator">
|
|
104
|
+
{label ? <span>{label}</span> : null}
|
|
105
|
+
{right ? <span>{right}</span> : null}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default {
|
|
111
|
+
layouts: { poster: Poster, index: Index, grid: Grid },
|
|
112
|
+
components: { Rule },
|
|
113
|
+
layers: { "slide-top": Header },
|
|
114
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,103 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kadal/theme-swiss",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"description": "Swiss, a theme for Kadal Deck (@kadal/deck). A bold International-style theme for design talks: huge grotesk headings on a strict twelve-column grid, one signal colour.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"kadal-theme",
|
|
7
|
+
"kadal-deck",
|
|
8
|
+
"presentation",
|
|
9
|
+
"slides",
|
|
10
|
+
"theme",
|
|
11
|
+
"swiss",
|
|
12
|
+
"grid",
|
|
13
|
+
"design",
|
|
14
|
+
"grotesk"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://deck.kadal.cc/themes/",
|
|
17
|
+
"funding": {
|
|
18
|
+
"type": "github",
|
|
19
|
+
"url": "https://github.com/sponsors/pmithunish"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/kadalcc/deck.git",
|
|
24
|
+
"directory": "packages/theme-swiss"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/kadalcc/deck/issues"
|
|
28
|
+
},
|
|
29
|
+
"license": "AGPL-3.0-or-later",
|
|
30
|
+
"author": "Kadal <hello@kadal.cc> (https://kadal.cc)",
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": [
|
|
33
|
+
"*.css"
|
|
34
|
+
],
|
|
35
|
+
"files": [
|
|
36
|
+
"style.css",
|
|
37
|
+
"index.tsx",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./index.tsx",
|
|
43
|
+
"./style.css": "./style.css",
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
48
|
+
"provenance": true
|
|
49
|
+
},
|
|
50
|
+
"kadal": {
|
|
51
|
+
"theme": {
|
|
52
|
+
"name": "swiss",
|
|
53
|
+
"title": "Swiss",
|
|
54
|
+
"description": "A bold International-style theme for design talks: huge grotesk headings on a strict twelve-column grid, one signal colour.",
|
|
55
|
+
"colorScheme": "both",
|
|
56
|
+
"config": {
|
|
57
|
+
"transition": "fade",
|
|
58
|
+
"fonts": {
|
|
59
|
+
"heading": "Inter Tight",
|
|
60
|
+
"sans": "Inter",
|
|
61
|
+
"mono": "JetBrains Mono",
|
|
62
|
+
"weights": "400,500,700,800"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"themeConfig": {
|
|
66
|
+
"header": true
|
|
67
|
+
},
|
|
68
|
+
"shiki": {
|
|
69
|
+
"light": "min-light",
|
|
70
|
+
"dark": "vesper"
|
|
71
|
+
},
|
|
72
|
+
"defaults": {},
|
|
73
|
+
"layouts": [
|
|
74
|
+
"poster",
|
|
75
|
+
"index",
|
|
76
|
+
"grid"
|
|
77
|
+
],
|
|
78
|
+
"components": [
|
|
79
|
+
"Rule"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"dev": "kadal-deck dev -C preview",
|
|
85
|
+
"check": "kadal-deck check -C preview",
|
|
86
|
+
"typecheck": "tsc --noEmit",
|
|
87
|
+
"test": "bun test"
|
|
88
|
+
},
|
|
89
|
+
"peerDependencies": {
|
|
90
|
+
"@kadal/deck": "^0.4.3",
|
|
91
|
+
"react": "^19.2.0"
|
|
92
|
+
},
|
|
93
|
+
"devDependencies": {
|
|
94
|
+
"@kadal/deck": "workspace:*",
|
|
95
|
+
"@types/react": "^19.2.0",
|
|
96
|
+
"@types/react-dom": "^19.2.0",
|
|
97
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
98
|
+
"react": "^19.2.7",
|
|
99
|
+
"react-dom": "^19.2.7",
|
|
100
|
+
"typescript": "^6.0.3",
|
|
101
|
+
"vite": "^8.0.16"
|
|
102
|
+
}
|
|
103
|
+
}
|