Skip to content

Commit fd7ff85

Browse files
authored
Merge pull request #317 from knockout/docs/landing-redesign
Refine tko.io landing page
2 parents fa97bc4 + 0e1e8de commit fd7ff85

5 files changed

Lines changed: 91 additions & 48 deletions

File tree

.github/workflows/test-headless.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ on:
88
jobs:
99
test:
1010
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
browser: [chromium, firefox, webkit]
1115
container:
1216
image: mcr.microsoft.com/playwright:v1.59.1-noble
1317

@@ -33,4 +37,4 @@ jobs:
3337
run: bunx vitest run
3438
env:
3539
HOME: /root
36-
VITEST_BROWSERS: chromium,firefox,webkit
40+
VITEST_BROWSERS: ${{ matrix.browser }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ builds/**/meta
3737
test-results/
3838
.claude/worktrees/
3939
__screenshots__
40+
.dts-tmp/
41+
.nx/
42+
.vitest-attachments/

tko.io/public/examples/honeycomb.html

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -557,34 +557,54 @@ <h1>Honeycomb</h1>
557557
lastKey: ko.observable(null),
558558
activeSource: null,
559559
activeNeighbors: [],
560+
_pendingHover: null,
561+
_hoverRaf: 0,
562+
_clickRaf: 0,
560563
hoverCell(cell) {
561564
if (!cell.interactive || cell.key === viewModel.lastKey()) return true
562565

563-
if (viewModel.activeSource) {
564-
viewModel.activeSource.source(false)
565-
}
566-
viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false))
566+
viewModel._pendingHover = cell
567+
if (!viewModel._hoverRaf) {
568+
viewModel._hoverRaf = requestAnimationFrame(() => {
569+
viewModel._hoverRaf = 0
570+
const target = viewModel._pendingHover
571+
if (!target) return
572+
573+
if (viewModel.activeSource) {
574+
viewModel.activeSource.source(false)
575+
}
576+
viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false))
567577

568-
viewModel.lastKey(cell.key)
569-
viewModel.activeSource = cell
570-
viewModel.activeNeighbors = cell.neighbors
578+
viewModel.lastKey(target.key)
579+
viewModel.activeSource = target
580+
viewModel.activeNeighbors = target.neighbors
571581

572-
cell.source(true)
573-
cell.neighbors.forEach(neighbor => neighbor.neighbor(true))
582+
target.source(true)
583+
target.neighbors.forEach(neighbor => neighbor.neighbor(true))
574584

575-
viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible())
576-
viewModel.obsCount(viewModel.obsCount() + cell.neighbors.length)
585+
viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible())
586+
viewModel.obsCount(viewModel.obsCount() + target.neighbors.length)
587+
})
588+
}
577589
return true
578590
},
579591
clickCell(cell) {
580592
if (!cell.interactive) return true
581593

594+
if (viewModel._clickRaf) {
595+
cancelAnimationFrame(viewModel._clickRaf)
596+
viewModel._clickRaf = 0
597+
}
598+
582599
const queue = buildWaterfallQueue(cell, cells)
583600
let index = 0
584601
const batchSize = 24
585602

586603
function advanceBurst() {
587-
if (index >= queue.length) return
604+
if (index >= queue.length) {
605+
viewModel._clickRaf = 0
606+
return
607+
}
588608

589609
let touched = 0
590610
while (index < queue.length && touched < batchSize) {
@@ -604,10 +624,10 @@ <h1>Honeycomb</h1>
604624

605625
viewModel.vdomCount(viewModel.vdomCount() + touched * viewModel.totalVisible())
606626
viewModel.obsCount(viewModel.obsCount() + touched)
607-
requestAnimationFrame(advanceBurst)
627+
viewModel._clickRaf = requestAnimationFrame(advanceBurst)
608628
}
609629

610-
requestAnimationFrame(advanceBurst)
630+
viewModel._clickRaf = requestAnimationFrame(advanceBurst)
611631
return true
612632
}
613633
}

tko.io/src/content/docs/index.mdx

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ description: Modern Knockout — reactive data binding and UI templating with ze
66
import { Tabs, TabItem } from '@astrojs/starlight/components';
77

88
<div class="landing-hero">
9-
<p class="landing-kicker">TKO v4.0.1</p>
10-
<h2>Modern Knockout, clarified</h2>
9+
<h2 class="landing-version">TKO v4.0.1</h2>
10+
<p class="landing-kicker">Modern Knockout, clarified</p>
1111
<p class="landing-lede">Reactive data binding and UI templating with zero runtime dependencies. Start with the package you need and move from overview to working bindings.</p>
1212
<div class="landing-actions">
1313
<a class="landing-button landing-button--primary" href="/bindings/">Start with bindings</a>
@@ -17,50 +17,53 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
1717

1818
## Quick start
1919

20-
### Script tag (global)
20+
### Browser
2121

