Skip to content
Draft
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
2 changes: 1 addition & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export default defineConfig({
defaultStrategy: 'viewport',
},
integrations: [
mdx(),
react(),
mdx(),
partytown({
config: {
// https://partytown.builder.io/google-tag-manager#google-analytics-4-ga4
Expand Down
17 changes: 13 additions & 4 deletions src/components/CodeBlock/LiveContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { themes } from 'prism-react-renderer';
import React, { type RefCallback, useState } from 'react';
import React, { Fragment, type RefCallback, useState } from 'react';
import Frame, { FrameContextConsumer } from 'react-frame-component';
import { LiveEditor, LiveError, LivePreview, LiveProvider } from 'react-live';
import { CssBaseLine } from 'smarthr-normalize-css';
import * as ui from 'smarthr-ui';
import styled, { StyleSheetManager, ThemeProvider, css } from 'styled-components';

import { AnnotatedComponent } from '@/components/article/AnnotatedComponent';
import { CSS_COLOR } from '@/constants/style';

import ComponentPreview from './ComponentPreview';
Expand All @@ -22,7 +23,7 @@ const smarthrTheme = ui.createTheme();
const transformCode = (snippet: string) =>
// Storybookでも利用するため、コード内に`import`・`export`が記述されているが、ここではエラーになるので削除する。
snippet.replace(/^import\s.*\sfrom\s.*$/gm, '').replace(/^export\s/gm, '');
export default function LiveContainer({ code, language, scope, noIframe, withStyled, gap, align, layout }: Props) {
export default function LiveContainer({ code, language, scope, noIframe, withStyled, gap, align, layout, canvas }: Props) {
const [iframeHeight, setIframeHeight] = useState(600); // デフォルトの高さを設定

// iframeの高さをコンテンツに合わせて変更する
Expand All @@ -42,6 +43,14 @@ export default function LiveContainer({ code, language, scope, noIframe, withSty
}, 500);
};

// Wrap preview content in AnnotatedComponent if canvas is provided
const wrapWithAnnotation = (children: React.ReactNode) => {
if (canvas) {
return <AnnotatedComponent canvasWidth={canvas}>{children}</AnnotatedComponent>;
}
return children;
};

return (
<ThemeProvider theme={smarthrTheme}>
<LiveProvider
Expand Down Expand Up @@ -74,15 +83,15 @@ export default function LiveContainer({ code, language, scope, noIframe, withSty
<StyleSheetManager target={document?.head}>
<ComponentPreview gap={gap} align={align} layout={layout}>
<CssBaseLine />
<LivePreview Component={React.Fragment} />
{wrapWithAnnotation(<LivePreview Component={React.Fragment} />)}
</ComponentPreview>
</StyleSheetManager>
)}
</FrameContextConsumer>
</Frame>
) : (
<ComponentPreview gap={gap} align={align} layout={layout}>
<LivePreview Component={React.Fragment} />
{wrapWithAnnotation(<LivePreview Component={React.Fragment} />)}
</ComponentPreview>
)}
<div className={styles.codeWrapper}>
Expand Down
5 changes: 4 additions & 1 deletion src/components/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type LiveContainerProps = {
* @deprecated noIframe は非推奨です。iframeが原因で表示が崩れるなどやむを得ない場合のみ使用してください。
*/
noIframe?: boolean;
canvas?: number;
} & Pick<LiveProviderProps, 'scope'> & {
gap?: Gap | SeparateGap;
align?: CSSProperties['alignItems'];
Expand Down Expand Up @@ -62,6 +63,7 @@ export default function CodeBlock({
layout,
code,
language,
canvas,
...componentProps // 残りのpropsはLivePreviewするコンポーネントに渡す
}: Props) {
// Storybookとのコード共通化のため、childrenで渡ってくるコードには`render()`が含まれていない。LivePreviewでコンポーネントのレンダリングが必要な場合には、末尾に追加する。
Expand All @@ -81,7 +83,7 @@ export default function CodeBlock({
<div className={styles.wrapper}>
{renderingComponent && (
<div className={styles.linkWrapper}>
<TextLink href={`${PATTERNS_STORYBOOK_URL}?path=/story/${componentTitle}/`} target="_blank">
<TextLink href={`${PATTERNS_STORYBOOK_URL}?path=/story/${componentTitle}/}`} target="_blank">
別画面で開く
</TextLink>
</div>
Expand All @@ -94,6 +96,7 @@ export default function CodeBlock({
gap={gap}
align={align}
layout={layout}
canvas={canvas}
/>
</div>
</ui.IntlProvider>
Expand Down
66 changes: 66 additions & 0 deletions src/components/article/AnnotatedComponent.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
import { AnnotatedComponent as ReactAnnotatedComponent } from './AnnotatedComponent.tsx';

interface Props {
canvasWidth?: number;
className?: string;
}

const { canvasWidth = 1000, className } = Astro.props;
---

<ReactAnnotatedComponent canvasWidth={canvasWidth} className={className} client:load>
<slot />
</ReactAnnotatedComponent>

<style lang="scss" is:global>
.annotated-container {
position: relative;
width: 100%;
margin: 0;
padding: 1rem;
padding-inline-start: 2rem;
background-color: #f8f9fa;
border-radius: 8px;
overflow: hidden;
box-sizing: border-box;
}

.annotated-content {
transform-origin: top left;
display: inline-block;
pointer-events: none;
box-sizing: border-box;
}

.annotated-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}

.annotated-label {
position: absolute;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
}

.annotated-number {
width: 1rem;
height: 1rem;
border-radius: 999px;
background-color: #e01e5a;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 0.625rem;
flex-shrink: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
</style>
Loading