Skip to content

Commit 413dd66

Browse files
authored
Feature table redesign (#498)
### Preview Online: https://wasm-website-preview.pages.dev/features/ ### Motivation 1. As discussed in #495, the feature table is continuously growing (more runtimes & tools). Some kind of redesign was needed to keep the column count reasonable. 1. The old implementation (mostly written by me) is plain JS that builds the DOM in an ad-hoc way. It has a lot of moving parts tangled together (feature detection, async loading, tooltip logic w/ timers, footnote mappings, etc). It's becoming frustrating to extend, and it's designed to "generate once" which fits poorly for dynamic behavior. A small templating solution would greatly improve maintainability. 1. The current UI relies on Wikipedia-style tooltips for notes, which I now think are a poor fit:. - Every cell has a tooltip that appears on hover and tends to "capture" the cursor when moving between cells. - Having a giant list of every note after the table is unwieldy and unnecessary. It reads like a bibliography, and it's growing in length. - Semantically speaking, the cells and their notes should be strongly associated, contrary to a "reference" relationship. - Keyboard navigation: only cells with footnotes are tabbable, which feels a bit inconsistent. Not sure if this is actually a problem for Assistive Technology users though. ### Design decisions - **Filtering** (addressing motivation 1): this PR uses checkboxes to toggle column categories (`Web Browsers`, `Standalone Runtimes`, `Tools`). While this does the job for now, I'm not super in love with this design and would welcome ideas. - Categories are hard to balance: `Standalone Runtimes` currently dominate while the others are sparse. This would worsen as more runtimes are added. - It's tricky to make the categories balanced. Right now, `Standalone Runtimes` have too many columns and the other two too few. We would still run into the columns problem in the future, when there're more server runtimes added. - Multiple stacked tables isn't great, the page is already very long vertically. - Multiple pages would hurt discoverability and prevent cross-category comparison. And it doesn't address the unbalanced problem. - **Visual style** (addressing motivation 3): heavily "inspired" by MDN's browser compatibility table ([example](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#browser_compatibility)). Their design works really well here. I emulated the look & feel without looking at their code, so I think it should avoid license issues? Otherwise, since their site uses MPL, a file-based copyleft license, we can make the relevant files MPL to be extra safe. - **JS framework** (addressing motivation 2): I used [Alpine.js](https://alpinejs.dev/) as a minimal framework, because it is the only option AFAIK that doesn't require a (JS-based) build step. Our current build process is Ruby-based and hasn't been touched in 8+ years, so I didn't dare to make changes. Let me know if we'd like to explore alternative approaches. ### Current status ~~I'd appreciate early feedback on whether the overall direction looks reasonable. I know large changes can be difficult to review with the project's limited bandwidth. If an incremental path would be preferable, I'm happy to take that route instead. I just don't have a clear idea to do this cleanly under the constraint of the existing code, so suggestions are very welcome.~~ Thanks everyone for the input! This is ready for review. Since `feature.js` is a wholesale rewrite, it's recommended to look at the new file rather than the messy diff.
1 parent bc8ba2d commit 413dd66

File tree

15 files changed

+1328
-740
lines changed

15 files changed

+1328
-740
lines changed

_includes/feature-table.html

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
<link rel="preload" href="/features.json" as="fetch">
2+
<link rel="modulepreload" href="https://unpkg.com/wasm-feature-detect@1/dist/esm/index.js?v=1">
3+
<script type="module" src="/features.js"></script>
4+
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.15/dist/cdn.min.js" defer></script>
5+
6+
The table below aims to track implemented features in popular engines and tools.
7+
You can click on a cell for more information.
8+
9+
<noscript><p>Please enable JavaScript for the table to load.</p></noscript>
10+
11+
<p id="feature-table-loading">
12+
Loading table, please wait&hellip;
13+
<span class="text-secondary">(<a href="https://github.com/WebAssembly/website/issues" target="_blank">report issues</a>)</span>
14+
</p>
15+
16+
<div
17+
id="feature-table"
18+
x-data="data"
19+
x-init="$watch('selectedCategories', (value, oldValue) => onSelectedCategoryChange(value, oldValue))"
20+
x-show="categories.length"
21+
x-cloak
22+
>
23+
<div id="table-actions">
24+
<fieldset>
25+
<legend>Currently showing categories:</legend>
26+
<div id="platform-filters">
27+
<template x-for="category in categoryNames" x-bind:key="category">
28+
<label class="platform-filter" x-id="['platform-filter']">
29+
<input type="checkbox" x-bind:id="$id('platform-filter')" x-bind:value="category" x-model="selectedCategories" />
30+
<div class="checkbox-button text-secondary" x-bind:for="$id('platform-filter')" x-text="category"></div>
31+
</label>
32+
</template>
33+
</div>
34+
</fieldset>
35+
<div>
36+
<a href="https://github.com/WebAssembly/website/issues" target="_blank">Report issues</a>
37+
&bull;
38+
<a href="https://github.com/WebAssembly/website/blob/main/features.json" target="_blank">Contribute data</a>
39+
</div>
40+
</div>
41+
42+
<div id="feature-scroll">
43+
<table aria-label="Feature Status in WebAssembly Platforms" x-bind:style="{ '--num-columns': numColumns }">
44+
<thead>
45+
<tr>
46+
<th class="top-corner"></th>
47+
<template x-for="(numColumns, category) in cellGroupsForRow" x-bind:key="category">
48+
<th
49+
scope="colgroup"
50+
x-bind:id="`col-category-header-${str2id(category)}`"
51+
class="category"
52+
x-bind:colspan="numColumns"
53+
x-bind:style="{ '--num-columns-in-category': numColumns }"
54+
>
55+
<div x-text="category"></div>
56+
</th>
57+
</template>
58+
</tr>
59+
<tr class="platform-header-row">
60+
<th class="top-corner"></th>
61+
<template x-for="platform in cellsForRow(null)" x-bind:key="platform.name">
62+
<th
63+
scope="col"
64+
x-bind:id="`col-header-${str2id(platform.name)}`"
65+
x-bind:headers="`col-category-header-${str2id(platform.category)}`"
66+
>
67+
<template x-if="platform.url">
68+
<a x-bind:href="platform.url" target="_blank">
69+
<template x-if="platform.logo">
70+
<!-- Empty alt trick: https://www.w3.org/WAI/WCAG22/Techniques/html/H2 -->
71+
<img x-bind:src="platform.logo" alt="" x-bind:class="platform.logoClassName">
72+
</template>
73+
<span class="platform-name" x-text="platform.name"></span>
74+
</a>
75+
</template>
76+
<template x-if="!platform.url">
77+
<span>
78+
<span class="platform-name" x-text="platform.name"></span>
79+
</span>
80+
</template>
81+
</th>
82+
</template>
83+
</tr>
84+
</thead>
85+
86+
<template x-for="(featureGroup, i) in featureGroups" x-bind:key="i">
87+
<tbody x-id="['feat-group']">
88+
<tr>
89+
<th scope="colgroup" x-bind:id="$id('feat-group')" x-bind:colspan="numColumns" x-text="featureGroup.name"></th>
90+
</tr>
91+
<template x-for="feature in featureGroup.features" x-bind:key="feature.id">
92+
<tr x-bind:data-feature-id="feature.id" x-id="['feat-row-header']">
93+
<th scope="row" x-bind:id="$id('feat-row-header')" x-bind:headers="$id('feat-group')">
94+
<a x-bind:href="feature.url" x-text="feature.description" target="_blank"></a>
95+
</th>
96+
<template x-for="{ name, status, rendered } in cellsForRow(feature.id)" x-bind:key="name">
97+
<td x-id="['cell-details']" x-bind:headers="`${$id('feat-row-header')} col-header-${str2id(name)}`">
98+
99+
<!-- Cell (click to expand) -->
100+
<button
101+
type="button"
102+
class="cell"
103+
x-bind:class="rendered.className"
104+
x-on:click="toggleFeatureDetails(status)"
105+
x-bind:aria-expanded="String(status?.expanded ?? false)"
106+
x-bind:aria-controls="$id('cell-details')"
107+
>
108+
<div class="icon" x-replace="rendered.cellIcon"></div>
109+
<div x-show="rendered.statusLabel" x-text="rendered.statusLabel"></div>
110+
<template x-if="rendered.note">
111+
<div x-show="rendered.note" class="icon icon-note" x-replace="ICONS['more']"></div>
112+
</template>
113+
</button>
114+
115+
<!-- Expanded details -->
116+
<div class="details" x-bind:id="$id('cell-details')" x-bind:hidden="!status?.expanded" tabindex="0">
117+
<template x-if="status?.expanded">
118+
<ul class="details-inner">
119+
<li class="details-status" x-bind:class="rendered.className">
120+
<div class="icon" x-replace="rendered.noteIcon" aria-hidden="true"></div>
121+
<div x-replace="rendered.detailsLabel"></div>
122+
</li>
123+
<li class="details-note" x-show="rendered.note">
124+
<div class="icon" x-replace="ICONS['asterisk']" aria-hidden="true"></div>
125+
<div class="details-note-line text-secondary" x-replace="rendered.note"></div>
126+
</li>
127+
</ul>
128+
</template>
129+
</div>
130+
131+
</td>
132+
</template>
133+
</tr>
134+
</template>
135+
</tbody>
136+
</template>
137+
</table>
138+
</div>
139+
</div>
140+
141+
<!-- Apache License 2.0, https://github.com/Remix-Design/remixicon -->
142+
<template id="icon-check">
143+
<span class="visually-hidden">Full Support</span>
144+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
145+
<title>Full Support</title>
146+
<path d="M10 15.2 19.2 6l1.4 1.4L10 18l-6.4-6.4L5 10.2Z"/>
147+
</svg>
148+
</template>
149+
<template id="icon-checkbox-circle">
150+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 12a8 8 0 1 1 16 0 8 8 0 0 1-16 0m8-10C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2m5.457 7.457-1.414-1.414L11 13.086l-2.793-2.793-1.414 1.414L11 15.914z"/></svg>
151+
</template>
152+
<template id="icon-close">
153+
<span class="visually-hidden">No Support</span>
154+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
155+
<title>No Support</title>
156+
<path d="m12 10.6 5-5 1.4 1.5-5 4.9 5 5-1.4 1.4-5-5-5 5L5.7 17l5-5-5-5 1.5-1.4z"/>
157+
</svg>
158+
</template>
159+
<template id="icon-close-circle">
160+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20m0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16m0-9.41 2.83-2.83 1.41 1.41L13.41 12l2.83 2.83-1.41 1.41L12 13.41l-2.83 2.83-1.41-1.41L10.59 12 7.76 9.17l1.41-1.41z"/></svg>
161+
</template>
162+
<template id="icon-checkbox-blank-circle">
163+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20m0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16"/></svg>
164+
</template>
165+
<template id="icon-flask">
166+
<span class="visually-hidden">Experimental Support</span>
167+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
168+
<title>Experimental Support</title>
169+
<path d="M15.9994 2v2h-1v3.243c0 1.1575.2512 2.3013.7363 3.3524l4.2813 9.276c.3471.7522.0188 1.6434-.7334 1.9905A1.5 1.5 0 0 1 18.655 22H5.3438c-.8285 0-1.5-.6716-1.5-1.5a1.5 1.5 0 0 1 .138-.6286l4.2813-9.276a8 8 0 0 0 .7363-3.3525V4h-1V2zm-2.6121 8.0012h-2.7758a10 10 0 0 1-.3744 1.0712l-.1581.3611L6.1244 20h11.749l-3.9536-8.5665a10 10 0 0 1-.5325-1.4323m-2.3879-2.7583a10 10 0 0 1-.0288.758h2.0576a10 10 0 0 1-.021-.3639l-.0078-.394V4h-2z"/>
170+
</svg>
171+
</template>
172+
<template id="icon-forbid-2">
173+
<span class="visually-hidden">Not Applicable</span>
174+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
175+
<title>Not Applicable</title>
176+
<path d="M12 22a10 10 0 1 1 0-20 10 10 0 0 1 0 20m0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16m4.9-11.48L8.51 16.9a6 6 0 0 1-1.41-1.41l8.37-8.37a6 6 0 0 1 1.41 1.41"/>
177+
</svg>
178+
</template>
179+
<template id="icon-asterisk">
180+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 3v7.267l6.294-3.633 1 1.732-6.293 3.633 6.293 3.635-1 1.732L13 13.732V21h-2v-7.268l-6.294 3.634-1-1.732L9.999 12 3.706 8.366l1-1.732L11 10.267V3z"/></svg>
181+
</template>
182+
<template id="icon-question-mark">
183+
<span class="visually-hidden">Unknown</span>
184+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-hidden="true">
185+
<title>Unknown</title>
186+
<path d="M24 38a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0-34a12 12 0 0 1 12 12c0 4.3-1.5 6.6-5.3 9.8-3.9 3.3-4.7 4.8-4.7 8.2h-4c0-5 1.6-7.4 6-11.2 3.1-2.6 4-4 4-6.8a8 8 0 1 0-16 0v2h-4v-2A12 12 0 0 1 24 4z"/>
187+
</svg>
188+
</template>
189+
<template id="icon-more">
190+
<span class="visually-hidden">footnote</span>
191+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
192+
<title>More</title>
193+
<path d="M5 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2m14 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2m-7 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2"/>
194+
</svg>
195+
</template>
196+
197+
<template id="icon-loading">
198+
<span class="visually-hidden">Loading</span>
199+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
200+
<title>Loading</title>
201+
<circle fill="#ccc" cx="2" cy="12" r="2"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin=".1"/></circle><circle fill="#ccc" cx="10" cy="12" r="2"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin=".2"/></circle><circle fill="#ccc" cx="18" cy="12" r="2"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin=".3"/></circle>
202+
</svg>
203+
</template>

_includes/header.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
<noscript id="dark-mode-toggle-stylesheets">
1717
<link rel="stylesheet" type="text/css" href="/css/light.css" media="(prefers-color-scheme: light)" />
1818
<link rel="stylesheet" type="text/css" href="/css/dark.css" media="(prefers-color-scheme: dark)" />
19-
<meta name="color-scheme" content="dark light" />
19+
<meta name="color-scheme" content="light dark" />
2020
</noscript>
21+
{% if page.url == "/features/" %}
22+
<link rel="stylesheet" type="text/css" href="/css/feature-table.css" />
23+
{% endif %}
2124
<script src="/js/dark-mode-toggle-stylesheets-loader.min.js"></script>
2225
<script type="module" src="/js/dark-mode-toggle.min.mjs"></script>
2326
<script type="module" src="/js/wasm-compat.js"></script>

0 commit comments

Comments
 (0)