Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
YumoImer committed Nov 22, 2024
0 parents commit 72d7a7a
Show file tree
Hide file tree
Showing 1,007 changed files with 38,255 additions and 0 deletions.
184 changes: 184 additions & 0 deletions .dumi/components/SemanticPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { XProvider } from '@ant-design/x';
import { Col, Flex, Row, Tag, Typography, theme } from 'antd';
import { createStyles, css } from 'antd-style';
import classnames from 'classnames';
import React from 'react';

const MARK_BORDER_SIZE = 2;

const useStyle = createStyles(({ token }, markPos: [number, number, number, number]) => ({
container: css`
position: relative;
`,
colWrap: css`
border-right: 1px solid ${token.colorBorderSecondary};
display: flex;
justify-content: center;
align-items: center;
padding: ${token.paddingMD}px;
overflow: hidden;
`,
listWrap: css`
display: flex;
flex-direction: column;
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
`,
listItem: css`
cursor: pointer;
padding: ${token.paddingSM}px;
transition: background-color ${token.motionDurationFast} ease;
&:hover {
background-color: ${token.controlItemBgHover};
}
&:not(:first-of-type) {
border-top: 1px solid ${token.colorBorderSecondary};
}
`,
marker: css`
position: absolute;
border: ${MARK_BORDER_SIZE}px solid ${token.colorWarning};
box-sizing: border-box;
z-index: 999999;
box-shadow: 0 0 0 1px #fff;
pointer-events: none;
inset-inline-start: ${markPos[0] - MARK_BORDER_SIZE}px;
top: ${markPos[1] - MARK_BORDER_SIZE}px;
width: ${markPos[2] + MARK_BORDER_SIZE * 2}px;
height: ${markPos[3] + MARK_BORDER_SIZE * 2}px;
`,
markerActive: css`
opacity: 1;
`,
markerNotActive: css`
opacity: 0;
`,
markerMotion: css`
transition:
opacity ${token.motionDurationSlow} ease,
all ${token.motionDurationSlow} ease;
`,
markerNotMotion: css`
transition: opacity ${token.motionDurationSlow} ease;
`,
}));

export interface SemanticPreviewProps {
semantics: { name: string; desc: string; version?: string }[];
children: React.ReactElement | ((injectProps: any) => React.ReactElement);
height?: number;
}

const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
const { semantics = [], children, height } = props;
const { token } = theme.useToken();

// ======================= Semantic =======================
const getMarkClassName = React.useCallback(
(semanticKey: string) => `semantic-mark-${semanticKey}`,
[],
);

const semanticClassNames = React.useMemo<Record<string, string>>(() => {
const classNames: Record<string, string> = {};

semantics.forEach((semantic) => {
classNames[semantic.name] = getMarkClassName(semantic.name);
});

return classNames;
}, [semantics]);

const injectProps = {
classNames: semanticClassNames,
};

const cloneNode =
typeof children === 'function'
? children(injectProps)
: React.cloneElement(children, injectProps);

// ======================== Hover =========================
const containerRef = React.useRef<HTMLDivElement>(null);

const timerRef = React.useRef<ReturnType<typeof setTimeout>>();

const [positionMotion, setPositionMotion] = React.useState<boolean>(false);
const [hoverSemantic, setHoverSemantic] = React.useState<string | null>(null);
const [markPos, setMarkPos] = React.useState<[number, number, number, number]>([0, 0, 0, 0]);

const { styles } = useStyle(markPos);

React.useEffect(() => {
if (hoverSemantic) {
const targetClassName = getMarkClassName(hoverSemantic);
const targetElement = containerRef.current?.querySelector<HTMLElement>(`.${targetClassName}`);
const containerRect = containerRef.current?.getBoundingClientRect();
const targetRect = targetElement?.getBoundingClientRect();
setMarkPos([
(targetRect?.left || 0) - (containerRect?.left || 0),
(targetRect?.top || 0) - (containerRect?.top || 0),
targetRect?.width || 0,
targetRect?.height || 0,
]);
timerRef.current = setTimeout(() => {
setPositionMotion(true);
}, 10);
} else {
timerRef.current = setTimeout(() => {
setPositionMotion(false);
}, 500);
}
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [hoverSemantic]);

// ======================== Render ========================
return (
<div className={classnames(styles.container)} ref={containerRef}>
<Row style={{ minHeight: height }}>
<Col span={16} className={classnames(styles.colWrap)}>
<XProvider theme={{ token: { motion: false } }}>{cloneNode}</XProvider>
</Col>
<Col span={8}>
<ul className={classnames(styles.listWrap)}>
{semantics.map<React.ReactNode>((semantic) => (
<li
key={semantic.name}
className={classnames(styles.listItem)}
onMouseEnter={() => setHoverSemantic(semantic.name)}
onMouseLeave={() => setHoverSemantic(null)}
>
<Flex vertical gap="small">
<Flex gap="small" align="center">
<Typography.Title level={5} style={{ margin: 0 }}>
{semantic.name}
</Typography.Title>
{semantic.version && <Tag color="blue">{semantic.version}</Tag>}
</Flex>
<Typography.Paragraph style={{ margin: 0, fontSize: token.fontSizeSM }}>
{semantic.desc}
</Typography.Paragraph>
</Flex>
</li>
))}
</ul>
</Col>
</Row>
<div
className={classnames(
styles.marker,
hoverSemantic ? styles.markerActive : styles.markerNotActive,
positionMotion ? styles.markerMotion : styles.markerNotMotion,
)}
/>
</div>
);
};

