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 detection of empty figma components #10

Merged
merged 4 commits into from
Mar 21, 2023
Merged
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
13 changes: 0 additions & 13 deletions client-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ module.exports = {
favicon: '/favicon.ico',
logo: '/logo.svg',
poweredBy: true,
show_components: {
alert: 'Alert',
button: 'Button',
checkbox:'Checkbox',
input:'Input',
modal:'Modal',
pagination: null,
radio:'Radio',
select:'Select',
switch:'Switch',
tooltip: 'Tooltip',
},
type_sort: [
'Heading 1',
'Heading 2',
Expand All @@ -33,5 +21,4 @@ module.exports = {
type_copy: 'Almost before we knew it, we had left the ground.',
color_sort: ['primary', 'secondary', 'extra', 'system'],
component_sort: ['primary', 'secondary', 'transparent'],

};
38 changes: 38 additions & 0 deletions components/ComponentNotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as util from 'components/util';
import Head from 'next/head';
import Header from './Header';
import Icon from './Icon';
import CustomNav from './SideNav/Custom';
export interface ComponentNotFoundProps extends util.DocumentationProps {
children?: JSX.Element;
}
export const ComponentNotFound: React.FC<ComponentNotFoundProps> = ({ metadata, menu, current, children }) => {
return (
<div className="c-page">
<Head>
<title>{metadata.metaTitle}</title>
<meta name="description" content={metadata.metaDescription} />
</Head>
<Header menu={menu} />
{current.subSections.length > 0 && <CustomNav menu={current} />}
<section className="c-content">
<div className="o-container-fluid">
<div className="c-hero">
<div>
<h1>{`${metadata.title} Not Found`}</h1>
<p>
No <span>{metadata.title.toLowerCase()}</span> tokens were found. Either they couldn&rsquo;t be extracted from figma, or the component was not found in figma.
Check to make sure that the component is being imported on fetch. If you see a red message indicating the component cannot
be retrieved, check to make sure the component exists in figma.
<br />
<br />
<a href="https://www.handoff.com/docs/tokens/not-found">Read More</a>
</p>
</div>
{metadata.image && <Icon name={metadata.image} className="c-hero__img" />}
</div>
</div>
</section>
</div>
);
};
127 changes: 122 additions & 5 deletions components/util/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Config } from 'client-config';
import { getConfig } from 'config';
import { filter } from 'domutils';
import * as fs from 'fs-extra';
Expand Down Expand Up @@ -42,6 +43,12 @@ export interface DocumentationProps {
current: SectionLink;
}

export interface ComponentDocumentationProps extends DocumentationProps{
componentFound: boolean;
}
/**
* List the default paths
*/
export const knownPaths = [
'assets',
'assets/fonts',
Expand All @@ -66,6 +73,32 @@ export const knownPaths = [
'components/checkbox',
];

/**
* Get the plural name of a component
* @param singular
* @returns
*/
export const pluralizeComponent = (singular: string): string => {
return (
{
button: 'buttons',
select: 'selects',
checkbox: 'checkboxes',
radio: 'radios',
input: 'inputs',
tooltip: 'tooltips',
alert: 'alerts',
switch: 'switches',
pagination: 'pagination',
modal: 'modal',
}[singular] ?? singular
);
};

/**
* Build level 1 static path parameters
* @returns
*/
export const buildL1StaticPaths = () => {
const files = fs.readdirSync('docs');
const paths = files
Expand All @@ -84,6 +117,10 @@ export const buildL1StaticPaths = () => {
return paths;
};

/**
* Build static paths for level 2
* @returns SubPathType[]
*/
export const buildL2StaticPaths = () => {
const files = fs.readdirSync('docs');
const paths: SubPageType[] = files
Expand All @@ -109,6 +146,26 @@ export const buildL2StaticPaths = () => {
return paths;
};

/**
* Does a component exist in figma? Check the length of the component tokens
* @param component
* @param config
* @returns
*/
export const componentExists = (component: string, config?: Config): boolean => {
if (!config) {
config = getConfig();
}
const componentKey = pluralizeComponent(component) ?? false;
// If this is a component (we define it in the tokens file)
// but it has a length of 0, return the menu as undefined even
// if its set in the file list
if (config.components[componentKey] && config.components[componentKey].length === 0) {
return false;
}
return true;
};

/**
* Build the static menu for rendeirng pages
* @returns SectionLink[]
Expand All @@ -117,6 +174,7 @@ export const staticBuildMenu = () => {
// Contents of docs
const files = fs.readdirSync('docs');
const sections: SectionLink[] = [];
const config = getConfig();

// Build path tree
const custom = files
Expand All @@ -128,15 +186,23 @@ export const staticBuildMenu = () => {
if (metadata.enabled === false) {
return undefined;
}
const path = `/${fileName.replace('.md', '')}`;
return {
title: metadata.menuTitle ?? metadata.title,
weight: metadata.weight,
path: `/${fileName.replace('.md', '')}`,
path,
// Build the submenus
subSections: metadata.menu
? Object.keys(metadata.menu)
.map((key) => {
const sub = metadata.menu[key];
// Component menus are filtered by the presence of tokens
if (path === '/components' && sub.path) {
const componentName = sub.path.replace('components/', '');
if (!componentExists(componentName, config)) {
return undefined;
}
}
if (sub.enabled !== false) {
return sub;
}
Expand All @@ -158,13 +224,14 @@ export const staticBuildMenu = () => {
*/
export const getCurrentSection = (menu: SectionLink[], path: string): SectionLink | null =>
menu.filter((section) => section.path === path)[0];
/**

/**
* Build a static object for rending markdown pages
* @param path
* @param slug
* @returns
*/
export const fetchDocPageMarkdown = (path: string, slug: string | string[] | undefined, id: string) => {
export const fetchDocPageMarkdown = (path: string, slug: string | undefined, id: string)=> {
const menu = staticBuildMenu();
const { metadata, content } = fetchDocPageMetadataAndContent(path, slug);
// Return props
Expand All @@ -174,19 +241,69 @@ export const fetchDocPageMarkdown = (path: string, slug: string | string[] | und
content,
menu,
current: getCurrentSection(menu, `${id}`) ?? [],

},
};
};

/**
* Fetch Component Doc Page Markdown
* @param path
* @param slug
* @param id
* @returns
*/
export const fetchCompDocPageMarkdown = (path: string, slug: string | undefined, id: string) => {
return {
props: {
...fetchDocPageMarkdown(path, slug, id).props,
componentFound: (slug) ? componentExists(pluralizeComponent(slug), undefined) : false
},
};
}

/**
* Reduce a slug which can be either an array or string, to just a string by
* plucking the first element
* @param slug
* @returns
*/
export const reduceSlugToString = (slug: string | string[] | undefined) : string | undefined => {
let prop: string | undefined;
if (Array.isArray(slug)) {
if(slug[0]){
prop = slug[0];
}
}else{
prop = slug;
}
return prop;
}

/**
* Get doc meta and content from markdown
* @param path
* @param slug
* @returns
*/
export const fetchDocPageMetadataAndContent = (path: string, slug: string | string[] | undefined) => {
const currentContents = fs.readFileSync(`${path}${slug}.md`, 'utf-8');
const { data: metadata, content } = matter(currentContents);

return { metadata, content };
}

};
/**
* Filter out undefined elements
* @param value
* @returns
*/
export const filterOutUndefined = <T>(value: T): value is NonNullable<T> => value !== undefined;

/**
* Create a title string from a prefix
* @param prefix
* @returns
*/
export const titleString = (prefix: string | null): string => {
const config = getConfig();
const prepend = prefix ? `${prefix} | ` : '';
Expand Down
2 changes: 2 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ menu:
title: Alert
- path: components/button
title: Button
- path: components/pagination
title: Pagination
- path: components/modal
title: Modal
- path: components/tooltip
Expand Down
2 changes: 1 addition & 1 deletion installer/template/templates/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

$prefix: '';
$enable-shadows: true;

@import '../sass/project/default_vars/defaults';
@import '../sass/project/buttons';
@import '../sass/project/checkbox';
@import '../sass/project/radio';
Expand Down
4 changes: 2 additions & 2 deletions pages/[level1]/[level2]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buildL2StaticPaths, DocumentationProps, fetchDocPageMarkdown, IParams } from 'components/util';
import { buildL2StaticPaths, DocumentationProps, fetchDocPageMarkdown, IParams, reduceSlugToString } from 'components/util';
import { GetStaticProps } from 'next';
import { getConfig } from 'config';
import Head from 'next/head';
Expand Down Expand Up @@ -39,7 +39,7 @@ export const getStaticProps: GetStaticProps = async (context) => {
if (!level2) {
level2 = '404';
}
return fetchDocPageMarkdown(`docs/${level1}/`, level2, `/${level1}`);
return fetchDocPageMarkdown(`docs/${level1}/`, reduceSlugToString(level2), `/${level1}`);
};

const config = getConfig();
Expand Down
4 changes: 2 additions & 2 deletions pages/[level1]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Header from 'components/Header';
import CustomNav from 'components/SideNav/Custom';
import { buildL1StaticPaths, DocumentationProps, fetchDocPageMarkdown, IParams } from 'components/util';
import { buildL1StaticPaths, DocumentationProps, fetchDocPageMarkdown, IParams, reduceSlugToString } from 'components/util';
import { MarkdownComponents } from 'components/Markdown/MarkdownComponents';
import { getConfig } from 'config';
import { GetStaticProps } from 'next';
Expand Down Expand Up @@ -30,7 +30,7 @@ export async function getStaticPaths() {
export const getStaticProps: GetStaticProps = async (context) => {
// Read current slug
const { level1 } = context.params as IParams;
return fetchDocPageMarkdown('docs/', level1, `/${level1}`);
return fetchDocPageMarkdown('docs/', reduceSlugToString(level1), `/${level1}`);
};

const config = getConfig();
Expand Down
9 changes: 7 additions & 2 deletions pages/components/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CustomNav from 'components/SideNav/Custom';
import AnchorNav from 'components/AnchorNav';
import ComponentGuidelines from 'components/ComponentGuidelines';
import { CodeHighlight } from 'components/Markdown/CodeHighlight';
import { ComponentNotFound } from 'components/ComponentNotFound';


const AlertDisplay: React.FC<{ alert: PreviewObject | undefined }> = ({ alert }) => {
Expand Down Expand Up @@ -80,12 +81,16 @@ const alerts = {
*/
export const getStaticProps: GetStaticProps = async (context) => {
// Read current slug
return util.fetchDocPageMarkdown('docs/components/', 'alert', `/components`);
return util.fetchCompDocPageMarkdown('docs/components/', 'alert', `/components`);
};

const AlertPage = ({ content, menu, metadata, current }: util.DocumentationProps) => {
const AlertPage = ({ content, menu, metadata, current, componentFound }: util.ComponentDocumentationProps) => {
const [activeTab, setActiveTab] = React.useState<ComponentTab>(ComponentTab.Overview);

if (!componentFound) {
return <ComponentNotFound menu={menu} metadata={metadata} current={current} content={content}></ComponentNotFound>;
}

return (
<div className="c-page">
<Head>
Expand Down
12 changes: 8 additions & 4 deletions pages/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CustomNav from 'components/SideNav/Custom';
import AnchorNav from 'components/AnchorNav';
import ComponentGuidelines from 'components/ComponentGuidelines';
import { CodeHighlight } from 'components/Markdown/CodeHighlight';

import { ComponentNotFound } from 'components/ComponentNotFound';

const ButtonDisplay: React.FC<{ button: PreviewObject | undefined }> = ({ button }) => {
return (
Expand Down Expand Up @@ -66,7 +66,7 @@ const buttons = {
const preview = getPreview().components.buttons.find((item) => item.id === button.id);
return {
...button,
preview
preview,
};
}),
};
Expand All @@ -80,12 +80,16 @@ const buttons = {
*/
export const getStaticProps: GetStaticProps = async (context) => {
// Read current slug
return util.fetchDocPageMarkdown('docs/components/', 'button', `/components`);
return util.fetchCompDocPageMarkdown('docs/components/', 'button', `/components`);
};

const ButtonsPage = ({ content, menu, metadata, current }: util.DocumentationProps) => {
const ButtonsPage = ({ content, menu, metadata, current, componentFound }: util.ComponentDocumentationProps) => {
const [activeTab, setActiveTab] = React.useState<ComponentTab>(ComponentTab.Overview);

if (!componentFound) {
return <ComponentNotFound menu={menu} metadata={metadata} current={current} content={content}></ComponentNotFound>;
}

return (
<div className="c-page">
<Head>
Expand Down
Loading