Skip to content
Open
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
61 changes: 56 additions & 5 deletions .github/scripts/createDocsRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Article = {
type Section = {
href: string;
title: string;
order?: number;
articles?: Article[];
sections?: Section[];
};
Expand All @@ -23,6 +24,7 @@ type Hub = {
icon: string;
articles?: Article[];
sections?: Section[];
flatSections?: Section[];
};

type Platform = {
Expand All @@ -36,6 +38,18 @@ type DocsRoutes = {

type HubEntriesKey = 'sections' | 'articles';

function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function getOptionalString(value: unknown): string | undefined {
return typeof value === 'string' ? value : undefined;
}

function getOptionalNumber(value: unknown): number | undefined {
return typeof value === 'number' ? value : undefined;
}

const warnMessage = (platform: string): string => `Number of hubs in _routes.yml does not match number of hubs in docs/${platform}/articles. Please update _routes.yml with hub info.`;
const disclaimer = '# This file is auto-generated. Do not edit it directly. Use npm run createDocsRoutes instead.\n';
const docsDir = `${process.cwd()}/docs`;
Expand Down Expand Up @@ -109,24 +123,55 @@ function getOrderFromArticleFrontMatter(path: string): number | undefined {
if (!frontmatter) {
return undefined;
}
const frontmatterObject = yaml.load(frontmatter) as Record<string, unknown>;
return frontmatterObject.order as number | undefined;
const frontmatterObject = yaml.load(frontmatter);
if (!isRecord(frontmatterObject)) {
return undefined;
}
return getOptionalNumber(frontmatterObject.order);
} catch {
return undefined;
}
}

function getSectionMeta(sectionPath: string): {title?: string; order?: number} {
try {
const metaPath = `${sectionPath}/_meta.yml`;
if (!fs.existsSync(metaPath)) {
return {};
}
const meta = yaml.load(fs.readFileSync(metaPath, 'utf8'));
if (!isRecord(meta)) {
return {};
}
return {
title: getOptionalString(meta.title),
order: getOptionalNumber(meta.order),
};
} catch {
return {};
}
}

function sortSectionsByOrder(sections: Section[]) {
sections.sort((a, b) => (a.order ?? Number.POSITIVE_INFINITY) - (b.order ?? Number.POSITIVE_INFINITY));
}

/**
* Build a section from a directory path, with optional parent path for nested href
*/
function buildSection(platformName: string, hub: string, sectionPath: string, parentHref: string): Section {
const sectionName = sectionPath.split('/').pop() ?? sectionPath;
const fullPath = `${docsDir}/articles/${platformName}/${hub}/${sectionPath}`;
const meta = getSectionMeta(fullPath);
const articles: Article[] = [];
const childSections: Section[] = [];
const href = parentHref ? `${parentHref}/${sectionName}` : sectionName;

for (const entry of fs.readdirSync(fullPath)) {
if (entry === '_meta.yml') {
continue;
}

const entryPath = `${fullPath}/${entry}`;
if (entry.endsWith('.md')) {
const order = getOrderFromArticleFrontMatter(entryPath);
Expand All @@ -140,9 +185,12 @@ function buildSection(platformName: string, hub: string, sectionPath: string, pa
// The sort is stable, so articles without an `order` keep their relative position and fall after ordered ones.
articles.sort((a, b) => (a.order ?? Number.POSITIVE_INFINITY) - (b.order ?? Number.POSITIVE_INFINITY));

sortSectionsByOrder(childSections);

const section: Section = {
href,
title: toTitleCase(sectionName.replaceAll('-', ' ')),
title: meta.title ?? toTitleCase(sectionName.replaceAll('-', ' ')),
...(meta.order !== undefined && {order: meta.order}),
...(articles.length > 0 && {articles}),
...(childSections.length > 0 && {sections: childSections}),
};
Expand Down Expand Up @@ -175,7 +223,9 @@ function createHubsWithArticles(hubs: string[], platformName: ValueOf<typeof pla

for (const fileOrFolder of fs.readdirSync(basePath)) {
if (fileOrFolder.endsWith('.md')) {
const articleObj = getArticleObj(fileOrFolder);
const entryPath = `${basePath}/${fileOrFolder}`;
const order = getOrderFromArticleFrontMatter(entryPath);
const articleObj = getArticleObj(fileOrFolder, order);
pushOrCreateEntry(routeHubs, hub, 'articles', articleObj);
continue;
}
Expand All @@ -188,7 +238,8 @@ function createHubsWithArticles(hubs: string[], platformName: ValueOf<typeof pla
// Add flat section list for nested section page lookup
const hubObj = routeHubs.find((obj) => obj.href === hub);
if (hubObj?.sections?.length) {
(hubObj as Hub & {flatSections?: Section[]}).flatSections = flattenSections(hubObj.sections);
sortSectionsByOrder(hubObj.sections);
hubObj.flatSections = flattenSections(hubObj.sections);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/_data/_routes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ platforms:
description: Manage profile settings and notifications.

- href: billing-and-subscriptions
title: Expensify Billing & Subscriptions
title: Billing & Subscriptions
icon: /assets/images/subscription-annual.svg
description: Review Expensify's subscription options, plan types, and payment methods.

Expand Down
6 changes: 3 additions & 3 deletions docs/_includes/hub.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ <h1 class="title">{{ hub.title }}</h1>
{% assign hubSections = hub.sections | default: emptyItems %}

{% if hub.articles %}
{% assign sortedSectionsAndArticles = hubSections | concat: hubArticles | sort: 'title' %}
{% assign sortedSectionsAndArticles = hubSections | concat: hubArticles | sort: 'order' %}
{% else %}
{% assign sortedSectionsAndArticles = hubSections | sort: 'title' %}
{% assign sortedSectionsAndArticles = hubSections | sort: 'order' %}
{% endif%}

<section>
<div class="cards-group">
{% for item in sortedSectionsAndArticles %}
{% if item.articles %}
{% if item.articles or item.sections %}
{% include section-card.html platform=activePlatform hub=hub.href section=item.href title=item.title %}
{% else %}
{% include article-card.html hub=hub.href href=item.href title=item.title platform=activePlatform %}
Expand Down
63 changes: 60 additions & 3 deletions docs/_includes/lhn-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
<span>{{ hub.title }}</span>
</div>
<ul class="nested-treeview">
{% assign emptyItems = "" | split: "," %}
{% assign hubArticles = hub.articles | default: emptyItems %}
{% assign hubSections = hub.sections | default: emptyItems %}
{% if hub.articles %}
{% assign sortedSectionsAndArticles = hub.sections | concat: hub.articles | sort: 'title' %}
{% assign sortedSectionsAndArticles = hubSections | concat: hubArticles | sort: 'order' %}
{% else %}
{% assign sortedSectionsAndArticles = hub.sections | sort: 'title' %}
{% assign sortedSectionsAndArticles = hubSections | sort: 'order' %}
{% endif%}
{% for item in sortedSectionsAndArticles %}
{% if item.articles %}
Expand Down Expand Up @@ -151,7 +154,61 @@
{% endif %}
</ul>
{% else %}
<a href="{{ item.href }}" class="icon-with-link link">
<a href="/{{ activePlatform }}/hubs/{{ hub.href }}/{{ item.href }}" class="icon-with-link link">
<img src="/assets/images/arrow-right.svg" class="base-icon"></img>
{{ item.title }}
</a>
{% endif %}
</li>
{% elsif item.sections %}
<li>
{% assign lhnSectionActive = false %}
{% if page.url contains item.href %}
{% assign lhnSectionActive = true %}
{% endif %}
{% if lhnSectionActive %}
<div class="icon-with-link selected">
<a href="/{{ activePlatform }}/hubs/{{ hub.href }}"><img src="/assets/images/down.svg" class="base-icon"></img></a>
<span>{{ item.title }}</span>
</div>
<ul>
{% assign lhnSortedSubsections = item.sections | sort: 'order' %}
{% for subsection in lhnSortedSubsections %}
<li>
<a href="/{{ activePlatform }}/hubs/{{ hub.href }}/{{ subsection.href }}" class="icon-with-link link">
<img src="/assets/images/arrow-right.svg" class="base-icon"></img>
{{ subsection.title }}
</a>
{% if subsection.articles %}
<ul>
{% for article in subsection.articles %}
{% assign article_href = subsection.href | append: '/' | append: article.href %}
{% include lhn-article-link.html platform=activePlatform hub=hub.href href=article_href title=article.title %}
{% endfor %}
</ul>
{% endif %}
{% if subsection.sections %}
<ul>
{% for nestedSection in subsection.sections %}
<li>
<span class="icon-with-link">{{ nestedSection.title }}</span>
{% if nestedSection.articles %}
<ul>
{% for article in nestedSection.articles %}
{% assign article_href = nestedSection.href | append: '/' | append: article.href %}
{% include lhn-article-link.html platform=activePlatform hub=hub.href href=article_href title=article.title %}
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<a href="/{{ activePlatform }}/hubs/{{ hub.href }}/{{ item.href }}" class="icon-with-link link">
<img src="/assets/images/arrow-right.svg" class="base-icon"></img>
{{ item.title }}
</a>
Expand Down
6 changes: 4 additions & 2 deletions docs/_includes/section.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ <h1 class="title">
<section>
<div class="cards-group">
{% if section.sections %}
{% for subsection in section.sections %}
{% assign sortedSubsections = section.sections | sort: 'order' %}
{% for subsection in sortedSubsections %}
{% include section-card.html platform=activePlatform hub=hub.href section=subsection.href title=subsection.title %}
{% endfor %}
{% endif %}
{% assign sortedArticles = section.articles | default: empty %}
{% assign emptyItems = "" | split: "," %}
{% assign sortedArticles = section.articles | default: emptyItems %}
{% for article in sortedArticles %}
{% assign article_href = section.href | append: '/' | append: article.href %}
{% include article-card.html hub=hub.href href=article_href title=article.title platform=activePlatform %}
Expand Down

This file was deleted.

Loading
Loading