@kadal/theme-ocean 0.0.0-stage → 0.4.0

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 +64 -2
  3. package/index.tsx +113 -0
  4. package/package.json +99 -4
  5. package/style.css +754 -0
package/README.md CHANGED
@@ -1,3 +1,65 @@
1
- # Temporary Holding Version
1
+ # @kadal/theme-ocean
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
+ **Ocean**, a theme for [Kadal Deck](https://deck.kadal.cc). Kadal's own theme. *Kadal* is Tamil for the sea, and the palette is the one [kadal.cc](https://kadal.cc) dives through: sunlit shallows in the light scheme (foam, sky and deep-sea ink), midnight water in the dark one (twilight blue, bioluminescent cyan, lure amber). Calm gradients for the page, Catamaran for type, Night Owl for code. Made to be a good default for a new deck.
4
+
5
+ ![Ocean: 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-ocean
11
+ ```
12
+
13
+ ```yaml
14
+ ---
15
+ theme: ocean
16
+ themeConfig: # all optional
17
+ accent: "#1d63a8"
18
+ accentDark: "#5ff7ff"
19
+ waves: true
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: Catamaran (text and headings), JetBrains Mono (code), loaded through the theme's `config.fonts`. Code colours: Shiki's night-owl-light / night-owl. To show it beside other themes in the theme menu (<kbd>T</kbd>), list it: `themes: [ocean, 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
+ | `accent` | colour | `#1d63a8` | The accent in the light scheme (links, bullets, the progress bar). |
32
+ | `accentDark` | colour | `#5ff7ff` | The accent in the dark scheme. Without it, a set `accent` is lifted towards white. |
33
+ | `waves` | boolean | `true` | `false` hides the swells along the cover's foot. |
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
+ | `waves` | A cover with the sea moving along the bottom edge. `align: center` centres it. The swells stand still under `prefers-reduced-motion` and in print. |
42
+ | `depth` | A section opener: its number (counted, or `n:`), a label (`depth: "200 m · twilight"`) and a sounding line down the side marking how far into the deck it is. |
43
+
44
+ ## Components
45
+
46
+ | component | what |
47
+ | --- | --- |
48
+ | `<Wave />` | A single swell as a divider, in the accent colour; `flip` turns it over. |
49
+
50
+ ## Preview
51
+
52
+ `preview/deck.mdx` walks through every layout and component (`theme: ../`). In this repository:
53
+
54
+ ```bash
55
+ bun run --filter @kadal/theme-ocean dev # the preview deck, live
56
+ node tools/theme-shots.mjs ocean # screenshots in light and dark, contrast and overflow checks
57
+ ```
58
+
59
+ ## Accessibility and print
60
+
61
+ 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.
62
+
63
+ ## Licence
64
+
65
+ 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,113 @@
1
+ import { type LayoutProps, useDeck, useSlideOptional } from "@kadal/deck";
2
+
3
+ /**
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * Ocean's module: two layouts and a divider. The stylesheet (style.css) styles every built-in
6
+ * layout; these add what a sea-themed deck reaches for.
7
+ *
8
+ * layout: waves a cover with the sea moving along the bottom edge (`align: center` centres
9
+ * it); the swells stand still under prefers-reduced-motion and in print
10
+ * layout: depth a section opener: its number, a label (`depth: "200 m · twilight"`), and a
11
+ * sounding line down the side marking how far into the deck it is
12
+ * <Wave /> a single swell as a divider, in the accent colour
13
+ * ─────────────────────────────────────────────────────────────────────────────
14
+ */
15
+
16
+ const str = (v: unknown) => (typeof v === "string" && v.trim() ? v.trim() : null);
17
+
18
+ /**
19
+ * A swell as an SVG path: `periods` crests across 2880 units (twice the visible width, so a
20
+ * -50% drift loops without a seam), `amp` high, its mean line at `base` from the top of 320.
21
+ */
22
+ function swell(periods: number, amp: number, base: number, phase = 0): string {
23
+ const w = 2880;
24
+ const step = w / (periods * 2);
25
+ let d = `M0 ${base + Math.sin(phase) * amp}`;
26
+ for (let i = 0; i < periods * 2; i++) {
27
+ const x0 = i * step;
28
+ const crest = i % 2 === 0 ? -amp : amp;
29
+ d += ` Q${x0 + step / 2} ${base + crest * 1.6 + Math.sin(phase) * amp * 0.2} ${x0 + step} ${base}`;
30
+ }
31
+ return `${d} L${w} 320 L0 320 Z`;
32
+ }
33
+
34
+ const SWELLS = [swell(4, 22, 120, 0.4), swell(6, 16, 175, 1.2), swell(8, 12, 235, 2.1)];
35
+
36
+ function Waves({ children, frontmatter }: LayoutProps) {
37
+ const center = str(frontmatter.align) === "center";
38
+ return (
39
+ <div className={`deck-layout deck-layout-waves${center ? " is-center" : ""}`}>
40
+ <div className="ocean-waves-body">{children}</div>
41
+ {/* placed, not flowed (deck-absolute): the auto-fit does not count the swells as overflow */}
42
+ <div className="ocean-waves deck-absolute" aria-hidden="true">
43
+ <svg viewBox="0 0 2880 320" preserveAspectRatio="none">
44
+ {SWELLS.map((d, i) => (
45
+ <path key={i} className={`ocean-swell-${i + 1}`} d={d} />
46
+ ))}
47
+ </svg>
48
+ </div>
49
+ </div>
50
+ );
51
+ }
52
+
53
+ /** Which depth opener this is (1-based), counting only `layout: depth` slides before it. */
54
+ function useDepthNumber(): { n: number; at: number } {
55
+ const deck = useDeck();
56
+ const slide = useSlideOptional();
57
+ const index = slide?.meta.index ?? 0;
58
+ const slides = deck.manifest.slides;
59
+ const n = slides.filter((s) => s.index <= index && s.frontmatter.layout === "depth").length;
60
+ return { n: Math.max(1, n), at: slides.length > 1 ? index / (slides.length - 1) : 0 };
61
+ }
62
+
63
+ const TICKS = 21;
64
+
65
+ function Depth({ children, frontmatter }: LayoutProps) {
66
+ const { n, at } = useDepthNumber();
67
+ const label = str(frontmatter.depth);
68
+ const given = frontmatter.n == null ? "" : String(frontmatter.n).trim();
69
+ const number = given || String(n).padStart(2, "0");
70
+ const here = Math.round(at * (TICKS - 1));
71
+ return (
72
+ <div className="deck-layout deck-layout-depth">
73
+ <div className="ocean-depth-number" aria-hidden="true">
74
+ {number}
75
+ </div>
76
+ <div className="ocean-depth-body">
77
+ {label ? <span className="ocean-depth-meta">{label}</span> : null}
78
+ {children}
79
+ </div>
80
+ <div className="ocean-depth-gauge" aria-hidden="true">
81
+ {Array.from({ length: TICKS }, (_, i) => (
82
+ <span key={i} className={i === here ? "is-here" : undefined} />
83
+ ))}
84
+ </div>
85
+ </div>
86
+ );
87
+ }
88
+
89
+ /** A divider: one swell across the column, in the accent colour (`flip` turns it over). */
90
+ function Wave({ flip = false, className }: { flip?: boolean; className?: string }) {
91
+ return (
92
+ <svg
93
+ className={["ocean-wave", className].filter(Boolean).join(" ")}
94
+ viewBox="0 0 240 14"
95
+ preserveAspectRatio="none"
96
+ aria-hidden="true"
97
+ style={flip ? { transform: "scaleY(-1)" } : undefined}
98
+ >
99
+ <path
100
+ d="M2 7 Q 17 -1 32 7 T 62 7 T 92 7 T 122 7 T 152 7 T 182 7 T 212 7 T 238 7"
101
+ fill="none"
102
+ strokeWidth="2.4"
103
+ strokeLinecap="round"
104
+ vectorEffect="non-scaling-stroke"
105
+ />
106
+ </svg>
107
+ );
108
+ }
109
+
110
+ export default {
111
+ layouts: { waves: Waves, depth: Depth },
112
+ components: { Wave },
113
+ };
package/package.json CHANGED
@@ -1,6 +1,101 @@
1
1
  {
2
2
  "name": "@kadal/theme-ocean",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.0",
4
+ "description": "Ocean, a theme for Kadal Deck (@kadal/deck). Kadal's own theme: the sea's palette from sunlit shallows to midnight water, calm gradients and polished type.",
5
+ "keywords": [
6
+ "kadal-theme",
7
+ "kadal-deck",
8
+ "presentation",
9
+ "slides",
10
+ "theme",
11
+ "ocean",
12
+ "sea",
13
+ "kadal",
14
+ "gradient"
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-ocean"
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": "ocean",
53
+ "title": "Ocean",
54
+ "description": "Kadal's own theme: the sea's palette from sunlit shallows to midnight water, calm gradients and polished type.",
55
+ "colorScheme": "both",
56
+ "config": {
57
+ "transition": "fade",
58
+ "fonts": {
59
+ "sans": "Catamaran",
60
+ "mono": "JetBrains Mono",
61
+ "weights": "400,500,600,700,800"
62
+ }
63
+ },
64
+ "themeConfig": {
65
+ "waves": true
66
+ },
67
+ "shiki": {
68
+ "light": "night-owl-light",
69
+ "dark": "night-owl"
70
+ },
71
+ "defaults": {},
72
+ "layouts": [
73
+ "waves",
74
+ "depth"
75
+ ],
76
+ "components": [
77
+ "Wave"
78
+ ]
79
+ }
80
+ },
81
+ "scripts": {
82
+ "dev": "kadal-deck dev -C preview",
83
+ "check": "kadal-deck check -C preview",
84
+ "typecheck": "tsc --noEmit",
85
+ "test": "bun test"
86
+ },
87
+ "peerDependencies": {
88
+ "@kadal/deck": "^0.4.0",
89
+ "react": "^19.2.0"
90
+ },
91
+ "devDependencies": {
92
+ "@kadal/deck": "workspace:*",
93
+ "@types/react": "^19.2.0",
94
+ "@types/react-dom": "^19.2.0",
95
+ "@vitejs/plugin-react": "^6.0.2",
96
+ "react": "^19.2.7",
97
+ "react-dom": "^19.2.7",
98
+ "typescript": "^6.0.3",
99
+ "vite": "^8.0.16"
100
+ }
101
+ }