Skip to content

Commit c5532e7

Browse files
committed
feat(astro): override components to support Dialog
1 parent 23ed41c commit c5532e7

File tree

20 files changed

+234
-63
lines changed

20 files changed

+234
-63
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ lerna-debug.log*
88
node_modules
99
dist
1010
dist-ssr
11+
e2e/dist-*
1112
*.local
1213
!.vscode/extensions.json
1314
.idea
Loading

docs/tutorialkit.dev/src/content/docs/guides/overriding-components.mdx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ title: 'Overriding Components'
33
description: "Override TutorialKit's default components to fit your needs."
44
---
55
import { Image } from 'astro:assets';
6+
import uiDialog from './images/ui-dialog.png';
67
import uiTopBar from './images/ui-top-bar.png';
78

89
TutorialKit's default components are customizable with [theming](/reference/theming/) options.
@@ -64,4 +65,12 @@ When overriding `TopBar` you can place TutorialKit's default components using fo
6465

6566
<slot name="login-button" />
6667
</nav>
67-
```
68+
```
69+
70+
### Dialog
71+
72+
<Image src={uiDialog} alt="TutorialKit's Dialog" />
73+
74+
Component for overriding confirmation dialogs. This component has to be a React component.
75+
76+
It will receive same props that `@tutorialkit/react/dialog` supports.

e2e/configs/override-components.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import tutorialkit from '@tutorialkit/astro';
2+
import { defineConfig } from 'astro/config';
3+
4+
export default defineConfig({
5+
devToolbar: { enabled: false },
6+
server: { port: 4330 },
7+
outDir: './dist-override-components',
8+
integrations: [
9+
tutorialkit({
10+
components: {
11+
Dialog: './src/components/Dialog.tsx',
12+
TopBar: './src/components/TopBar.astro',
13+
},
14+
}),
15+
],
16+
});

e2e/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"scripts": {
66
"dev": "astro dev",
77
"preview": "astro build && astro preview",
8+
"dev:override-components": "astro dev --config ./configs/override-components.ts",
9+
"preview:override-components": "astro build --config ./configs/override-components.ts && astro preview --config ./configs/override-components.ts",
810
"test": "playwright test",
911
"test:ui": "pnpm run test --ui"
1012
},
@@ -18,8 +20,9 @@
1820
"@tutorialkit/runtime": "workspace:*",
1921
"@tutorialkit/theme": "workspace:*",
2022
"@tutorialkit/types": "workspace:*",
21-
"@types/react": "^18.3.3",
2223
"@types/node": "^22.2.0",
24+
"@types/react": "^18.3.3",
25+
"@types/react-dom": "^18.3.0",
2326
"@unocss/reset": "^0.59.4",
2427
"@unocss/transformer-directives": "^0.62.0",
2528
"astro": "^4.15.0",

e2e/playwright.config.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
11
import { defineConfig } from '@playwright/test';
22

33
export default defineConfig({
4+
projects: [
5+
{
6+
name: 'Default',
7+
testMatch: 'test/*.test.ts',
8+
testIgnore: 'test/*.override-components.test.ts',
9+
use: { baseURL: 'http://localhost:4329' },
10+
},
11+
{
12+
name: 'Override Components',
13+
testMatch: 'test/*.override-components.test.ts',
14+
use: { baseURL: 'http://localhost:4330' },
15+
},
16+
],
17+
webServer: [
18+
{
19+
command: 'pnpm preview',
20+
url: 'http://localhost:4329',
21+
reuseExistingServer: !process.env.CI,
22+
stdout: 'ignore',
23+
stderr: 'pipe',
24+
},
25+
{
26+
command: 'pnpm preview:override-components',
27+
url: 'http://localhost:4330',
28+
reuseExistingServer: !process.env.CI,
29+
stdout: 'ignore',
30+
stderr: 'pipe',
31+
},
32+
],
433
expect: {
534
timeout: process.env.CI ? 30_000 : 10_000,
635
},
7-
use: {
8-
baseURL: 'http://localhost:4329',
9-
},
10-
webServer: {
11-
command: 'pnpm preview',
12-
url: 'http://localhost:4329',
13-
reuseExistingServer: !process.env.CI,
14-
stdout: 'ignore',
15-
stderr: 'pipe',
16-
},
1736
});

e2e/src/components/Dialog.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type DialogType from '@tutorialkit/react/dialog';
2+
import type { ComponentProps } from 'react';
3+
import { createPortal } from 'react-dom';
4+
5+
export default function Dialog({ title, confirmText, onClose, children }: ComponentProps<typeof DialogType>) {
6+
return createPortal(
7+
<div role="dialog" className="fixed z-11 inset-50 color-tk-text-warning bg-tk-background-accent p-10 z-99">
8+
<h2>Custom Dialog</h2>
9+
<h3>{title}</h3>
10+
11+
{children}
12+
13+
<button className="mt2 p2 border border-tk-border-warning rounded" onClick={onClose}>
14+
{confirmText}
15+
</button>
16+
</div>,
17+
document.body,
18+
);
19+
}

e2e/src/components/TopBar.astro

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<nav
2+
class="bg-tk-elements-topBar-backgroundColor border-b border-tk-elements-app-borderColor flex gap-1 max-w-full items-center p-3 px-4 min-h-[56px]"
3+
>
4+
<div class="flex flex-1">
5+
<slot name="logo" />
6+
</div>
7+
8+
<div class="mr-2 color-tk-text-primary">Custom Top Bar Mounted</div>
9+
10+
<div class="mr-2">
11+
<slot name="open-in-stackblitz-link" />
12+
</div>
13+
14+
<div>
15+
<slot name="theme-switch" />
16+
</div>
17+
18+
<div>
19+
<slot name="login-button" />
20+
</div>
21+
</nav>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
const BASE_URL = '/tests/file-tree';
4+
5+
test('developer can override dialog in File Tree', async ({ page }) => {
6+
await page.goto(`${BASE_URL}/allow-edits-glob`);
7+
await expect(page.getByRole('heading', { level: 1, name: 'File Tree test - Allow Edits Glob' })).toBeVisible();
8+
9+
await page.getByRole('button', { name: 'first-level' }).click({ button: 'right' });
10+
await page.getByRole('menuitem', { name: `Create file` }).click();
11+
12+
await page.locator('*:focus').fill('new-file.js');
13+
await page.locator('*:focus').press('Enter');
14+
15+
const dialog = page.getByRole('dialog');
16+
await expect(dialog.getByRole('heading', { level: 2, name: 'Custom Dialog' })).toBeVisible();
17+
18+
// default elements should also be visible
19+
await expect(dialog.getByText('Created files and folders must match following patterns:')).toBeVisible();
20+
await expect(dialog.getByRole('listitem').nth(0)).toHaveText('/*');
21+
await expect(dialog.getByRole('listitem').nth(1)).toHaveText('/first-level/allowed-filename-only.js');
22+
await expect(dialog.getByRole('listitem').nth(2)).toHaveText('**/second-level/**');
23+
24+
await dialog.getByRole('button', { name: 'OK' }).click();
25+
await expect(dialog).not.toBeVisible();
26+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('developer can override TopBar', async ({ page }) => {
4+
await page.goto('/');
5+
6+
const nav = page.getByRole('navigation');
7+
await expect(nav.getByText('Custom Top Bar Mounted')).toBeVisible();
8+
9+
// default elements should also be visible
10+
await expect(nav.getByRole('button', { name: 'Open in StackBlitz' })).toBeVisible();
11+
await expect(nav.getByRole('button', { name: 'Toggle Theme' })).toBeVisible();
12+
});

0 commit comments

Comments
 (0)