Skip to content
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
6 changes: 6 additions & 0 deletions docs/docs/about.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Cards } from '#components/cards/cards.tsx';

export const meta = {
title: 'About',
category: '',
Expand Down Expand Up @@ -27,3 +29,7 @@ Some utilities are created for training and educational purposes.
- Well tested by unit/e2e
- No dependencies (except optional peers)
- Tree Shaking ready

## Sections

<Cards />
27 changes: 27 additions & 0 deletions docs/src/components/cards/cards.m.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.root {
display: flex;
gap: 12px;
flex-wrap: wrap;
}

.item {
width: 0;
flex-grow: 1;
flex-basis: calc(50% - 6px);
transition: scale 200ms;
}

.item:hover {
scale: 1.025;
}

a.item {
color: inherit !important;
text-decoration: none !important;
}

@media (max-width: 1024px) {
.item {
flex-basis: 100%;
}
}
59 changes: 59 additions & 0 deletions docs/src/components/cards/cards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Callout } from '#components/callout/callout.tsx';
import { Link } from '#components/link/link.tsx';
import { withPublicPath } from '../../utils.ts';
import styles from './cards.m.css';

export function Cards() {
return (
<div className={styles.root}>
<Link className={styles.item} href={withPublicPath('./react/overview')}>
<Callout>
<Callout.Heading>React</Callout.Heading>
<Callout.Main>SSR ready performant components and hooks</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./rspack/overview')}>
<Callout>
<Callout.Heading>Rspack</Callout.Heading>
<Callout.Main>Plugins to define configs easy</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./typescript/overview')}>
<Callout>
<Callout.Heading>Typings</Callout.Heading>
<Callout.Main>TypeScript type declarations</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./di/overview')}>
<Callout>
<Callout.Heading>DI</Callout.Heading>
<Callout.Main>Dependency injection toolkit</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./router/browser-router')}>
<Callout>
<Callout.Heading>Router</Callout.Heading>
<Callout.Main>Router implementation and React bindings</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./math/overview')}>
<Callout>
<Callout.Heading>Math</Callout.Heading>
<Callout.Main>Math and geometry functions</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./misc/overview')}>
<Callout>
<Callout.Heading>Misc</Callout.Heading>
<Callout.Main>Non specific helpers</Callout.Main>
</Callout>
</Link>
<Link className={styles.item} href={withPublicPath('./dom/overview')}>
<Callout>
<Callout.Heading>DOM</Callout.Heading>
<Callout.Main>Browser utilities</Callout.Main>
</Callout>
</Link>
</div>
);
}
33 changes: 16 additions & 17 deletions docs/src/components/code-block/code-block.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-console */
import { ReactNode, isValidElement, useMemo, useRef, useState } from 'react';
import { useIsomorphicLayoutEffect } from '@krutoo/utils/react';
import { codeToHtml } from 'shiki';
import { getProcessedLang, useHighlighter } from './utils.ts';
import styles from './code-block.m.css';

export interface CodeBlockProps {
Expand All @@ -15,6 +15,7 @@ interface CodeProps {
}

export function CodeBlock({ title, children }: CodeBlockProps) {
const highlighter = useHighlighter();
const [content, setContent] = useState('');
const [background, setBackground] = useState<string | undefined>(undefined);
const blockRef = useRef<HTMLDivElement>(null);
Expand All @@ -38,32 +39,30 @@ export function CodeBlock({ title, children }: CodeBlockProps) {
return null;
}

let lang = /^language-(.+)$/g.exec(children.props.className ?? '')?.[1];

if (!lang) {
lang = 'plaintext';
}

// traffic economy - load one bundle of shiki syntax for multiple syntaxes
if (['js', 'jsx', 'ts', 'javascript', 'typescript'].includes(lang.toLowerCase())) {
lang = 'tsx';
}
const lang = /^language-(.+)$/g.exec(children.props.className ?? '')?.[1] ?? 'plaintext';

return {
code: children.props.children,
lang,
lang: getProcessedLang(lang),
};
}, [children]);

useIsomorphicLayoutEffect(() => {
if (!sourceCode) {
if (!highlighter || !sourceCode) {
return;
}

codeToHtml(sourceCode.code, { lang: sourceCode.lang, theme: 'poimandres' })
.then(setContent)
.catch(console.error);
}, [sourceCode]);
try {
const html = highlighter.codeToHtml(sourceCode.code, {
lang: sourceCode.lang,
theme: 'poimandres',
});

setContent(html);
} catch (error) {
console.error(error);
}
}, [highlighter, sourceCode]);

return (
<div className={styles.root} style={{ background }}>
Expand Down
66 changes: 66 additions & 0 deletions docs/src/components/code-block/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useEffect, useState } from 'react';
import { once } from '@krutoo/utils';
import { type HighlighterCore, createHighlighterCore, createJavaScriptRegexEngine } from 'shiki';
import themeOneDarkPro from 'shiki/themes/poimandres.mjs';

// IMPORTANT: make singleton by using `once` according to "shiki" docs
export const getHighlighterCore = once((): Promise<HighlighterCore> => {
return createHighlighterCore({
engine: createJavaScriptRegexEngine(),
langs: [
// supported langs:
import('shiki/langs/sh.mjs'),
import('shiki/langs/tsx.mjs'),
import('shiki/langs/css.mjs'),
],
themes: [
// themes:
themeOneDarkPro,
],
});
});

export function useHighlighter(): HighlighterCore | null {
const [highlighter, setHighlighter] = useState<HighlighterCore | null>(null);

useEffect(() => {
let mount = true;

getHighlighterCore()
.then(result => {
if (!mount) {
return;
}

setHighlighter(result);
})
// eslint-disable-next-line no-console
.catch(console.error);

return () => {
mount = false;
};
}, []);

return highlighter;
}

export function getProcessedLang(lang: string): string {
// make lang from ext (remove first dot if exist)
switch (lang.replace(/^\./, '')) {
case 'sh':
case 'bash':
case 'shell':
case 'shellscript':
return 'sh';

case 'js':
case 'jsx':
case 'ts':
case 'tsx':
return 'tsx';

default:
return lang;
}
}
6 changes: 3 additions & 3 deletions docs/src/components/link/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ export function Link({
...restProps
}: AnchorHTMLAttributes<HTMLAnchorElement>) {
const navigate = useNavigate();
const [internal, setInternal] = useState(false);
const [external, setExternal] = useState(false);

useEffect(() => {
if (!href) {
return;
}

setInternal(new URL(new Request(href).url).hostname === new URL(window.location.href).hostname);
setExternal(new URL(new Request(href).url).hostname !== new URL(window.location.href).hostname);
}, [href]);

const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {
Expand All @@ -29,7 +29,7 @@ export function Link({
navigate(event.currentTarget.href);
};

const resultTarget = target ?? (!internal ? '_blank' : undefined);
const resultTarget = target ?? (external ? '_blank' : undefined);

return <a href={href} target={resultTarget} {...restProps} onClick={handleClick} />;
}
Loading