Skip to content

Commit 854d735

Browse files
authored
Merge pull request #30 from barocss/feat/codegroup-astro-and-styles
feat(theme-docs): CodeGroup Astro 전환 및 코드 영역 여백
2 parents 275570d + ef6d1e2 commit 854d735

5 files changed

Lines changed: 101 additions & 36 deletions

File tree

docs/src/content/docs/en/components/code-group.mdx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
title: Code Group
33
description: Display multiple code blocks in a tabbed interface
44
---
5-
import { CodeGroup } from "@barodoc/theme-docs/components/mdx/CodeGroup.tsx";
5+
import CodeGroup from "@barodoc/theme-docs/components/mdx/CodeGroup.astro";
66
import { ParamField, ParamFieldGroup } from "@barodoc/theme-docs/components/mdx/ParamField.tsx";
77

88
Code groups allow you to display multiple code examples in a tabbed interface, making it easy to show the same functionality in different languages.
99

1010
## Basic Usage
1111

12-
<CodeGroup client:load titles={["JavaScript", "Python", "Go"]}>
12+
<CodeGroup titles={["JavaScript", "Python", "Go"]}>
1313

1414
```javascript
1515
const greeting = "Hello, World!";
@@ -35,7 +35,7 @@ func main() {
3535
</CodeGroup>
3636

3737
```mdx
38-
<CodeGroup client:load titles={["JavaScript", "Python", "Go"]}>
38+
<CodeGroup titles={["JavaScript", "Python", "Go"]}>
3939

4040
\`\`\`javascript
4141
const greeting = "Hello, World!";
@@ -61,7 +61,7 @@ func main() {
6161

6262
## Package Manager Example
6363

64-
<CodeGroup client:load titles={["npm", "pnpm", "yarn", "bun"]}>
64+
<CodeGroup titles={["npm", "pnpm", "yarn", "bun"]}>
6565

6666
```bash
6767
npm install @barodoc/core
@@ -87,7 +87,4 @@ bun add @barodoc/core
8787
<ParamField name="titles" type="string[]">
8888
Array of tab labels for each code block
8989
</ParamField>
90-
<ParamField name="client:load" type="directive" required>
91-
Required Astro directive for client-side interactivity
92-
</ParamField>
9390
</ParamFieldGroup>

docs/src/content/docs/ko/components/code-group.mdx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
title: Code Group
33
description: 여러 코드 블록을 탭 인터페이스로 표시
44
---
5-
import { CodeGroup } from "@barodoc/theme-docs/components/mdx/CodeGroup.tsx";
5+
import CodeGroup from "@barodoc/theme-docs/components/mdx/CodeGroup.astro";
66
import { ParamField, ParamFieldGroup } from "@barodoc/theme-docs/components/mdx/ParamField.tsx";
77

88
코드 그룹을 사용하면 여러 코드 예제를 탭 인터페이스로 표시할 수 있어, 같은 기능을 다른 언어로 보여주기 쉽습니다.
99

1010
## 기본 사용법
1111

12-
<CodeGroup client:load titles={["JavaScript", "Python", "Go"]}>
12+
<CodeGroup titles={["JavaScript", "Python", "Go"]}>
1313

1414
```javascript
1515
const greeting = "Hello, World!";
@@ -36,7 +36,7 @@ func main() {
3636

3737
## 패키지 매니저 예제
3838

39-
<CodeGroup client:load titles={["npm", "pnpm", "yarn", "bun"]}>
39+
<CodeGroup titles={["npm", "pnpm", "yarn", "bun"]}>
4040

4141
```bash
4242
npm install @barodoc/core
@@ -62,7 +62,4 @@ bun add @barodoc/core
6262
<ParamField name="titles" type="string[]">
6363
각 코드 블록의 탭 레이블 배열
6464
</ParamField>
65-
<ParamField name="client:load" type="directive" required>
66-
클라이언트 사이드 인터랙티브에 필요한 Astro 디렉티브
67-
</ParamField>
6865
</ParamFieldGroup>

