Skip to content

Commit

Permalink
feat(docs): sourceCode support shiki
Browse files Browse the repository at this point in the history
  • Loading branch information
mortalYoung committed Feb 26, 2025
1 parent 2f9348d commit 6a63cc7
Show file tree
Hide file tree
Showing 10 changed files with 1,811 additions and 983 deletions.
19 changes: 19 additions & 0 deletions .dumi/theme/builtins/sourceCode/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.source-code {
&-container {
position: relative;
}

&-content {
max-height: 400px;
padding: 24px 20px;
overflow: auto;
}

&-shadow {
box-shadow: inset 0 6px 6px -6px #00000029;
width: 100%;
height: 3px;
position: absolute;
top: 0;
}
}
19 changes: 19 additions & 0 deletions .dumi/theme/builtins/sourceCode/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

Check failure on line 1 in .dumi/theme/builtins/sourceCode/index.tsx

View workflow job for this annotation

GitHub Actions / setup

Run autofix to sort these imports!
import { useScrollWithShadow } from '../../hooks';
import classNames from 'classnames';
import './index.less';

export default function SourceCode({ jsx }: { jsx: string }) {
const [ref, shadow] = useScrollWithShadow();

return (
<div className="source-code-container">
{shadow.top && <div className="source-code-shadow" />}
<div
ref={ref}
className={classNames('source-code-content')}
dangerouslySetInnerHTML={{ __html: jsx }}
/>
</div>
);
}
39 changes: 38 additions & 1 deletion .dumi/theme/hooks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
import { useState } from 'react';
import { useEffect, useMemo, useState } from 'react';

const RESPONSIVE_MOBILE = 768;

export function useMobile() {
const [isMobile] = useState<boolean>(window.innerWidth < RESPONSIVE_MOBILE);
return isMobile;
}

export function useScrollWithShadow<E extends HTMLElement>() {
const [element, ref] = useState<E | null>(null);

const [scrollTop, setScrollTop] = useState(0);
const [scrollHeight, setScrollHeight] = useState(0);
const [clientHeight, setClientHeight] = useState(0);

useEffect(() => {
if (!element) return;

function scrollHandler(event: Event) {
const ele = event.target as E;
setScrollTop(ele.scrollTop);
setScrollHeight(ele.scrollHeight);
setClientHeight(ele.clientHeight);
}

element.addEventListener('scroll', scrollHandler);

return () => {
element.removeEventListener('scroll', scrollHandler);
};
}, [element]);

const shadow = useMemo(() => {
const isBottom = clientHeight === scrollHeight - scrollTop;
const isTop = scrollTop === 0;
const isBetween = scrollTop > 0 && clientHeight < scrollHeight - scrollTop;
return {
top: isBottom || isBetween,
bottom: isTop || isBetween,
};
}, [scrollTop, scrollHeight, clientHeight]);

return [ref, shadow] as const;
}
29 changes: 29 additions & 0 deletions .dumi/theme/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { IApi } from 'dumi';
import ReactTechStack from 'dumi/dist/techStacks/react';
import type { ExampleBlockAsset } from 'dumi-assets-types';

class DTReactTech extends ReactTechStack {
async generateMetadata(asset: ExampleBlockAsset) {
// workaround for esm module
// const { transformerTwoslash } = await import('@shikijs/twoslash');
const { codeToHtml } = await import('shiki');
for (const [filename, dep] of Object.entries(asset.dependencies)) {
if (dep.type === 'FILE') {
const html = await codeToHtml(dep.value, {
lang: 'ts',
theme: 'vitesse-light',
// transformers: [transformerTwoslash()],
});

asset.dependencies[filename] = <any>{ ...dep, jsx: html };
}
}
return asset;
}
}

const AssetsPlugin = async (api: IApi) => {
api.registerTechStack(() => new DTReactTech());
};

export default AssetsPlugin;
226 changes: 226 additions & 0 deletions .dumi/theme/slots/PreviewerActions/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
@import (reference) '~dumi/theme-default/styles/variables.less';
@import '~dumi/theme-default/styles/utils.less';

.@{prefix}-previewer {
&-actions {
display: flex;
height: 32px;
align-items: center;
justify-content: center;

&:not(:last-child) {
border-bottom: 1px dashed @c-border-light;

@{dark-selector} & {
border-bottom-color: @c-border-less-dark;
}
}
}

&-action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: 0;
background: transparent;
cursor: pointer;

> svg {
width: 16px;
fill: darken(@c-border, 20%);
transition: fill 0.2s;

@{dark-selector} & {
fill: lighten(@c-border-dark, 20%);
}
}

&:hover > svg {
fill: darken(@c-border, 30%);

@{dark-selector} & {
fill: lighten(@c-border-dark, 30%);
}
}

&:not(:last-child) {
margin-inline-end: 4px;
}
}

&-action-sketch {
> select {
position: absolute;
appearance: none;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
}

&[data-copied] > svg {
fill: @c-success;
}
}

&-tabs {
position: relative;
padding: 0 12px;

&::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 0;
border-bottom: 1px dashed @c-border-light;

@{dark-selector} & {
border-bottom-color: @c-border-less-dark;
}
}
}
}

.@{prefix}-tabs {
overflow: hidden;

&-top {
flex-direction: column;

.@{prefix}-tabs-ink-bar {
bottom: 0;
}
}

&-nav {
display: flex;

&-wrap {
display: flex;
white-space: nowrap;
overflow: hidden;

&&-ping-left {
box-shadow: 5px 0 5px -5px rgba(0, 0, 0, 10%) inset;
}

&&-ping-right ~ * > .@{prefix}-tabs-nav-more {
box-shadow: 0 0 5px rgba(0, 0, 0, 10%);
}
}

&-list {
position: relative;
z-index: 1;
display: flex;
transition: transform 0.2s;
}

&-more {
height: 100%;
cursor: pointer;
background: none;
border: 0;
transition: box-shadow 0.2s;
}
}

&-tab {
display: flex;
margin: 0 12px;

&-btn {
padding: 0;
color: @c-text-secondary;
font-size: 14px;
line-height: 36px;
border: 0;
outline: none;
background: transparent;
box-sizing: border-box;
cursor: pointer;
transition: all 0.2s;

@{dark-selector} & {
color: @c-text-secondary-dark;
}

&:hover {
color: @c-text;

@{dark-selector} & {
color: @c-text-dark;
}
}
}

&-active &-btn {
color: @c-text;

@{dark-selector} & {
color: @c-text-dark;
}
}
}

&-ink-bar {
position: absolute;
height: 1px;
background: @c-primary;
transition: left 0.2s, width 0.2s;
pointer-events: none;

@{dark-selector} & {
background: @c-primary-dark;
}
}

&-dropdown {
position: absolute;
background: inherit;
border: 1px solid @c-border;
max-height: 200px;
overflow: auto;

@{dark-selector} & {
border-color: @c-border-dark;
}

> ul {
list-style: none;
margin: 0;
padding: 0;

> li {
padding: 4px 12px;
font-size: 14px;
cursor: pointer;

&:hover {
color: @c-primary;

@{dark-selector} & {
color: @c-primary-dark;
}
}

&:not(:last-child) {
border-bottom: 1px dashed @c-border;

@{dark-selector} & {
border-bottom-color: @c-border-dark;
}
}
}
}

&-hidden {
display: none;
}
}
}
Loading

0 comments on commit 6a63cc7

Please sign in to comment.