Skip to content
Merged
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
66 changes: 44 additions & 22 deletions packages/lit-dev-content/src/components/litdev-tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,16 @@ export class LitDevTutorial extends LitElement {
hash = hash.slice(1);
}
this._idx = hash === '' ? 0 : this._slugToIdx(hash) ?? this._idx;
if (hash.startsWith('0')) {
// In an earlier URL scheme, we indexed steps from 0, and left-padded with
// "0"s. Now we index from 1, and conveniently use the fact that we also
// no longer left-pad to detect people still on the old scheme, and fix
// their URLs. Note we never published any tutorials with >10 steps on the
// old scheme, so there has never been a "#10" or higher in the old
// scheme, so this is never ambiguous.
this._idx++;
window.location.hash = `#${this._idxToSlug(this._idx)}`;
}
};

/**
Expand Down Expand Up @@ -713,23 +723,20 @@ export class LitDevTutorial extends LitElement {
}

/**
* Finds the index of the given slug. e.g. "" -> 0, "03" -> 3
*
* @param slug slug of the step
* @returns The index with the given slug
* Makes a 0-indexed step number from a 1-indexed URL slug.
* E.g. "" -> 0, "1" -> 0, "2" -> 1
*/
private _slugToIdx(slug: string): number | undefined {
const idx = Number(slug);
return isNaN(idx) ? undefined : idx;
return isNaN(idx) ? 0 : idx - 1;
}

/**
* Turns an index into a 2-length stringified number for the slug.
* @param idx index to slugify
* @returns A 2-length stringified number
* Makes a 1-indexed URL slug from a 0-indexed step number.
* E.g. 0 -> "1", 1 -> "2"
*/
private _idxToSlug(idx: number): string {
return `${idx}`.padStart(2, '0');
return String(idx + 1);
}

/**
Expand All @@ -741,25 +748,40 @@ export class LitDevTutorial extends LitElement {
* does not exist in the file system
*/
private _idxToInfo(idx: number): ExpandedTutorialStep {
const slug = this._idxToSlug(idx);
// The "after"'s code is located in the before dir of the next step
let afterSlug = `${this._idxToSlug(idx + 1)}/before`;
// Note URLs visible to the user are 1-indexed and non-padded, while the
// underlying resources are 0-indexed and zero-padded to 2 digits.
//
// TODO(aomarks) It would be nice to rename all of the tutorial files on
// disk to be 1-indexed instead of 0-indexed, so that it's easier to see
// which step they correspond to during development.

// if the user specified this step has an after, use that
if (this._manifest.steps[idx].hasAfter) {
afterSlug = `${slug}/after`;
}
const name = this._projectLocation;

// On the first step, we don't include a #num anchor.
const url =
idx === 0
? `/tutorials/${name}`
: `/tutorials/${name}/#${this._idxToSlug(idx)}`;

const thisIdxPadded = String(idx).padStart(2, '0');
const nextIdxPadded = String(idx + 1).padStart(2, '0');

const htmlSrc = `/tutorials/content/${name}/${thisIdxPadded}/`;

const firstUrl = `/tutorials/${this._projectLocation}`;
const projectSrcRoot = `${this._samplesRoot}/tutorials/${name}`;
const projectSrcBefore = `${projectSrcRoot}/${thisIdxPadded}/before/project.json`;

const nextUrl = `/tutorials/${this._projectLocation}#${slug}`;
// If there is no after, use the before of the next step.
const projectSrcAfter = this._manifest.steps[idx].hasAfter
? `${projectSrcRoot}/${thisIdxPadded}/after/project.json`
: `${projectSrcRoot}/${nextIdxPadded}/before/project.json`;

return {
idx,
url: idx === 0 ? firstUrl : nextUrl,
htmlSrc: `/tutorials/content/${this._projectLocation}/${slug}/`,
projectSrcBefore: `${this._samplesRoot}/tutorials/${this._projectLocation}/${slug}/before/project.json`,
projectSrcAfter: `${this._samplesRoot}/tutorials/${this._projectLocation}/${afterSlug}/project.json`,
url,
htmlSrc,
projectSrcBefore,
projectSrcAfter,
};
}

Expand Down