packages/theme-docs/src/components/CodeCopy.astro

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@
9999
border-radius: 0 !important;
100100
background: transparent !important;
101101
}
102+
103+
/* Inside CodeGroup: no extra border/background so the group is one unified block */
104+
.code-group .code-block-wrapper {
105+
margin: 0;
106+
border: none;
107+
border-radius: 0;
108+
background: transparent;
109+
}
102110

103111
.code-block-header {
104112
display: flex;

packages/theme-docs/src/components/mdx/CodeGroup.astro

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ interface Props {
77
const { titles = [] } = Astro.props;
88
---
99

10-
<div class="not-prose my-4 code-group" data-titles={JSON.stringify(titles)}>
11-
<div class="code-group-tabs flex border-b border-[var(--color-border)] bg-[var(--color-bg-secondary)] rounded-t-lg"></div>
12-
<div class="code-group-content">
10+
<div class="code-group not-prose my-4 rounded-lg border border-[var(--color-border)] overflow-hidden" data-titles={JSON.stringify(titles)}>
11+
<div class="code-group-tabs flex flex-wrap gap-0 border-b border-[var(--color-border)] bg-[var(--color-bg-tertiary)]"></div>
12+
<div class="code-group-content bg-[var(--color-bg-secondary)] px-5 py-4">
1313
<slot />
1414
</div>
1515
</div>
@@ -27,30 +27,27 @@ const { titles = [] } = Astro.props;
2727
// Create tabs
2828
codeBlocks.forEach((block, index) => {
2929
const tab = document.createElement('button');
30-
tab.className = 'px-4 py-2 text-sm font-medium transition-colors text-[var(--color-text-secondary)] hover:text-[var(--color-text)]';
30+
tab.className = 'shrink-0 px-4 py-2 text-sm font-medium transition-colors whitespace-nowrap text-[var(--color-text-muted)] hover:text-[var(--color-text)]';
3131
tab.textContent = titles[index] || `Tab ${index + 1}`;
3232
tab.addEventListener('click', () => {
33-
// Update tabs
3433
tabsContainer.querySelectorAll('button').forEach((t, i) => {
3534
if (i === index) {
36-
t.classList.add('border-b-2', 'border-primary-600', 'text-primary-600');
37-
t.classList.remove('text-[var(--color-text-secondary)]');
35+
t.classList.add('border-b-2', 'border-primary-500', 'text-[var(--color-text)]', '-mb-px');
36+
t.classList.remove('text-[var(--color-text-muted)]');
3837
} else {
39-
t.classList.remove('border-b-2', 'border-primary-600', 'text-primary-600');
40-
t.classList.add('text-[var(--color-text-secondary)]');
38+
t.classList.remove('border-b-2', 'border-primary-500', 'text-[var(--color-text)]', '-mb-px');
39+
t.classList.add('text-[var(--color-text-muted)]');
4140
}
4241
});
43-
// Update content
4442
codeBlocks.forEach((b, i) => {
4543
(b as HTMLElement).style.display = i === index ? 'block' : 'none';
4644
});
4745
});
4846
tabsContainer.appendChild(tab);
4947

50-
// Hide all but first
5148
if (index === 0) {
52-
tab.classList.add('border-b-2', 'border-primary-600', 'text-primary-600');
53-
tab.classList.remove('text-[var(--color-text-secondary)]');
49+
tab.classList.add('border-b-2', 'border-primary-500', 'text-[var(--color-text)]', '-mb-px');
50+
tab.classList.remove('text-[var(--color-text-muted)]');
5451
} else {
5552
(block as HTMLElement).style.display = 'none';
5653
}

packages/theme-docs/src/components/mdx/CodeGroup.tsx

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,91 @@ interface CodeGroupProps {
55
titles?: string[];
66
}
77

8+
function isCodeBlockLike(el: React.ReactElement): boolean {
9+
if (el.type === "pre") return true;
10+
const className =
11+
typeof el.props?.className === "string" ? el.props.className : "";
12+
if (
13+
className.includes("language-") ||
14+
className.includes("astro-code") ||
15+
className.includes("code-block")
16+
)
17+
return true;
18+
return false;
19+
}
20+
21+
function collectCodeBlocks(node: React.ReactNode): React.ReactElement[] {
22+
const result: React.ReactElement[] = [];
23+
React.Children.forEach(node, (child) => {
24+
if (!React.isValidElement(child)) return;
25+
if (child.type === React.Fragment && child.props?.children != null) {
26+
result.push(...collectCodeBlocks(child.props.children));
27+
return;
28+
}
29+
if (child.type === "pre" || isCodeBlockLike(child)) {
30+
result.push(child);
31+
return;
32+
}
33+
if (child.props?.children != null) {
34+
result.push(...collectCodeBlocks(child.props.children));
35+
}
36+
});
37+
return result;
38+
}
39+
840
export function CodeGroup({ children, titles = [] }: CodeGroupProps) {
941
const [activeIndex, setActiveIndex] = React.useState(0);
10-
11-
// Extract code blocks from children
12-
const codeBlocks = React.Children.toArray(children);
13-
42+
43+
const codeBlocks = React.useMemo(() => {
44+
let blocks = collectCodeBlocks(children);
45+
if (blocks.length > 0) return blocks;
46+
const direct = React.Children.toArray(children).filter(
47+
(c): c is React.ReactElement => React.isValidElement(c) && c.type != null
48+
);
49+
if (direct.length > 1) return direct;
50+
if (
51+
direct.length === 1 &&
52+
direct[0].props?.children != null
53+
) {
54+
const inner = React.Children.toArray(direct[0].props.children).filter(
55+
(c): c is React.ReactElement =>
56+
React.isValidElement(c) && c.type != null
57+
);
58+
if (inner.length > 0) return inner;
59+
}
60+
return direct;
61+
}, [children]);
62+
63+
const tabTitles =
64+
titles.length >= codeBlocks.length
65+
? titles.slice(0, codeBlocks.length)
66+
: [
67+
...titles,
68+
...codeBlocks
69+
.slice(titles.length)
70+
.map((_, i) => `Tab ${titles.length + i + 1}`),
71+
];
72+
73+
if (codeBlocks.length === 0) {
74+
return (
75+
<div className="code-group not-prose my-4 rounded-lg border border-[var(--color-border)] overflow-hidden p-4 text-[var(--color-text-muted)] text-sm">
76+
No code blocks found inside CodeGroup.
77+
</div>
78+
);
79+
}
80+
1481
return (
15-
<div className="not-prose my-4 rounded-lg border border-[var(--color-border)] overflow-hidden">
82+
<div className="code-group not-prose my-4 rounded-lg border border-[var(--color-border)] overflow-hidden">
1683
{/* Tabs */}
17-
<div className="flex bg-[var(--color-bg-tertiary)] border-b border-[var(--color-border)]">
18-
{codeBlocks.map((_, index) => {
84+
<div className="flex flex-wrap gap-0 bg-[var(--color-bg-tertiary)] border-b border-[var(--color-border)]">
85+
{tabTitles.map((title, index) => {
1986
const isActive = activeIndex === index;
20-
const title = titles[index] || `Tab ${index + 1}`;
2187
return (
2288
<button
2389
key={index}
2490
type="button"
2591
onClick={() => setActiveIndex(index)}
26-
className={`px-4 py-2 text-sm font-medium transition-colors ${
92+
className={`shrink-0 px-4 py-2 text-sm font-medium transition-colors whitespace-nowrap ${
2793
isActive
2894
? "bg-[var(--color-bg-secondary)] text-[var(--color-text)] border-b-2 border-primary-500 -mb-px"
2995
: "text-[var(--color-text-muted)] hover:text-[var(--color-text)]"
@@ -34,7 +100,7 @@ export function CodeGroup({ children, titles = [] }: CodeGroupProps) {
34100
);
35101
})}
36102
</div>
37-
103+
38104
{/* Content */}
39105
<div className="bg-[var(--color-bg-secondary)]">
40106
{codeBlocks.map((block, index) => (

0 commit comments

Comments
 (0)