Skip to content

Commit

Permalink
Merge pull request #1172 from ItzNotABug/improve-title-context
Browse files Browse the repository at this point in the history
Improve Title Context
  • Loading branch information
ernstmul authored Oct 8, 2024
2 parents e30c836 + 0468f82 commit 986bc5f
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 88 deletions.
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: Tutorial | null = tutorials[0] ?? null;
// 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: Tutorial, checkAt: number): string {
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" />

0 comments on commit 986bc5f

Please sign in to comment.