@kadal/theme-swiss 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.
Files changed (5) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +65 -2
  3. package/index.tsx +114 -0
  4. package/package.json +101 -4
  5. package/style.css +723 -0
package/README.md CHANGED
@@ -1,3 +1,66 @@
1
- # Temporary Holding Version
1
+ # @kadal/theme-swiss
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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
+ ![Swiss: the cover, a content slide, code and the theme's own layout](./screenshot.jpg)
6
+
7
+ ## Use it
8
+
9
+ ```bash
10
+ npm install @kadal/theme-swiss
11
+ ```
12
+
13
+ ```yaml
14
+ ---
15
+ theme: swiss
16
+ themeConfig: # all optional
17
+ header: true
18
+ signal: "#d70017"
19
+ signalDark: "#ff3b2f"
20
+ ---
21
+ ```
22
+
23
+ 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]`.
24
+
25
+ ## themeConfig
26
+
27
+ 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.
28
+
29
+ | key | type | default | what it does |
30
+ | --- | --- | --- | --- |
31
+ | `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. |
32
+ | `signal` | colour | `#d70017` | The one colour (light scheme), and the section slides' ground. |
33
+ | `signalDark` | colour | `#ff3b2f` | The signal on the dark page. Without it, a set `signal` is lifted towards white. |
34
+
35
+ ## Layouts
36
+
37
+ 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:
38
+
39
+ | layout | what |
40
+ | --- | --- |
41
+ | `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. |
42
+ | `index` | The slide's list as a grid of numbered cells (`columns:`, default 3). A **bold** opening is the cell's title. |
43
+ | `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:`. |
44
+
45
+ ## Components
46
+
47
+ | component | what |
48
+ | --- | --- |
49
+ | `<Rule label right signal />` | A heavy rule with a label on the left and one on the right; `signal` colours it. |
50
+
51
+ ## Preview
52
+
53
+ `preview/deck.mdx` walks through every layout and component (`theme: ../`). In this repository:
54
+
55
+ ```bash
56
+ bun run --filter @kadal/theme-swiss dev # the preview deck, live
57
+ node tools/theme-shots.mjs swiss # screenshots in light and dark, contrast and overflow checks
58
+ ```
59
+
60
+ ## Accessibility and print
61
+
62
+ 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.
63
+
64
+ ## Licence
65
+
66
+ 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.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.2",
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/docs/",
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": "Mithunish Prabhakaran <pmithunish@gmail.com>",
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.2",
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
+ }