diff --git a/packages/storylite/src/app/stores/global.ts b/packages/storylite/src/app/stores/global.ts index 5aec4d4..3f6b5ca 100644 --- a/packages/storylite/src/app/stores/global.ts +++ b/packages/storylite/src/app/stores/global.ts @@ -15,6 +15,7 @@ const builtinAddons: SLAddonsMap = new Map( ) const defaultState: StoryLiteState = { + basePath: import.meta.env.BASE_URL, canvas: { element: null, standalone: false, diff --git a/packages/storylite/src/app/stores/global.types.ts b/packages/storylite/src/app/stores/global.types.ts index c41b781..d589267 100644 --- a/packages/storylite/src/app/stores/global.types.ts +++ b/packages/storylite/src/app/stores/global.types.ts @@ -15,6 +15,7 @@ export type StoryLiteCanvasState = { export type StoryLiteParamValue = string | string[] | number | number[] | boolean | undefined | null export type StoryLiteState = { + basePath: string config: Required canvas: StoryLiteCanvasState parameters: SLParameters diff --git a/packages/storylite/src/services/csf-api/navigation.tsx b/packages/storylite/src/services/csf-api/navigation.tsx index cddf048..181fb01 100644 --- a/packages/storylite/src/services/csf-api/navigation.tsx +++ b/packages/storylite/src/services/csf-api/navigation.tsx @@ -1,7 +1,7 @@ import { SLNode, StoryModuleMap } from '@/types' import { isTruthy } from '@/utility' -import { asCleanHash } from '../router/router.utils' +import { STORYLITE_BASE_PATH } from '../router' export type SLNavigationNode = { title: string @@ -14,10 +14,6 @@ export type SLNavigationNode = { type SLTopLevelNavigation = SLNavigationNode[] -export function getStoryUrlHash(storyId: string): string { - return `/#/stories/${asCleanHash(storyId)}` -} - export function getStoryUrl( storyId: string | undefined, options: { standalone?: boolean; target: 'top' | 'iframe' } = { @@ -28,17 +24,19 @@ export function getStoryUrl( const { standalone, target } = options const isIframe = target === 'iframe' - const targetBasePath = isIframe ? '/canvas.html#' : '/#' - const targetHashBasePath = isIframe ? '/preview/' : '/' - const baseStr = `${targetBasePath}${targetHashBasePath}`.replace(/\/\//g, '/') + const targetBasePath = isIframe ? '/canvas.html#' : '#' + const targetHashBasePath = isIframe ? 'preview/' : '' + const baseStr = [STORYLITE_BASE_PATH, targetBasePath, targetHashBasePath] + .join('') + .replace(/\/\//g, '/') - let url = storyId === undefined ? baseStr : `${baseStr}stories/${storyId}` + let url = storyId === undefined ? baseStr : `${baseStr}/stories/${storyId}` if (standalone) { url += `/?standalone=true` } - return url + return url.replace(/\/\//g, '/') } // TODO: support nested levels by splitting the title on `/` @@ -50,7 +48,7 @@ export function getStoryNavigationTree(storyModuleMap: StoryModuleMap): SLTopLev const topNode: SLNavigationNode = { title: stories.default?.title || storiesFileId, storyId: stories.default?.id || storiesFileId, - href: getStoryUrlHash(storiesFileId), + href: getStoryUrl(storiesFileId, { target: 'top', standalone: false }), icon: stories.default?.navigation?.icon, iconExpanded: stories.default?.navigation?.iconExpanded, children: [], @@ -64,7 +62,7 @@ export function getStoryNavigationTree(storyModuleMap: StoryModuleMap): SLTopLev const childNode: SLNavigationNode = { title: story.title || exportedName, storyId: story.id, - href: getStoryUrlHash(story.id), + href: getStoryUrl(story.id, { target: 'top', standalone: false }), icon: story.navigation?.icon, iconExpanded: story.navigation?.iconExpanded, children: [], // TODO: support nested levels in a future implementation diff --git a/packages/storylite/src/services/router/constants.ts b/packages/storylite/src/services/router/constants.ts new file mode 100644 index 0000000..521d183 --- /dev/null +++ b/packages/storylite/src/services/router/constants.ts @@ -0,0 +1 @@ +export const STORYLITE_BASE_PATH = import.meta.env.BASE_URL diff --git a/packages/storylite/src/services/router/index.ts b/packages/storylite/src/services/router/index.ts index e928039..ed6cff7 100644 --- a/packages/storylite/src/services/router/index.ts +++ b/packages/storylite/src/services/router/index.ts @@ -1,5 +1,6 @@ +export * from './constants' +export * from './createStoryLiteRouter' export * from './router.class' export * from './router.component' -export * from './createStoryLiteRouter' export * from './router.store' export * from './router.types' diff --git a/packages/storylite/src/services/router/router.class.ts b/packages/storylite/src/services/router/router.class.ts index dbf4f4f..1a0d33e 100644 --- a/packages/storylite/src/services/router/router.class.ts +++ b/packages/storylite/src/services/router/router.class.ts @@ -2,7 +2,6 @@ import React from 'react' import { CurrentRoute, Route } from './router.types' import { - asAbsoluteHash, createPatternRegex, getWindowHash, parseHashbangPath, @@ -79,7 +78,7 @@ export class Router implements Iterable { } navigate(path: string, query?: URLSearchParams | Record, replace = false): void { - const absPath = asAbsoluteHash(path) + const absPath = path // asAbsoluteHash(path) // const relPath = asRelativeHash(path) const newUrl = new URL(absPath, window.location.origin) newUrl.search = new URLSearchParams(query).toString() diff --git a/packages/storylite/src/services/router/router.component.tsx b/packages/storylite/src/services/router/router.component.tsx index 39d1d29..ea82c3f 100644 --- a/packages/storylite/src/services/router/router.component.tsx +++ b/packages/storylite/src/services/router/router.component.tsx @@ -2,7 +2,7 @@ import { HTMLAttributes, ReactNode } from 'react' import { useRouterStore } from './router.store' import { CurrentRoute } from './router.types' -import { asAbsoluteHash, parseWindowHash } from './router.utils' +import { parseWindowHash } from './router.utils' export type RouteRendererProps = { route?: CurrentRoute @@ -42,7 +42,7 @@ export const Link = ({ return ( { e.preventDefault() navigate(to) diff --git a/packages/storylite/src/services/router/router.utils.ts b/packages/storylite/src/services/router/router.utils.ts index eddb547..e2e11f7 100644 --- a/packages/storylite/src/services/router/router.utils.ts +++ b/packages/storylite/src/services/router/router.utils.ts @@ -1,5 +1,15 @@ export function cleanHashBang(path: string): string { - return path + const parts = path.split('#', 2) + if (parts.length === 1) { + return parts[0] + } + if (parts.length === 0) { + return '' + } + + const hash = parts[1] + + return hash .replace(/(^#|^\/#)/, '') .replace(/(^\/+|\/+$)/, '') .replace(/\/+/g, '/') @@ -11,15 +21,17 @@ export function parseHashbangPath(path?: string): [string, URLSearchParams] { return ['', new URLSearchParams()] } - if (!path.match(/^(\/?#)|([a-z]+\:)/)) { - path = '/#/' + path + let cleanPath = cleanHashBang(path) + + if (!cleanPath.match(/^(\/?#)|([a-z]+\:)/)) { + cleanPath = '/#/' + cleanPath } - if (path.startsWith('/') && !path.startsWith('/#')) { - path = '/#' + path + if (cleanPath.startsWith('#') && !cleanPath.startsWith('#/')) { + cleanPath = '#/' + cleanPath } - const url = new URL(path, window.location.origin) + const url = new URL(cleanPath, window.location.origin) const queryFromHash = url.hash.split('?') if (queryFromHash.length > 1) { url.search = queryFromHash[1]