Skip to content

Commit

Permalink
feat: list pages, date, tags fields
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Jun 9, 2020
1 parent bf41c47 commit 8dac2f9
Show file tree
Hide file tree
Showing 30 changed files with 338 additions and 183 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ There are many developments that have contributed to the creation of `component-

- [theme-ui](https://theme-ui.com) is the driving force for standardizing `react` theming and design systems. `theme-ui` is used by our project as the theming and components founding block.

- [mdx](https://mdxjs.com) is driving the adoption of JSX in Markdown and allows writing rich, interactive documentation pages.

# Roadmap

- [x] Core packages
Expand Down
16 changes: 15 additions & 1 deletion core/instrument/src/babel/mdx-stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ import {

import { componentsFromParams } from '../misc/component-attributes';

const serialzeProp = (prop: any): string => {
if (prop instanceof Date) {
return `"${prop.toString()}"`;
}
if (Array.isArray(prop)) {
return prop.map(p => serialzeProp(p));
}
if (typeof prop === 'string') {
return `"${jsStringEscape(prop)}"`;
}
return prop;
};

export const extractMDXStories = (props: any) => (
ast: File,
_options: Required<InstrumentOptions>,
Expand Down Expand Up @@ -79,13 +92,14 @@ export const extractMDXStories = (props: any) => (
exports: {},
packages: {},
};

if (props) {
store.exports.default = {
story: Object.keys(props).reduce((acc: object, key: string) => {
const prop = props[key];
return {
...acc,
[key]: typeof prop === 'string' ? `"${jsStringEscape(prop)}"` : prop,
[key]: serialzeProp(prop),
};
}, {}),
};
Expand Down
1 change: 1 addition & 0 deletions core/instrument/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export const parseStories = async (
mergedOptions,
);
const { stories, doc, components, exports, packages } = store;
debugger;
const exportsSource = extractStoryExports(exports);
let transformed = `
Expand Down
24 changes: 12 additions & 12 deletions core/loader/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
BuildConfiguration,
RunConfiguration,
StoriesDoc,
defPageType,
Pages,
PageType,
} from '@component-controls/specification';
import { LoadingDocStore } from '@component-controls/instrument';
export interface LoadingStore {
Expand Down Expand Up @@ -31,8 +34,7 @@ export interface LoadingStore {
stores: (Partial<Pick<LoadingDocStore, 'stories' | 'doc'>> & {
filePath: string;
})[];
getDocs: () => StoriesDoc[];
getBlogs: () => StoriesDoc[];
getDocs: (pageType: PageType) => Pages;
}

class Store implements LoadingStore {
Expand All @@ -41,17 +43,15 @@ class Store implements LoadingStore {
packages: LoadingStore['packages'] = {};
config: LoadingStore['config'] = {};
buildConfig: LoadingStore['buildConfig'] = {};
getDocs = () =>
getDocs = (pageType: PageType) =>
this.stores
.filter(
store =>
store?.doc &&
(store.doc?.type === undefined || store.doc?.type === 'story'),
)
.map(store => store.doc as StoriesDoc);
getBlogs = () =>
this.stores
.filter(store => store?.doc && store.doc?.type === 'blog')
.filter(store => {
if (store?.doc) {
const { type = defPageType } = store.doc;
return type === pageType;
}
return false;
})
.map(store => store.doc as StoriesDoc);
}

Expand Down
64 changes: 36 additions & 28 deletions core/specification/src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
import { StoryRenderFn } from './utility';

export type PageType = 'story' | 'blog' | 'page';

export interface PageConfiguration {
/**
* base url path for the page
*/
basePath?: string;

/**
* label - used for menu labels
*/
label?: string;
}

export interface PagesConfiguration {
[key: string]: PageConfiguration;
}

/**
* global configuration used at build time
* stored in a file named main.js/main.ts
Expand All @@ -14,11 +32,7 @@ export interface BuildConfiguration {
/**
* base url path for API documentation pages. Default is "docs/"
*/
docsPath?: string;
/**
* base url path for blogs pages. Default is "blogs/"
*/
blogsPath?: string;
pages?: { [key: string]: Pick<PageConfiguration, 'basePath'> };
}

/**
Expand Down Expand Up @@ -70,31 +84,13 @@ export interface RunConfiguration {
*/
siteImage?: string;

/**
* Label for docs menu. Default is Docs
*/
docsLabel?: string;
pages?: PagesConfiguration;

/**
* Label for blog menu. Default is Blog
*/
blogsLabel?: string;
/**
* story sorting function
*/
storySort?: (a: string, b: string) => number;

/**
* the following used in both run time and build time. Should be set in the build config and
* they will be carried to the run config
/**
* base url path for API documentation pages. Default is "docs/"
*/
docsPath?: string;
/**
* base url path for blogs pages. Default is "blogs/"
*/
blogsPath?: string;
}

export const defaultRunConfig: RunConfiguration = {
Expand All @@ -107,11 +103,23 @@ export const defaultRunConfig: RunConfiguration = {
'Component controls stories. Write your components documentation with MDX and JSX. Design, develop, test and review in a single site.',
siteLanguage: 'en',
author: '@component-controls',
docsLabel: 'Docs',
blogsLabel: 'Blog',
pages: {
story: {
label: 'Docs',
},
blog: {
label: 'Blog',
},
},
};

export const defaultBuildConfig: BuildConfiguration = {
docsPath: 'docs/',
blogsPath: 'blogs/',
pages: {
story: {
basePath: 'docs/',
},
blog: {
basePath: 'blogs/',
},
},
};
42 changes: 27 additions & 15 deletions core/specification/src/stories.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CodeLocation, PackageInfo, StoryRenderFn } from './utility';
import { StoryComponent } from './components';
import { ComponentControls } from './controls';
import { RunConfiguration } from './configuration';
import { RunConfiguration, PageType } from './configuration';
/**
* an identifier/variable.argument in the source code
*/
Expand Down Expand Up @@ -149,6 +149,7 @@ export interface Stories {
[id: string]: Story;
}