22-
```html
23-
<script src="https://cdn.jsdelivr.net/npm/@tko/build.knockout/dist/browser.min.js"></script>
24-
<script>
25-
const ko = globalThis.ko
26-
</script>
27-
```
28-
29-
### ES module (browser)
30-
31-
```html
32-
<script type="module">
33-
import ko from 'https://esm.run/@tko/build.knockout'
34-
const name = ko.observable('TKO')
35-
</script>
36-
```
22+
<Tabs syncKey="script">
23+
<TabItem label="ES module">
24+
```html
25+
<script type="module">
26+
import ko from 'https://esm.run/@tko/build.reference'
27+
const name = ko.observable('TKO')
28+
</script>
29+
```
30+
</TabItem>
31+
<TabItem label="Classic script">
32+
```html
33+
<script src="https://cdn.jsdelivr.net/npm/@tko/build.reference/dist/browser.min.js"></script>
34+
<script>
35+
const ko = globalThis.tko
36+
</script>
37+
```
38+
</TabItem>
39+
</Tabs>
3740

3841
### Package manager
3942

4043
<Tabs syncKey="pkg">
4144
<TabItem label="npm">
4245
```sh
43-
npm install @tko/build.knockout
46+
npm install @tko/build.reference
4447
```
4548
</TabItem>
4649
<TabItem label="bun">
4750
```sh
48-
bun add @tko/build.knockout
51+
bun add @tko/build.reference
4952
```
5053
</TabItem>
5154
<TabItem label="pnpm">
5255
```sh
53-
pnpm add @tko/build.knockout
56+
pnpm add @tko/build.reference
5457
```
5558
</TabItem>
5659
<TabItem label="yarn">
5760
```sh
58-
yarn add @tko/build.knockout
61+
yarn add @tko/build.reference
5962
```
6063
</TabItem>
6164
</Tabs>
6265

63-
For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
66+
For Knockout 3.x compatibility, use `@tko/build.knockout` instead.
6467

6568
## First binding example
6669

@@ -73,25 +76,26 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
7376
<p>Hello, <strong data-bind="text: name"></strong>.</p>
7477
</div>
7578

76-
<script src="https://cdn.jsdelivr.net/npm/@tko/build.knockout/dist/browser.min.js"></script>
79+
<script src="https://cdn.jsdelivr.net/npm/@tko/build.reference/dist/browser.min.js"></script>
7780
<script>
81+
const ko = globalThis.tko
7882
ko.applyBindings({ name: ko.observable('TKO') }, document.getElementById('app'))
7983
</script>
8084
```
8185

8286
## Choose a build
8387

8488
<div class="landing-grid">
85-
<a class="landing-card" href="/bindings/">
86-
<span class="landing-card__eyebrow">Recommended for migrations</span>
87-
<h3><code>@tko/build.knockout</code></h3>
88-
<p>Compatibility-focused. Closest match to a traditional Knockout application. Includes `data-bind` and `foreach`.</p>
89-
</a>
9089
<a class="landing-card" href="/advanced/provider/">
91-
<span class="landing-card__eyebrow">Recommended for new projects</span>
90+
<span class="landing-card__eyebrow">Recommended</span>
9291
<h3><code>@tko/build.reference</code></h3>
9392
<p>Modern path with TSX, `ko-*` attributes, native provider, and strict equality in expressions.</p>
9493
</a>
94+
<a class="landing-card" href="/3to4/">
95+
<span class="landing-card__eyebrow">Knockout 3.x migrations</span>
96+
<h3><code>@tko/build.knockout</code></h3>
97+
<p>Compatibility-focused. Drop-in replacement for existing Knockout applications.</p>
98+
</a>
9599
</div>
96100

97101
## What stays familiar
@@ -118,6 +122,11 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
118122
<h3>Components</h3>
119123
<p>Reusable UI, loading strategies, and component architecture.</p>
120124
</a>
125+
<a class="landing-card" href="/examples/">
126+
<span class="landing-card__eyebrow">See it in action</span>
127+
<h3>Examples</h3>
128+
<p>Interactive demos showing observable updates, dependency graphs, and reactive state.</p>
129+
</a>
121130
</div>
122131

123132
## Community

tko.io/src/styles/tko.css

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ header {
128128

129129
.sidebar,
130130
.right-sidebar-panel,
131-
.content-panel,
132-
.sidebar-pane {
131+
.content-panel {
133132
background: transparent;
134133
}
135134

@@ -258,7 +257,15 @@ header {
258257
color: var(--sl-color-text-accent);
259258
}
260259

261-
.landing-hero h2 {
260+
.landing-hero .landing-version {
261+
margin: 0 0 0.3rem;
262+
font-family: var(--tko-font-display);
263+
font-size: clamp(2rem, 5vw, 3.2rem);
264+
font-weight: 700;
265+
color: var(--sl-color-white);
266+
}
267+
268+
.landing-hero h2:not(.landing-version) {
262269
margin: 0;
263270
max-width: 11ch;
264271
font-size: clamp(1.55rem, 3.7vw, 2.55rem);

0 commit comments

Comments
 (0)