export default SemanticPreview;
20 changes: 20 additions & 0 deletions .dumi/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.demo-logo {
width: 120px;
min-width: 120px;
height: 32px;
background: rgba(255, 255, 255, 0.2);
border-radius: 6px;
margin-inline-end: 24px;
}

.demo-logo-vertical {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.2);
border-radius: 6px;
}

html {
scrollbar-width: thin;
scrollbar-color: unset;
}
30 changes: 30 additions & 0 deletions .dumi/hooks/use.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
function use<T>(promise: PromiseLike<T>): T {
const internal: PromiseLike<T> & {
status?: 'pending' | 'fulfilled' | 'rejected';
value?: T;
reason?: any;
} = promise;
if (internal.status === 'fulfilled') {
return internal.value as T;
}
if (internal.status === 'rejected') {
throw internal.reason;
}
if (internal.status === 'pending') {
throw internal;
}
internal.status = 'pending';
internal.then(
(result) => {
internal.status = 'fulfilled';
internal.value = result;
},
(reason) => {
internal.status = 'rejected';
internal.reason = reason;
},
);
throw internal;
}

export default use;
7 changes: 7 additions & 0 deletions .dumi/hooks/useDark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

export const DarkContext = React.createContext(false);

export default function useDark() {
return React.useContext(DarkContext);
}
21 changes: 21 additions & 0 deletions .dumi/hooks/useFetch/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default class FetchCache {
private cache: Map<string, PromiseLike<any>> = new Map();

get(key: string) {
return this.cache.get(key);
}

set(key: string, value: PromiseLike<any>) {
this.cache.set(key, value);
}

promise<T>(key: string, promiseFn: () => PromiseLike<T>): PromiseLike<T> {
const cached = this.get(key);
if (cached) {
return cached;
}
const promise = promiseFn();
this.set(key, promise);
return promise;
}
}
21 changes: 21 additions & 0 deletions .dumi/hooks/useFetch/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import fetch from 'cross-fetch';

import use from '../use';
import FetchCache from './cache';

const cache = new FetchCache();

const useFetch = <T>(options: string | { request: () => PromiseLike<T>; key: string }) => {
let request;
let key;
if (typeof options === 'string') {
request = () => fetch(options).then((res) => res.json());
key = options;
} else {
request = options.request;
key = options.key;
}
return use(cache.promise<T>(key, request));
};

export default useFetch;
17 changes: 17 additions & 0 deletions .dumi/hooks/useLayoutState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { startTransition, useState } from 'react';

const useLayoutState: typeof useState = <S>(
...args: Parameters<typeof useState<S>>
): ReturnType<typeof useState<S>> => {
const [state, setState] = useState<S>(...args);

const setLayoutState: typeof setState = (...setStateArgs) => {
startTransition(() => {
setState(...setStateArgs);
});
};

return [state, setLayoutState];
};

export default useLayoutState;
22 changes: 22 additions & 0 deletions .dumi/hooks/useLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useLocale as useDumiLocale } from 'dumi';

export interface LocaleMap<
K extends PropertyKey = PropertyKey,
V extends string | ((...params: any[]) => string) = string,
> {
cn: Record<K, V>;
en: Record<K, V>;
}

const useLocale = <
K extends PropertyKey = PropertyKey,
V extends string | ((...params: any[]) => string) = string,
>(
localeMap?: LocaleMap<K, V>,
): [Record<K, V>, 'cn' | 'en'] => {
const { id } = useDumiLocale();
const localeType = id === 'zh-CN' ? 'cn' : 'en';
return [localeMap?.[localeType]!, localeType] as const;
};

export default useLocale;
48 changes: 48 additions & 0 deletions .dumi/hooks/useLocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useLocation as useDumiLocation } from 'dumi';
import * as React from 'react';

import useLocale from './useLocale';

function clearPath(path: string) {
return path.replace('-cn', '').replace(/\/$/, '');
}

export default function useLocation() {
const location = useDumiLocation();
const { search } = location;
const [, localeType] = useLocale();

const getLink = React.useCallback(
(path: string, hash?: string | { cn: string; en: string }) => {
let pathname = clearPath(path);

if (localeType === 'cn') {
pathname = `${pathname}-cn`;
}

if (search) {
pathname = `${pathname}${search}`;
}

if (hash) {
let hashStr: string;
if (typeof hash === 'object') {
hashStr = hash[localeType];
} else {
hashStr = hash;
}

pathname = `${pathname}#${hashStr}`;
}

return pathname;
},
[localeType, search],
);

return {
...location,
pathname: clearPath(location.pathname),
getLink,
};
}
Loading

0 comments on commit 72d7a7a

Please sign in to comment.