Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Title Context #1172

Merged
merged 19 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
158 changes: 98 additions & 60 deletions src/lib/layouts/DocsTutorial.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,103 @@
import { Feedback } from '$lib/components';
import type { Tutorial } from '$markdoc/layouts/Tutorial.svelte';
import type { TocItem } from './DocsArticle.svelte';
import Heading from '$markdoc/nodes/Heading.svelte';
import { onMount } from 'svelte';

export let title: string;
export let toc: Array<TocItem>;
export let currentStep: number;
export let back: string;
export let date: string;

export let tutorials: Array<Tutorial>;

const firstStepItem = tutorials[0];
ItzNotABug marked this conversation as resolved.
Show resolved Hide resolved
// currentStep starts from 1, the arrays start from 0.
const currentStepItem = (tutorials[currentStep - 1] ?? firstStepItem);

$: nextStep = tutorials.find((tutorial) => tutorial.step === currentStep + 1);
$: prevStep = tutorials.find((tutorial) => tutorial.step === currentStep - 1);

// `any` for compatibility with reactive variables.
function getCorrectTitle(tutorial: any | Tutorial, checkAt: number): string {
ItzNotABug marked this conversation as resolved.
Show resolved Hide resolved
if (tutorial.step === checkAt) {
return 'Introduction';
} else {
return tutorial.title;
}
}

let slotContent: HTMLElement | null = null;

onMount(() => {
if (!slotContent) return;

// dynamically modify all `label` headers to `body`.
slotContent.querySelectorAll<HTMLHeadingElement>('h2.web-label').forEach(header => {
header.classList.replace('web-label', 'web-main-body-500');
});
});
</script>

