Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions apps/tutorial/app/components/selection.gts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { service } from '@ember/service';
import FaIcon from '@fortawesome/ember-fontawesome/components/fa-icon';
import { faBars } from '@fortawesome/free-solid-svg-icons';
import { isCollection } from 'kolay';
import { isNotHidden, titleize } from 'tutorial/utils';
import { isNotHidden, lessonPath, titleize } from 'tutorial/utils';

import type RouterService from '@ember/routing/router-service';
import type DocsService from 'tutorial/services/docs';
Expand All @@ -32,10 +32,8 @@ export class Selection extends Component {
this.router.transitionTo(event.target.value);
};

isSelected = (group: { path: string }, tutorial: { path: string }) => {
const fullPath = `/${group.path}/${tutorial.path}`;

return this.docs.currentPath === fullPath;
isSelected = (tutorial: Parameters<typeof lessonPath>[0]) => {
return this.docs.currentPath === lessonPath(tutorial);
};

<template>
Expand Down Expand Up @@ -71,8 +69,8 @@ export class Selection extends Component {
{{#if (isNotHidden tutorial)}}

<option
value="/{{group.path}}/{{tutorial.path}}"
selected={{this.isSelected group tutorial}}
value={{lessonPath tutorial}}
selected={{this.isSelected tutorial}}
>
{{titleize tutorial.name}}
</option>
Expand Down
3 changes: 2 additions & 1 deletion apps/tutorial/app/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export default class Router extends EmberRouter {
}

Router.map(function () {
addRoutes(this);
// scoped mount: the 'docs' group serves from the root URL space
addRoutes(this, 'docs');
});
1 change: 0 additions & 1 deletion apps/tutorial/app/routes/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export default class ApplicationRoute extends Route {
const highlighter = await createShiki();

const manifest = await setupKolay(this, {
resolve: {},
rehypePlugins: [
[
rehypeShikiFromHighlighter,
Expand Down
11 changes: 9 additions & 2 deletions apps/tutorial/app/services/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { cached, tracked } from '@glimmer/tracking';
import Service, { service } from '@ember/service';

import { docsManager } from 'kolay';
import { lessonPath } from 'tutorial/utils';

import type Selected from './selected';
import type RouterService from '@ember/routing/router-service';
Expand All @@ -25,6 +26,12 @@ export default class DocsService extends Service {
return this.docs.tree ?? {};
}

get firstLesson(): string | undefined {
const first = this.tutorials[0];

return first ? lessonPath(first) : undefined;
}

get showAnswer() {
return this.router.currentRoute?.queryParams?.['showAnswer'] === '1';
}
Expand All @@ -40,11 +47,11 @@ export default class DocsService extends Service {
};

get currentPath(): string | undefined {
if (!this.router.currentURL) return this.tutorials[0]?.path;
if (!this.router.currentURL) return this.firstLesson;

const [path] = this.router.currentURL.split('?');

return path && path !== '/' ? path : this.tutorials[0]?.path;
return path && path !== '/' ? path : this.firstLesson;
}

toggleProse = () => {
Expand Down
8 changes: 4 additions & 4 deletions apps/tutorial/app/services/selected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Compiled as MarkdownToHTML } from 'kolay';
import { keepLatest } from 'reactiveweb/keep-latest';
import { link } from 'reactiveweb/link';
import { RemoteData } from 'reactiveweb/remote-data';
import { nextPage } from 'tutorial/utils';
import { lessonPath, nextPage } from 'tutorial/utils';

import type DocsService from './docs';
import type RouterService from '@ember/routing/router-service';
Expand Down Expand Up @@ -117,8 +117,8 @@ export default class Selected extends Service {
}

#findByPath = (path: string) => {
const prosePath = `${path}/prose.md`;

return this.docs.tutorials.find((tutorial) => tutorial.path === prosePath);
return this.docs.tutorials.find(
(tutorial) => lessonPath(tutorial) === path
);
};
}
55 changes: 36 additions & 19 deletions apps/tutorial/app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,39 @@ import type { Collection, Page } from 'kolay';

export const not = (x: unknown) => !x;

/**
* The manifest's page paths live under the 'docs' group
* (e.g. /docs/1-introduction/1-basics/prose.md), but the app's URLs are
* the lesson directories at the root (e.g. /1-introduction/1-basics) —
* the group is mounted at the root via addRoutes(this, 'docs').
*/
export function lessonPath(item: Page | Collection): string {
return item.appRelativePath
.replace(/^\/docs/, '')
.replace(/\/prose\.md$/, '');
}

/**
* keyed-each-blocks is only shown in dev builds.
* Pending: https://github.com/emberjs/ember.js/issues/20419
*/
const isProdOnlyHidden = (path: string) =>
import.meta.env.PROD && path.includes('keyed-each-blocks');

export function isHidden(page: Page | Collection) {
// Only lesson directories (via their prose.md) are tutorial entries.
// Stray .md files next to the lesson directories have no prompt/answer
// and never had manifest entries before the kolay rework.
if (!isCollection(page) && !page.path.endsWith('/prose.md')) return true;

if (location.href.includes('showHidden')) return false;

if (isCollection(page)) {
return page.path.startsWith('x-');
}
const path = isCollection(page) ? page.path : lessonPath(page);

return page.path.startsWith('/x-');
return (
path.split('/').some((segment) => segment.startsWith('x-')) ||
isProdOnlyHidden(path)
);
}

export function isNotHidden(page: Page | Collection) {
Expand All @@ -30,9 +55,9 @@ export function nextPage(
}

if (found) {
preload(tutorial.path);
preload(lessonPath(tutorial));

return unprose(tutorial.path);
return lessonPath(tutorial);
}

if (current?.path && current.path === tutorial.path) {
Expand All @@ -43,27 +68,19 @@ export function nextPage(
return;
}

function unprose(prosePath: string | undefined) {
if (!prosePath) return;

return prosePath.replace(/\/prose.md$/, '');
}

/**
* To help reduce load time between chapters, we'll load
* the next and previous documents for each page
*/
async function preload(prosePath?: string) {
if (!prosePath) return;
async function preload(path?: string) {
if (!path) return;

await Promise.resolve();

const path = unprose(prosePath);

await Promise.all([
fetch(`/docs/${path}/prose.md`),
fetch(`/docs/${path}/prompt.gjs`),
fetch(`/docs/${path}/answer.gjs`),
fetch(`/docs${path}/prose.md`),
fetch(`/docs${path}/prompt.gjs`),
fetch(`/docs${path}/answer.gjs`),
]);
}

Expand Down
4 changes: 3 additions & 1 deletion apps/tutorial/tests/application/visitable-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import { tmpData } from './tmp';

import type { Manifest } from 'kolay';

const manifest = tmpData as Manifest;
// tmpData is a snapshot of the pre-rework manifest shape; the test only
// uses it to enumerate lesson URLs, which are unchanged.
const manifest = tmpData as unknown as Manifest;

module('every tutorial chapter', function (hooks) {
setupApplicationTest(hooks);
Expand Down
4 changes: 4 additions & 0 deletions apps/tutorial/tests/helpers/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ function makeDocsTree(treeData: [string, string[]][]) {

const page = {
path: tutorialPath,
// as in the real manifest: the 'docs' group prefixes appRelativePath
appRelativePath: `/docs/${groupPath}/${tutorialPath}`,
name: tutorialName,
cleanedName: tutorialName.replace(/-/g, ' '),
pages: [
{
path: prosePath,
appRelativePath: `/docs${prosePath}`,
name: 'prose',
groupName: tutorialName.replace(/-/g, ' '),
cleanedName: 'prose',
Expand All @@ -42,6 +45,7 @@ function makeDocsTree(treeData: [string, string[]][]) {

const group = {
path: groupPath,
appRelativePath: `/docs/${groupPath}`,
name: groupName,
cleanedName: groupName.replace(/-/g, ' '),
pages: groupPages,
Expand Down
31 changes: 15 additions & 16 deletions apps/tutorial/vite.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { ember, extensions } from '@embroider/vite';

import { babel } from '@rollup/plugin-babel';
import { kolay } from 'kolay/vite';
import { docs } from 'kolay/vite';
import { defineConfig } from 'vite';

export default defineConfig(
({ mode /* command, isSsrBuild, isPreview */ }) => ({
(/* { mode, command, isSsrBuild, isPreview } */) => ({
build: {
sourcemap: true,
minify: 'terser',
/**
* Vite's default cssTarget predates light-dark(), so lightningcss
* rewrites it into var(--lightningcss-light/dark) space toggles whose
* :root definitions don't survive chunking, invalidating the
* declarations (kolay ships light-dark() colors). These targets
* support light-dark() natively, so it ships as authored.
*/
cssTarget: ['chrome123', 'firefox120', 'safari17.5'],
},
resolve: {
extensions,
Expand All @@ -17,29 +25,20 @@ export default defineConfig(
postcss: './config/postcss.config.mjs',
},
optimizeDeps: {
// a wasm-providing dependency
exclude: [
// a wasm-providing dependency
'content-tag',
// 'ember-repl'
// stateful: the scoped-route registry must be a single module
// instance between the router (addRoutes) and the docs service
'kolay',
],
// for top-level-await, etc
esbuildOptions: {
target: 'esnext',
},
},
plugins: [
kolay({
src: 'public/docs',
/**
* Pending: https://github.com/emberjs/ember.js/issues/20419
*/
exclude: mode === 'production' ? [/^x-/, 'keyed-each-blocks'] : [],
/**
* This project has convention a based manifest so we only need directories
*/
onlyDirectories: true,
packages: [],
}),
docs('docs', { src: import.meta.resolve('./public/docs') }),
ember(),
babel({
babelHelpers: 'runtime',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"object.values": "npm:@nolyfill/object.values@^1",
"reactiveweb": "1.9.1",
"@codemirror/view": "6.39.12",
"kolay": "github:universal-ember/kolay#dist",
"kolay>ember-repl": "^8.0.0",
"side-channel": "npm:@nolyfill/side-channel@^1",
"string.prototype.matchall": "npm:@nolyfill/string.prototype.matchall@^1",
Expand Down
Loading
Loading