export const defPageType: PageType = 'story';
/**
* a group of stories. Usually multiple stories are in one csf file
* and the 'group' is the default export
Expand All @@ -162,7 +163,7 @@ export interface StoriesDoc {
/**
* document type - blogs a and stories. By default - storie
*/
type?: 'story' | 'blog' | 'page';
type?: PageType;
/**
* list of stories contained in the file/groups
*/
Expand Down Expand Up @@ -253,6 +254,22 @@ export interface StoriesDoc {
* side menu - hide
*/
menu?: boolean | string;

/**
* optional date the document was created
*/
date?: string;

/**
* comma-separated list of document tags, used for search
*/
tags?: string;

/**
* document author
*/
author?: string;

[name: string]: any;
}

Expand All @@ -271,6 +288,8 @@ export interface StoryDocs {
[title: string]: StoriesDoc;
}

export type Pages = StoriesDoc[];

/**
* list of stories
*/
Expand Down Expand Up @@ -314,20 +333,14 @@ export interface StoriesStore {
}

export const getDocPath = (
pageType: PageType,
doc?: StoriesDoc,
config?: RunConfiguration,
): string => {
const { docsPath = '' } = config || {};
return doc ? doc.route || `/${docsPath}${doc.title?.toLowerCase()}/` : '';
const { basePath = '' } = config?.pages?.[pageType] || {};
return doc ? doc.route || `/${basePath}${doc.title?.toLowerCase()}/` : '';
};

export const getBlogPath = (
doc?: StoriesDoc,
config?: RunConfiguration,
): string => {
const { blogsPath = '' } = config || {};
return doc ? doc.route || `/${blogsPath}${doc.title?.toLowerCase()}/` : '';
};
export const getStoryPath = (
story?: Story,
doc?: StoriesDoc,
Expand All @@ -336,8 +349,7 @@ export const getStoryPath = (
if (!story) {
return '';
}
const docsPath = config?.docsPath || '';
return doc
? doc.route || `/${docsPath}${doc.title?.toLowerCase()}/#${story.id}`
: '';

const docsPath = getDocPath('story', doc, config);
return `${docsPath}/#${story.id}`;
};
66 changes: 31 additions & 35 deletions core/store/src/Store/Store.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {
StoriesStore,
StoryDocs,
Pages,
StoriesDoc,
RunConfiguration,
getDocPath,
getStoryPath,
getBlogPath,
PageType,
defPageType,
} from '@component-controls/specification';
import { BroadcastChannel } from 'broadcast-channel';
import {
Expand Down Expand Up @@ -38,9 +39,7 @@ export class Store implements StoryStore {
private channel: BroadcastChannel | undefined;
private observers: StoreObserver[];
private moduleId: number;
private _docs: StoryDocs = {};
private _blogs: StoryDocs = {};

private _cachedPages: { [key: string]: Pages } = {};
private _firstStory: string | undefined;
private _firstDoc: string | undefined;
/**
Expand Down Expand Up @@ -108,28 +107,6 @@ export class Store implements StoryStore {
//point to first story of first doc
this._firstStory = doc.stories?.[0];
}
if (this.loadedStore.docs) {
this._docs = Object.keys(this.loadedStore.docs).reduce(
(acc: StoryDocs, key: string) => {
const doc: StoriesDoc | undefined = this.loadedStore?.docs[key];
if (doc && (doc.type === undefined || doc.type === 'story')) {
return { ...acc, [key]: doc };
}
return acc;
},
{},
);
this._blogs = Object.keys(this.loadedStore.docs).reduce(
(acc: StoryDocs, key: string) => {
const doc: StoriesDoc | undefined = this.loadedStore?.docs[key];
if (doc && doc.type === 'blog') {
return { ...acc, [key]: doc };
}
return acc;
},
{},
);
}
}
};
/**
Expand Down Expand Up @@ -191,9 +168,31 @@ export class Store implements StoryStore {
/**
* returns all the documentation files
*/
getDocs = () => this._docs;
getDocs = (): Pages => this.getPageList('story');

getBlogs = () => this._blogs;
getBlogs = (): Pages => this.getPageList('blog');

getPageList = (type: PageType = defPageType): Pages => {
if (this.loadedStore?.docs) {
if (!this._cachedPages[type]) {
this._cachedPages[type] = Object.keys(this.loadedStore.docs).reduce(
(acc: StoriesDoc[], key: string) => {
const doc: StoriesDoc | undefined = this.loadedStore?.docs[key];
if (doc) {
const { type: docTYpe = defPageType } = doc;
if (docTYpe === type) {
return [...acc, doc];
}
}
return acc;
},
[],
);
}
return this._cachedPages[type];
}
return [];
};

get config(): RunConfiguration | undefined {
return this.loadedStore?.config;
Expand All @@ -205,14 +204,11 @@ export class Store implements StoryStore {
return this._firstDoc;
}

getDocPath = (name: string): string => {
getPagePath = (pageType: PageType, name: string): string => {
const doc = this.getStoryDoc(name);
return getDocPath(doc, this.config);
};
getBlogPath = (name: string): string => {
const doc = this.getStoryDoc(name);
return getBlogPath(doc, this.config);
return getDocPath(pageType, doc, this.config);
};

getStoryPath = (storyId: string): string => {
const story = this.getStory(storyId);
if (!story) {
Expand Down

0 comments on commit 8dac2f9

Please sign in to comment.