<main class="contents" id="main">
<article class="web-article contents">
<header class="web-article-header">
<div class="web-article-header-start web-u-cross-start flex flex-col">
<button class="web-icon-button web-is-only-mobile" aria-label="previous page">
<span class="icon-cheveron-left" aria-hidden="true" />
</button>
<ul class="web-metadata text-caption">
<slot name="metadata" />
</ul>
<div class="relative flex items-center">
{#if back}
<a
href={back}
class="
web-button is-text is-only-icon web-items-center web-u-size-40
web-u-translate-x-negative absolute top-0"
aria-label="previous page"
>
<span
class="icon-cheveron-left web-u-font-size-24 text-primary web-is-not-mobile"
aria-hidden="true"
/>
</a>
<div class="web-article-header-start u-flex-vertical web-u-cross-start">
<ul class="web-metadata web-caption-400">
{#if currentStepItem.difficulty}
<li>{currentStepItem.difficulty}</li>
{/if}
{#if currentStepItem.readtime}
<li>{currentStepItem.readtime} min</li>
{/if}
<h1 class="text-title font-aeonik-pro">{title}</h1>
</ul>
<div class="u-position-relative u-flex u-cross-center">
<h1 class="web-title">{firstStepItem.title}</h1>
</div>
</div>
<div class="web-article-header-end" />
</header>
<div class="web-article-content">
<slot />
<div class="flex justify-between">
{#if prevStep}
<a href={prevStep.href} class="web-button is-text">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text-sub-body font-medium">
Step {prevStep.step}<span class="web-is-not-mobile"
>: {prevStep.title}</span
<section class="web-article-content-section">
<section class="web-article-content-sub-section">
<header class="web-article-content-header">
<span class="web-numeric-badge">{currentStep}</span>
<Heading level={1} id={currentStepItem.href} step={currentStep}>
{getCorrectTitle(currentStepItem, 1)}
</Heading>
</header>

<div class="u-padding-block-start-32" bind:this={slotContent}>
<slot />
</div>

<div class="u-flex u-main-space-between">
{#if prevStep}
<a href={prevStep.href} class="web-button is-text previous-step-anchor">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="web-sub-body-500">
Step {prevStep.step}<span class="web-is-not-mobile"
>: {getCorrectTitle(prevStep, 1)}</span
>
</span>
</a>
{/if}
{#if nextStep}
<a
href={nextStep.href}
class="web-button is-secondary"
style:margin-left={prevStep ? undefined : 'auto'}
>
</span>
</a>
{/if}
{#if nextStep}
<a
href={nextStep.href}
class="web-button is-secondary"
style:margin-left={prevStep ? undefined : 'auto'}
>
<span class="text-sub-body font-medium">
Step {nextStep.step}<span class="web-is-not-mobile"
<span class="web-sub-body-500">
Step {nextStep.step}<span class="web-is-not-mobile"
>: {nextStep.title}</span
>
</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</a>
{/if}
</div>
>
</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</a>
{/if}
</div>
</section>
</section>

<Feedback {date} />
</div>
Expand All @@ -83,7 +109,7 @@
<h5 class="web-references-menu-title text-micro uppercase">Tutorial Steps</h5>
</div>
<ol class="web-references-menu-list">
{#each tutorials as tutorial}
{#each tutorials as tutorial, index}
{@const isCurrentStep = currentStep === tutorial.step}
<li class="web-references-menu-item">
<a
Expand All @@ -93,24 +119,22 @@
class:is-selected={isCurrentStep}
>
<span class="web-numeric-badge">{tutorial.step}</span>
<span class="text-caption">{tutorial.title}</span>
<!-- first item will always be introduction -->
<span class="web-caption-400">{index === 0 ? 'Introduction' : tutorial.title}</span>
</a>
{#if isCurrentStep}
<ol class="web-references-menu-list mt-4 ml-8">
{#each toc as parent}
{#if isCurrentStep && toc.length}
<ol
class="web-references-menu-list u-margin-block-start-16 u-margin-inline-start-32"
>
{#each toc.slice(1) as parent}
<li class="web-references-menu-item">
<a
href={parent.href}
class="web-references-menu-link is-inner"
class:tutorial-scroll-indicator={parent.selected}
class:is-selected={parent.selected}
>
{#if parent?.step}
<span class="web-numeric-badge"
>{parent.step}</span
>
{/if}
<span class="text-caption">{parent.title}</span>
<span class="web-caption-400">{parent.title}</span>
</a>
{#if parent.children}
<ol class="web-references-menu-list mt-4 ml-8">
Expand Down Expand Up @@ -145,3 +169,17 @@
</aside>
</article>
</main>

<style>
.web-article-header {
margin-block-end: 2rem;
padding-inline-start: unset;
}

.previous-step-anchor {
border: unset;
outline: unset;
background: unset;
padding-inline-start: unset;
}
</style>
42 changes: 26 additions & 16 deletions src/lib/utils/tutorials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@ import { base } from '$app/paths';
import type { Tutorial } from '$markdoc/layouts/Tutorial.svelte';

export function globToTutorial(data: { tutorials: Record<string, unknown>; pathname: string }) {
return Object.entries(data.tutorials)
.map(([filepath, tutorial]) => {
const { frontmatter } = tutorial as {
frontmatter: Tutorial;
};
const slug = filepath.replace('./', '').replace('/+page.markdoc', '');
const tutorialName = data.pathname.split('/').slice(0, -1).join('/');
let isFound = false;
let difficulty, readtime;

return {
title: frontmatter.title,
step: frontmatter.step,
href: `${base}${tutorialName}/${slug}`
};
})
.sort((a, b) => {
return a.step - b.step;
});
return Object.entries(data.tutorials)
.map(([filepath, tutorial]) => {
const { frontmatter } = tutorial as {
frontmatter: Tutorial;
};
const slug = filepath.replace('./', '').replace('/+page.markdoc', '');
const tutorialName = data.pathname.split('/').slice(0, -1).join('/');

if (!isFound && 'difficulty' in frontmatter && 'readtime' in frontmatter) {
isFound = true;
readtime = frontmatter.readtime;
difficulty = frontmatter.difficulty;
}

return {
readtime,
difficulty,
...frontmatter,
href: `${base}${tutorialName}/${slug}`
};
})
.sort((a, b) => {
return a.step - b.step;
});
}
15 changes: 3 additions & 12 deletions src/markdoc/layouts/Tutorial.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
step: number;
href: string;
draft?: boolean;
difficulty?: string;
readtime?: string;
};
</script>

Expand All @@ -21,10 +23,7 @@

export let title: string;
export let description: string;
export let difficulty: string;
export let readtime: string;
export let step: number;
export let back: string;
export let date: string;

setContext<LayoutContext>('headings', writable({}));
Expand Down Expand Up @@ -77,15 +76,7 @@
<meta name="twitter:card" content="summary_large_image" />
</svelte:head>

<DocsTutorial {title} {back} {toc} {tutorials} {date} currentStep={step}>
<svelte:fragment slot="metadata">
{#if difficulty}
<li>{difficulty}</li>
{/if}
{#if readtime}
<li>{readtime} min</li>
{/if}
</svelte:fragment>
<DocsTutorial {toc} {tutorials} {date} currentStep={step}>
<slot />
</DocsTutorial>
<MainFooter variant="docs" />
Loading