mirror of
https://github.com/zoriya/v10.git
synced 2026-08-15 10:23:32 +00:00
chore: consistent formatting (#47)
This commit is contained in:
Vendored
+2
-1
@@ -49,5 +49,6 @@
|
||||
"pcss",
|
||||
"postcss",
|
||||
"svg"
|
||||
]
|
||||
],
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
A monorepo for Video.js 10 related library packages, organized by platform and runtime environment.
|
||||
|
||||
---
|
||||
### 🚧 Note to new viewers 🚧
|
||||
|
||||
### 🚧 Note to new viewers 🚧
|
||||
|
||||
\[90s under-construction gif\]
|
||||
|
||||
@@ -12,17 +12,17 @@ Thanks for checking out the project! It's in its early stages and currently a mi
|
||||
|
||||
#### Get up to speed
|
||||
|
||||
* Read the [v10 discussion topic](https://github.com/videojs/video.js/discussions/9035)
|
||||
* Watch [Heff's recent presentation](https://players.brightcove.net/3737230800001/eyILA5XG7K_default/index.html?videoId=6379311036112)
|
||||
* More roadmap and architecture docs to come...
|
||||
- Read the [v10 discussion topic](https://github.com/videojs/video.js/discussions/9035)
|
||||
- Watch [Heff's recent presentation](https://players.brightcove.net/3737230800001/eyILA5XG7K_default/index.html?videoId=6379311036112)
|
||||
- More roadmap and architecture docs to come...
|
||||
|
||||
#### How you can help currently
|
||||
|
||||
* Run the React and HTML demos
|
||||
* Give us feedback in a github issue on:
|
||||
* The aesthetics of the player(s)
|
||||
* The initial embed code and component structure
|
||||
* The general direction
|
||||
- Run the React and HTML demos
|
||||
- Give us feedback in a github issue on:
|
||||
- The aesthetics of the player(s)
|
||||
- The initial embed code and component structure
|
||||
- The general direction
|
||||
|
||||
Thank you!
|
||||
|
||||
|
||||
+3
-18
@@ -1,24 +1,9 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"ignorePaths": [
|
||||
"package.json",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"ignorePaths": ["package.json", "tsconfig.json"],
|
||||
"dictionaryDefinitions": [],
|
||||
"dictionaries": [
|
||||
"css",
|
||||
"html",
|
||||
"node",
|
||||
"typescript",
|
||||
"npm"
|
||||
],
|
||||
"words": [
|
||||
"antfu",
|
||||
"noto",
|
||||
"nums",
|
||||
"rahim",
|
||||
"segoe"
|
||||
],
|
||||
"dictionaries": ["css", "html", "node", "typescript", "npm"],
|
||||
"words": ["antfu", "noto", "nums", "rahim", "segoe"],
|
||||
"ignoreWords": [],
|
||||
"import": []
|
||||
}
|
||||
|
||||
+38
-34
@@ -1,39 +1,43 @@
|
||||
import antfu from '@antfu/eslint-config';
|
||||
|
||||
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
||||
|
||||
export default antfu({
|
||||
react: true,
|
||||
typescript: true,
|
||||
formatters: {
|
||||
css: true,
|
||||
html: true,
|
||||
markdown: 'prettier',
|
||||
svg: 'prettier',
|
||||
export default antfu(
|
||||
{
|
||||
react: true,
|
||||
typescript: true,
|
||||
formatters: {
|
||||
css: true,
|
||||
html: true,
|
||||
markdown: 'prettier',
|
||||
svg: 'prettier',
|
||||
},
|
||||
stylistic: {
|
||||
semi: true,
|
||||
spacedComment: true,
|
||||
indent: 2,
|
||||
quotes: 'single',
|
||||
},
|
||||
// Many are ignored by default.
|
||||
// https://github.com/antfu/eslint-config/blob/main/src/globs.ts#L56
|
||||
ignores: ['**/.astro/'],
|
||||
plugins: {
|
||||
'jsx-a11y': jsxA11y,
|
||||
},
|
||||
rules: {
|
||||
// Allow single line bracing.
|
||||
'antfu/if-newline': 'off',
|
||||
'style/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
||||
// Only quote props when necessary.
|
||||
'style/quote-props': ['error', 'as-needed'],
|
||||
// JSX A11Y plugin rules
|
||||
...jsxA11y.configs.recommended.rules,
|
||||
},
|
||||
},
|
||||
stylistic: {
|
||||
semi: true,
|
||||
spacedComment: true,
|
||||
indent: 2,
|
||||
quotes: 'single',
|
||||
{
|
||||
files: ['**/*.md'],
|
||||
rules: {
|
||||
'style/max-len': 'off',
|
||||
},
|
||||
},
|
||||
// Many are ignored by default.
|
||||
// https://github.com/antfu/eslint-config/blob/main/src/globs.ts#L56
|
||||
ignores: ['**/.astro/'],
|
||||
plugins: {
|
||||
'jsx-a11y': jsxA11y,
|
||||
},
|
||||
rules: {
|
||||
// Allow single line bracing.
|
||||
'antfu/if-newline': 'off',
|
||||
'style/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
||||
// Only quote props when necessary.
|
||||
'style/quote-props': ['error', 'as-needed'],
|
||||
// JSX A11Y plugin rules
|
||||
...jsxA11y.configs.recommended.rules,
|
||||
},
|
||||
}, {
|
||||
files: ['**/*.md'],
|
||||
rules: {
|
||||
'style/max-len': 'off',
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
|
||||
import { MediaProvider, MediaSkinDefault, MediaSkinToasted, Video } from '@vjs-10/react';
|
||||
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import './globals.css';
|
||||
|
||||
const skins = [{
|
||||
key: 'default',
|
||||
name: 'Frosted',
|
||||
component: MediaSkinDefault,
|
||||
}, {
|
||||
key: 'toasted',
|
||||
name: 'Toasted',
|
||||
component: MediaSkinToasted,
|
||||
}] as const;
|
||||
const skins = [
|
||||
{
|
||||
key: 'default',
|
||||
name: 'Frosted',
|
||||
component: MediaSkinDefault,
|
||||
},
|
||||
{
|
||||
key: 'toasted',
|
||||
name: 'Toasted',
|
||||
component: MediaSkinToasted,
|
||||
},
|
||||
] as const;
|
||||
|
||||
type SkinKey = (typeof skins)[number]['key'];
|
||||
|
||||
const mediaSources = [{
|
||||
key: '1',
|
||||
name: 'Mux 1',
|
||||
value: 'https://stream.mux.com/fXNzVtmtWuyz00xnSrJg4OJH6PyNo6D02UzmgeKGkP5YQ.m3u8',
|
||||
}, {
|
||||
key: '2',
|
||||
name: 'Mux 2',
|
||||
value: 'https://stream.mux.com/a4nOgmxGWg6gULfcBbAa00gXyfcwPnAFldF8RdsNyk8M.m3u8',
|
||||
}, {
|
||||
key: '3',
|
||||
name: 'Mux 3',
|
||||
value: 'https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4',
|
||||
}, {
|
||||
key: '4',
|
||||
name: 'Mux 4',
|
||||
value: 'https://stream.mux.com/lyrKpPcGfqyzeI00jZAfW6MvP6GNPrkML.m3u8',
|
||||
}] as const;
|
||||
const mediaSources = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'Mux 1',
|
||||
value: 'https://stream.mux.com/fXNzVtmtWuyz00xnSrJg4OJH6PyNo6D02UzmgeKGkP5YQ.m3u8',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Mux 2',
|
||||
value: 'https://stream.mux.com/a4nOgmxGWg6gULfcBbAa00gXyfcwPnAFldF8RdsNyk8M.m3u8',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Mux 3',
|
||||
value: 'https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: 'Mux 4',
|
||||
value: 'https://stream.mux.com/lyrKpPcGfqyzeI00jZAfW6MvP6GNPrkML.m3u8',
|
||||
},
|
||||
] as const;
|
||||
|
||||
type MediaSourceKey = (typeof mediaSources)[number]['key'];
|
||||
|
||||
function getParam<T>(key: string, defaultValue: T): T {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.get(key) as T || defaultValue;
|
||||
return (params.get(key) as T) || defaultValue;
|
||||
}
|
||||
function setParam(key: string, value: string) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import App from './App';
|
||||
|
||||
import './globals.css';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
"dev:website": "turbo run dev --filter=website",
|
||||
"dev": "turbo run dev --parallel",
|
||||
"generate:icons": "turbo run generate:icons",
|
||||
"format:check": "prettier . --check --log-level warn --cache",
|
||||
"format": "prettier . --write --log-level warn --cache",
|
||||
"lint": "eslint . --cache",
|
||||
"lint:fix": "eslint . --fix --cache",
|
||||
"test": "turbo run test",
|
||||
|
||||
@@ -122,7 +122,10 @@ export class Slider {
|
||||
}
|
||||
}
|
||||
|
||||
export interface Point { x: number; y: number }
|
||||
export interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get progress ratio of a point on a line segment.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Placement } from '@floating-ui/dom';
|
||||
|
||||
import { autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom';
|
||||
|
||||
import { uniqueId } from '../utils/element-utils';
|
||||
|
||||
export class MediaPopoverRoot extends HTMLElement {
|
||||
|
||||
@@ -60,7 +60,7 @@ export class TimeSliderRootBase extends HTMLElement {
|
||||
}
|
||||
|
||||
get orientation(): 'horizontal' | 'vertical' {
|
||||
return this.getAttribute('orientation') as 'horizontal' | 'vertical' || 'horizontal';
|
||||
return (this.getAttribute('orientation') as 'horizontal' | 'vertical') || 'horizontal';
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Placement } from '@floating-ui/dom';
|
||||
import type { MediaContainer } from '@/media-container';
|
||||
|
||||
import { arrow, autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom';
|
||||
|
||||
import { uniqueId } from '../utils/element-utils';
|
||||
|
||||
export class MediaTooltipRoot extends HTMLElement {
|
||||
|
||||
@@ -62,7 +62,7 @@ export class VolumeSliderRootBase extends HTMLElement {
|
||||
}
|
||||
|
||||
get orientation(): 'horizontal' | 'vertical' {
|
||||
return this.getAttribute('orientation') as 'horizontal' | 'vertical' || 'horizontal';
|
||||
return (this.getAttribute('orientation') as 'horizontal' | 'vertical') || 'horizontal';
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MediaSkin } from '../media-skin';
|
||||
|
||||
import { uniqueId } from '../utils/element-utils';
|
||||
|
||||
import '../media-container';
|
||||
import '../components/media-play-button';
|
||||
import '../components/media-mute-button';
|
||||
|
||||
@@ -26,7 +26,12 @@ export interface ConnectedComponentConstructor<State> {
|
||||
* @param displayName - Display name for debugging
|
||||
* @returns Connected custom element class with media store integration
|
||||
*/
|
||||
export function toConnectedHTMLComponent<State = any>(BaseClass: CustomElementConstructor, stateHook: StateHook<State>, propsHook: PropsHook<State>, displayName?: string): ConnectedComponentConstructor<State> {
|
||||
export function toConnectedHTMLComponent<State = any>(
|
||||
BaseClass: CustomElementConstructor,
|
||||
stateHook: StateHook<State>,
|
||||
propsHook: PropsHook<State>,
|
||||
displayName?: string,
|
||||
): ConnectedComponentConstructor<State> {
|
||||
const ConnectedComponent = class extends ConsumerMixin(BaseClass) {
|
||||
static get observedAttributes(): string[] {
|
||||
return [
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"build:watch": "tsdown --watch --silent",
|
||||
"dev": "pnpm generate:icons && pnpm run build:watch",
|
||||
"clean": "rm -rf dist src/generated-icons",
|
||||
"format:icons": "prettier src/generated-icons --write --log-level warn --cache",
|
||||
"format:icons": "echo noop. Need to replace based on eslint vs. prettier decisions!",
|
||||
"generate:icons": "svgr --config-file svgr.config.js --out-dir src/generated-icons ../../core/icons/assets && pnpm format:icons",
|
||||
"test": "echo \"No tests yet\""
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ export function useMediaStore(): MediaStore {
|
||||
return useContext(MediaContext);
|
||||
}
|
||||
|
||||
export function useMediaDispatch(): ((value: any) => unknown) {
|
||||
export function useMediaDispatch(): (value: any) => unknown {
|
||||
const store = useContext(MediaContext);
|
||||
const dispatch = store?.dispatch ?? identity;
|
||||
return (value: any) => {
|
||||
@@ -118,7 +118,10 @@ export function shallowEqual(objA: any, objB: any): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function useMediaSelector<S = any,>(selector: (state: any) => S, equalityFn: (a: S, b: S) => boolean = refEquality): S {
|
||||
export function useMediaSelector<S = any>(
|
||||
selector: (state: any) => S,
|
||||
equalityFn: (a: S, b: S) => boolean = refEquality,
|
||||
): S {
|
||||
const store = useContext(MediaContext);
|
||||
const selectedState = useSyncExternalStoreWithSelector(
|
||||
store?.subscribe ?? identity,
|
||||
|
||||
@@ -23,7 +23,10 @@ export function useCurrentTimeDisplayState(_props: any): {
|
||||
export type useCurrentTimeDisplayState = typeof useCurrentTimeDisplayState;
|
||||
export type CurrentTimeDisplayState = ReturnType<useCurrentTimeDisplayState>;
|
||||
|
||||
export function useCurrentTimeDisplayProps(props: PropsWithChildren, _state: ReturnType<typeof useCurrentTimeDisplayState>): PropsWithChildren<Record<string, unknown>> {
|
||||
export function useCurrentTimeDisplayProps(
|
||||
props: PropsWithChildren,
|
||||
_state: ReturnType<typeof useCurrentTimeDisplayState>,
|
||||
): PropsWithChildren<Record<string, unknown>> {
|
||||
const baseProps: Record<string, any> = {
|
||||
/** external props spread last to allow for overriding */
|
||||
...props,
|
||||
|
||||
@@ -32,7 +32,10 @@ export function useFullscreenButtonState(_props: any): {
|
||||
export type useFullscreenButtonState = typeof useFullscreenButtonState;
|
||||
export type FullscreenButtonState = ReturnType<useFullscreenButtonState>;
|
||||
|
||||
export function useFullscreenButtonProps(props: PropsWithChildren, state: ReturnType<typeof useFullscreenButtonState>): PropsWithChildren<Record<string, unknown>> {
|
||||
export function useFullscreenButtonProps(
|
||||
props: PropsWithChildren,
|
||||
state: ReturnType<typeof useFullscreenButtonState>,
|
||||
): PropsWithChildren<Record<string, unknown>> {
|
||||
const baseProps: Record<string, any> = {
|
||||
/** @TODO Need another state provider in core for i18n (CJP) */
|
||||
/** aria attributes/props */
|
||||
|
||||
@@ -52,12 +52,14 @@ export function useMediaContainerRef(): RefCallback<HTMLElement | null> {
|
||||
* </MediaContainer>
|
||||
* );
|
||||
*/
|
||||
export const MediaContainer: FC<PropsWithChildren<HTMLProps<HTMLDivElement>>> = forwardRef(({ children, ...props }, ref) => {
|
||||
const containerRef = useMediaContainerRef();
|
||||
const composedRef = useComposedRefs(ref, containerRef);
|
||||
return (
|
||||
<div ref={composedRef} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
export const MediaContainer: FC<PropsWithChildren<HTMLProps<HTMLDivElement>>> = forwardRef(
|
||||
({ children, ...props }, ref) => {
|
||||
const containerRef = useMediaContainerRef();
|
||||
const composedRef = useComposedRefs(ref, containerRef);
|
||||
return (
|
||||
<div ref={composedRef} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -32,7 +32,10 @@ export function useMuteButtonState(_props: any): {
|
||||
export type useMuteButtonState = typeof useMuteButtonState;
|
||||
export type MuteButtonState = ReturnType<useMuteButtonState>;
|
||||
|
||||
export function useMuteButtonProps(props: PropsWithChildren, state: ReturnType<typeof useMuteButtonState>): PropsWithChildren<Record<string, unknown>> {
|
||||
export function useMuteButtonProps(
|
||||
props: PropsWithChildren,
|
||||
state: ReturnType<typeof useMuteButtonState>,
|
||||
): PropsWithChildren<Record<string, unknown>> {
|
||||
const baseProps: Record<string, any> = {
|
||||
/** data attributes/props - non-boolean */
|
||||
'data-volume-level': state.volumeLevel,
|
||||
|
||||
@@ -30,7 +30,10 @@ export function usePlayButtonState(_props: any): {
|
||||
export type usePlayButtonState = typeof usePlayButtonState;
|
||||
export type PlayButtonState = ReturnType<usePlayButtonState>;
|
||||
|
||||
export function usePlayButtonProps(props: Record<string, unknown>, state: ReturnType<typeof usePlayButtonState>): PropsWithChildren<Record<string, unknown>> {
|
||||
export function usePlayButtonProps(
|
||||
props: Record<string, unknown>,
|
||||
state: ReturnType<typeof usePlayButtonState>,
|
||||
): PropsWithChildren<Record<string, unknown>> {
|
||||
const baseProps: Record<string, any> = {
|
||||
/** @TODO Need another state provider in core for i18n (CJP) */
|
||||
/** aria attributes/props */
|
||||
|
||||
@@ -150,7 +150,11 @@ function PopoverPopup({ className, children }: PopoverPopupProps): JSX.Element {
|
||||
}
|
||||
|
||||
function PopoverPortal({ children, root, rootId }: PopoverPortalProps): JSX.Element {
|
||||
return <FloatingPortal root={root as HTMLElement} id={rootId as string}>{children}</FloatingPortal>;
|
||||
return (
|
||||
<FloatingPortal root={root as HTMLElement} id={rootId as string}>
|
||||
{children}
|
||||
</FloatingPortal>
|
||||
);
|
||||
}
|
||||
|
||||
// Export compound component
|
||||
|
||||
@@ -156,7 +156,12 @@ function TooltipTrigger({ children }: TooltipTriggerProps): JSX.Element {
|
||||
});
|
||||
}
|
||||
|
||||
function TooltipPositioner({ side = 'top', sideOffset = 0, collisionPadding = 0, children }: TooltipPositionerProps): JSX.Element | null {
|
||||
function TooltipPositioner({
|
||||
side = 'top',
|
||||
sideOffset = 0,
|
||||
collisionPadding = 0,
|
||||
children,
|
||||
}: TooltipPositionerProps): JSX.Element | null {
|
||||
const { context, updatePositioning } = useTooltipContext();
|
||||
const { refs, floatingStyles } = context;
|
||||
|
||||
@@ -232,7 +237,11 @@ function TooltipArrow({ className = '', children }: TooltipArrowProps): JSX.Elem
|
||||
}
|
||||
|
||||
function TooltipPortal({ children, root, rootId }: TooltipPortalProps): JSX.Element {
|
||||
return <FloatingPortal root={root as HTMLElement} id={rootId as string}>{children}</FloatingPortal>;
|
||||
return (
|
||||
<FloatingPortal root={root as HTMLElement} id={rootId as string}>
|
||||
{children}
|
||||
</FloatingPortal>
|
||||
);
|
||||
}
|
||||
|
||||
// Export compound component
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
VolumeLowIcon,
|
||||
VolumeOffIcon,
|
||||
} from '@vjs-10/react-icons';
|
||||
|
||||
import { useId } from 'react';
|
||||
|
||||
import { CurrentTimeDisplay } from '../../components/CurrentTimeDisplay';
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '@vjs-10/react-icons';
|
||||
|
||||
import { CurrentTimeDisplay } from '../../components/CurrentTimeDisplay';
|
||||
|
||||
import { DurationDisplay } from '../../components/DurationDisplay';
|
||||
import { FullscreenButton } from '../../components/FullscreenButton';
|
||||
import { MediaContainer } from '../../components/MediaContainer';
|
||||
@@ -69,4 +70,4 @@ export default function MediaSkinDefault({ children, className = '' }: SkinProps
|
||||
</div>
|
||||
</MediaContainer>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { MediaToastedSkinStyles } from './types';
|
||||
|
||||
import { cn } from '../../utils/cn';
|
||||
|
||||
const styles: MediaToastedSkinStyles = {
|
||||
|
||||
@@ -28,7 +28,12 @@ export function toConnectedComponent<
|
||||
TState,
|
||||
TResultProps extends Record<string, any>,
|
||||
TRenderFn extends RenderFn<TResultProps, TState>,
|
||||
>(useStateHook: StateHookFn<TProps, TState>, usePropsHook: PropsHookFn<TProps, TState, TResultProps>, defaultRender: TRenderFn, displayName: string): ConnectedComponent<TProps, TRenderFn> {
|
||||
>(
|
||||
useStateHook: StateHookFn<TProps, TState>,
|
||||
usePropsHook: PropsHookFn<TProps, TState, TResultProps>,
|
||||
defaultRender: TRenderFn,
|
||||
displayName: string,
|
||||
): ConnectedComponent<TProps, TRenderFn> {
|
||||
const ConnectedComponent = forwardRef<any, TProps & { render?: TRenderFn }>(
|
||||
({ render = defaultRender, ...props }, ref) => {
|
||||
const connectedState = useStateHook(props as TProps);
|
||||
@@ -64,7 +69,11 @@ export function toContextComponent<
|
||||
TProps extends Record<string, any>,
|
||||
TResultProps extends Record<string, any>,
|
||||
TRenderFn extends (props: TResultProps, context: any) => ReactElement,
|
||||
>(usePropsHook: (props: TProps, context: any) => TResultProps, defaultRender: TRenderFn, displayName: string): ContextComponent<TProps, TRenderFn> {
|
||||
>(
|
||||
usePropsHook: (props: TProps, context: any) => TResultProps,
|
||||
defaultRender: TRenderFn,
|
||||
displayName: string,
|
||||
): ContextComponent<TProps, TRenderFn> {
|
||||
const ContextComponent = forwardRef<any, TProps & { render?: TRenderFn }>(
|
||||
({ render = defaultRender, ...props }, ref) => {
|
||||
const context = useContext(Context);
|
||||
|
||||
+2
-6
@@ -134,13 +134,9 @@ Documentation pages can be restricted to specific frameworks or styles:
|
||||
**Within MDX content** (using conditional components):
|
||||
|
||||
```mdx
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
This content only appears in React docs.
|
||||
</FrameworkCase>
|
||||
<FrameworkCase frameworks={['react']}>This content only appears in React docs.</FrameworkCase>
|
||||
|
||||
<StyleCase styles={["tailwind"]}>
|
||||
This content only appears when Tailwind is selected.
|
||||
</StyleCase>
|
||||
<StyleCase styles={['tailwind']}>This content only appears when Tailwind is selected.</StyleCase>
|
||||
```
|
||||
|
||||
##### Static Site Generation
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { file } from 'astro/loaders';
|
||||
import { defineCollection, reference, z } from 'astro:content';
|
||||
import { simpleGit } from 'simple-git';
|
||||
|
||||
import { globWithParser } from './utils/globWithParser';
|
||||
|
||||
const git = simpleGit();
|
||||
@@ -12,9 +13,7 @@ const git = simpleGit();
|
||||
function extractDateFromFilename(id: string): Date {
|
||||
const match = id.match(/^(\d{4})-(\d{2})-(\d{2})-/);
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`Filename "${id}" must follow format: YYYY-MM-DD-slug.{md,mdx}`,
|
||||
);
|
||||
throw new Error(`Filename "${id}" must follow format: YYYY-MM-DD-slug.{md,mdx}`);
|
||||
}
|
||||
|
||||
const [, year, month, day] = match;
|
||||
@@ -59,10 +58,7 @@ const blog = defineCollection({
|
||||
data: {
|
||||
...entry.data,
|
||||
pubDate,
|
||||
...(updatedDate
|
||||
&& updatedDate.getTime() !== pubDate.getTime()
|
||||
? { updatedDate }
|
||||
: {}),
|
||||
...(updatedDate && updatedDate.getTime() !== pubDate.getTime() ? { updatedDate } : {}),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import rss from '@astrojs/rss';
|
||||
|
||||
import { getCollection } from 'astro:content';
|
||||
import { SITE_DESCRIPTION, SITE_TITLE } from '@/consts';
|
||||
|
||||
|
||||
@@ -3,30 +3,23 @@ export const FRAMEWORK_STYLES = {
|
||||
react: ['css', 'tailwind', 'styled-components'],
|
||||
} as const;
|
||||
|
||||
export const SUPPORTED_FRAMEWORKS = Object.keys(
|
||||
FRAMEWORK_STYLES,
|
||||
) as (keyof typeof FRAMEWORK_STYLES)[];
|
||||
export const SUPPORTED_FRAMEWORKS = Object.keys(FRAMEWORK_STYLES) as (keyof typeof FRAMEWORK_STYLES)[];
|
||||
|
||||
export type SupportedFramework = keyof typeof FRAMEWORK_STYLES;
|
||||
export type SupportedStyle<F extends SupportedFramework>
|
||||
= (typeof FRAMEWORK_STYLES)[F][number];
|
||||
export type SupportedStyle<F extends SupportedFramework> = (typeof FRAMEWORK_STYLES)[F][number];
|
||||
export type AnySupportedStyle = SupportedStyle<SupportedFramework>;
|
||||
|
||||
/**
|
||||
* Get the available styles for a given framework
|
||||
*/
|
||||
export function getAvailableStyles<F extends SupportedFramework>(
|
||||
framework: F,
|
||||
): readonly SupportedStyle<F>[] {
|
||||
export function getAvailableStyles<F extends SupportedFramework>(framework: F): readonly SupportedStyle<F>[] {
|
||||
return FRAMEWORK_STYLES[framework];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default style for a given framework (first available style)
|
||||
*/
|
||||
export function getDefaultStyle<F extends SupportedFramework>(
|
||||
framework: F,
|
||||
): SupportedStyle<F> {
|
||||
export function getDefaultStyle<F extends SupportedFramework>(framework: F): SupportedStyle<F> {
|
||||
return FRAMEWORK_STYLES[framework][0];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { SupportedFramework, SupportedStyle } from '@/types/docs';
|
||||
|
||||
import { findFirstGuide } from '@/utils/docs/sidebar';
|
||||
|
||||
/**
|
||||
@@ -11,16 +12,11 @@ import { findFirstGuide } from '@/utils/docs/sidebar';
|
||||
* @returns The full docs URL to redirect to
|
||||
* @throws Error if no guide is available for the given framework/style
|
||||
*/
|
||||
export function getDocsRedirectUrl<F extends SupportedFramework>(
|
||||
framework: F,
|
||||
style: SupportedStyle<F>,
|
||||
): string {
|
||||
export function getDocsRedirectUrl<F extends SupportedFramework>(framework: F, style: SupportedStyle<F>): string {
|
||||
const firstGuide = findFirstGuide(framework, style);
|
||||
|
||||
if (!firstGuide) {
|
||||
throw new Error(
|
||||
`No guide available for framework "${framework}" and style "${style}"`,
|
||||
);
|
||||
throw new Error(`No guide available for framework "${framework}" and style "${style}"`);
|
||||
}
|
||||
|
||||
return `/docs/framework/${framework}/style/${style}/${firstGuide}/`;
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import type { AnySupportedStyle, Guide, Section, Sidebar, SupportedFramework, SupportedStyle } from '@/types/docs';
|
||||
|
||||
import { sidebar } from '@/config/docs/sidebar';
|
||||
import {
|
||||
|
||||
getAvailableStyles,
|
||||
|
||||
isSection,
|
||||
|
||||
} from '@/types/docs';
|
||||
import { getAvailableStyles, isSection } from '@/types/docs';
|
||||
|
||||
/**
|
||||
* Check if an item (Guide or Section) should be shown based on framework and style.
|
||||
@@ -18,13 +13,8 @@ import {
|
||||
* @param style - The currently selected style
|
||||
* @returns true if the item should be visible
|
||||
*/
|
||||
function isItemVisible(
|
||||
item: Guide | Section,
|
||||
framework: SupportedFramework,
|
||||
style: AnySupportedStyle,
|
||||
): boolean {
|
||||
const frameworkMatch
|
||||
= !item.frameworks || item.frameworks.includes(framework);
|
||||
function isItemVisible(item: Guide | Section, framework: SupportedFramework, style: AnySupportedStyle): boolean {
|
||||
const frameworkMatch = !item.frameworks || item.frameworks.includes(framework);
|
||||
const styleMatch = !item.styles || item.styles.includes(style);
|
||||
return frameworkMatch && styleMatch;
|
||||
}
|
||||
@@ -133,10 +123,7 @@ export function getAllGuideSlugs(sidebarToExtract: Sidebar = sidebar): string[]
|
||||
* @param sidebarToSearch - Optional sidebar to search (defaults to main sidebar config)
|
||||
* @returns The guide object if found, null otherwise
|
||||
*/
|
||||
export function findGuideBySlug(
|
||||
slug: string,
|
||||
sidebarToSearch: Sidebar = sidebar,
|
||||
): Guide | null {
|
||||
export function findGuideBySlug(slug: string, sidebarToSearch: Sidebar = sidebar): Guide | null {
|
||||
for (const item of sidebarToSearch) {
|
||||
if (isSection(item)) {
|
||||
// Recursively search section contents
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ParseDataOptions } from 'astro/loaders';
|
||||
|
||||
import { glob } from 'astro/loaders';
|
||||
|
||||
/**
|
||||
@@ -7,7 +8,7 @@ import { glob } from 'astro/loaders';
|
||||
*/
|
||||
type Parser = <TData extends Record<string, unknown>>(
|
||||
options: ParseDataOptions<TData>,
|
||||
originalEntry: string,
|
||||
originalEntry: string
|
||||
) => Promise<ParseDataOptions<TData>>;
|
||||
|
||||
type GlobWithParserOptions = Parameters<typeof glob>[0] & {
|
||||
@@ -36,11 +37,7 @@ type GlobWithParserOptions = Parameters<typeof glob>[0] & {
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function globWithParser({
|
||||
parser,
|
||||
generateId,
|
||||
...globOptions
|
||||
}: GlobWithParserOptions) {
|
||||
export function globWithParser({ parser, generateId, ...globOptions }: GlobWithParserOptions) {
|
||||
/**
|
||||
* Store mapping of transformed IDs to original entry filenames.
|
||||
* Created per-invocation to avoid memory leaks across builds.
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
},
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
".astro/types.d.ts",
|
||||
"**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"dist"
|
||||
]
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user