Skip to content

Commit 41d23ea

Browse files
authored
Use 1-indexed tutorial URLs (#832)
Previously, we used 0-indexed and left-padded tutorial URLs. For example, the 2nd step of a tutorial had URL `/tutorials/<name>/#1`. Now it is 1-indexed, and not padded. For example: `/tutorials/<name>/#2`. I think 0-indexed is more intuitive, because it means the URLs are aligned with the "Step 2/8" text on the page. I think left-padding was unnecessary in URLs, plus by removing it, we have a convenient way to detect people still on the 0-indexed scheme, and fix the URLs to be 1-indexed. This way nobody will get jumped ahead if they reload before/after the new scheme is deployed. Also fixes a bug where we would set the URL to `/tutorials/<name>#2` (no trailing slash), but then after reloading it would turn into `/tutorials/<name>/#2`. Now we always set the final form.
1 parent 50d0939 commit 41d23ea

File tree

1 file changed

+44
-22
lines changed

1 file changed

+44
-22
lines changed

packages/lit-dev-content/src/components/litdev-tutorial.ts

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,16 @@ export class LitDevTutorial extends LitElement {
660660
hash = hash.slice(1);
661661
}
662662
this._idx = hash === '' ? 0 : this._slugToIdx(hash) ?? this._idx;
663+
if (hash.startsWith('0')) {
664+
// In an earlier URL scheme, we indexed steps from 0, and left-padded with
665+
// "0"s. Now we index from 1, and conveniently use the fact that we also
666+
// no longer left-pad to detect people still on the old scheme, and fix
667+
// their URLs. Note we never published any tutorials with >10 steps on the
668+
// old scheme, so there has never been a "#10" or higher in the old
669+
// scheme, so this is never ambiguous.
670+
this._idx++;
671+
window.location.hash = `#${this._idxToSlug(this._idx)}`;
672+
}
663673
};
664674

665675
/**
@@ -713,23 +723,20 @@ export class LitDevTutorial extends LitElement {
713723
}
714724

715725
/**
716-
* Finds the index of the given slug. e.g. "" -> 0, "03" -> 3
717-
*
718-
* @param slug slug of the step
719-
* @returns The index with the given slug
726+
* Makes a 0-indexed step number from a 1-indexed URL slug.
727+
* E.g. "" -> 0, "1" -> 0, "2" -> 1
720728
*/
721729
private _slugToIdx(slug: string): number | undefined {
722730
const idx = Number(slug);
723-
return isNaN(idx) ? undefined : idx;
731+
return isNaN(idx) ? 0 : idx - 1;
724732
}
725733

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

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

748-
// if the user specified this step has an after, use that
749-
if (this._manifest.steps[idx].hasAfter) {
750-
afterSlug = `${slug}/after`;
751-
}
758+
const name = this._projectLocation;
759+
760+
// On the first step, we don't include a #num anchor.
761+
const url =
762+
idx === 0
763+
? `/tutorials/${name}`
764+
: `/tutorials/${name}/#${this._idxToSlug(idx)}`;
765+
766+
const thisIdxPadded = String(idx).padStart(2, '0');
767+
const nextIdxPadded = String(idx + 1).padStart(2, '0');
768+
769+
const htmlSrc = `/tutorials/content/${name}/${thisIdxPadded}/`;
752770

753-
const firstUrl = `/tutorials/${this._projectLocation}`;
771+
const projectSrcRoot = `${this._samplesRoot}/tutorials/${name}`;
772+
const projectSrcBefore = `${projectSrcRoot}/${thisIdxPadded}/before/project.json`;
754773

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

757779
return {
758780
idx,
759-
url: idx === 0 ? firstUrl : nextUrl,
760-
htmlSrc: `/tutorials/content/${this._projectLocation}/${slug}/`,
761-
projectSrcBefore: `${this._samplesRoot}/tutorials/${this._projectLocation}/${slug}/before/project.json`,
762-
projectSrcAfter: `${this._samplesRoot}/tutorials/${this._projectLocation}/${afterSlug}/project.json`,
781+
url,
782+
htmlSrc,
783+
projectSrcBefore,
784+
projectSrcAfter,
763785
};
764786
}
765787

0 commit comments

Comments
 (0)