@shadng/sng-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/cli/sng-ui.js +331 -0
- package/ng-package.json +29 -0
- package/package.json +64 -0
- package/registry.json +72 -0
- package/src/lib/accordion/cn.ts +6 -0
- package/src/lib/accordion/index.ts +18 -0
- package/src/lib/accordion/sng-accordion-content.ts +131 -0
- package/src/lib/accordion/sng-accordion-item.ts +299 -0
- package/src/lib/accordion/sng-accordion-trigger.ts +137 -0
- package/src/lib/accordion/sng-accordion.ts +118 -0
- package/src/lib/accordion/sng-accordion.types.ts +82 -0
- package/src/lib/alert/cn.ts +6 -0
- package/src/lib/alert/index.ts +3 -0
- package/src/lib/alert/sng-alert-description.ts +49 -0
- package/src/lib/alert/sng-alert-title.ts +46 -0
- package/src/lib/alert/sng-alert.ts +48 -0
- package/src/lib/avatar/cn.ts +6 -0
- package/src/lib/avatar/index.ts +3 -0
- package/src/lib/avatar/sng-avatar-fallback.ts +50 -0
- package/src/lib/avatar/sng-avatar-image.ts +73 -0
- package/src/lib/avatar/sng-avatar.ts +60 -0
- package/src/lib/badge/cn.ts +6 -0
- package/src/lib/badge/index.ts +1 -0
- package/src/lib/badge/sng-badge.ts +36 -0
- package/src/lib/breadcrumb/cn.ts +6 -0
- package/src/lib/breadcrumb/index.ts +7 -0
- package/src/lib/breadcrumb/sng-breadcrumb-ellipsis.ts +61 -0
- package/src/lib/breadcrumb/sng-breadcrumb-item.ts +47 -0
- package/src/lib/breadcrumb/sng-breadcrumb-link.ts +43 -0
- package/src/lib/breadcrumb/sng-breadcrumb-list.ts +42 -0
- package/src/lib/breadcrumb/sng-breadcrumb-page.ts +44 -0
- package/src/lib/breadcrumb/sng-breadcrumb-separator.ts +60 -0
- package/src/lib/breadcrumb/sng-breadcrumb.ts +52 -0
- package/src/lib/button/cn.ts +6 -0
- package/src/lib/button/index.ts +2 -0
- package/src/lib/button/sng-button.ts +264 -0
- package/src/lib/calendar/cn.ts +6 -0
- package/src/lib/calendar/index.ts +2 -0
- package/src/lib/calendar/sng-calendar.ts +753 -0
- package/src/lib/card/cn.ts +6 -0
- package/src/lib/card/index.ts +6 -0
- package/src/lib/card/sng-card-content.ts +36 -0
- package/src/lib/card/sng-card-description.ts +38 -0
- package/src/lib/card/sng-card-footer.ts +34 -0
- package/src/lib/card/sng-card-header.ts +34 -0
- package/src/lib/card/sng-card-title.ts +48 -0
- package/src/lib/card/sng-card.ts +43 -0
- package/src/lib/carousel/cn.ts +6 -0
- package/src/lib/carousel/index.ts +18 -0
- package/src/lib/carousel/sng-carousel.ts +526 -0
- package/src/lib/checkbox/cn.ts +6 -0
- package/src/lib/checkbox/index.ts +1 -0
- package/src/lib/checkbox/sng-checkbox.ts +154 -0
- package/src/lib/code-block/cn.ts +6 -0
- package/src/lib/code-block/index.ts +1 -0
- package/src/lib/code-block/sng-code-block.ts +296 -0
- package/src/lib/dialog/cn.ts +6 -0
- package/src/lib/dialog/index.ts +37 -0
- package/src/lib/dialog/sng-dialog-close.ts +76 -0
- package/src/lib/dialog/sng-dialog-content.ts +132 -0
- package/src/lib/dialog/sng-dialog-description.ts +36 -0
- package/src/lib/dialog/sng-dialog-footer.ts +39 -0
- package/src/lib/dialog/sng-dialog-header.ts +39 -0
- package/src/lib/dialog/sng-dialog-title.ts +52 -0
- package/src/lib/dialog/sng-dialog.service.ts +222 -0
- package/src/lib/dialog/sng-dialog.ts +224 -0
- package/src/lib/drawer/cn.ts +6 -0
- package/src/lib/drawer/index.ts +36 -0
- package/src/lib/drawer/sng-drawer-close.ts +28 -0
- package/src/lib/drawer/sng-drawer-content.ts +135 -0
- package/src/lib/drawer/sng-drawer-description.ts +29 -0
- package/src/lib/drawer/sng-drawer-footer.ts +34 -0
- package/src/lib/drawer/sng-drawer-handle.ts +30 -0
- package/src/lib/drawer/sng-drawer-header.ts +30 -0
- package/src/lib/drawer/sng-drawer-title.ts +27 -0
- package/src/lib/drawer/sng-drawer-trigger.ts +21 -0
- package/src/lib/drawer/sng-drawer-wrapper.ts +27 -0
- package/src/lib/drawer/sng-drawer.ts +166 -0
- package/src/lib/file-input/cn.ts +6 -0
- package/src/lib/file-input/index.ts +1 -0
- package/src/lib/file-input/sng-file-input.ts +288 -0
- package/src/lib/hover-card/cn.ts +6 -0
- package/src/lib/hover-card/index.ts +3 -0
- package/src/lib/hover-card/sng-hover-card-content.ts +100 -0
- package/src/lib/hover-card/sng-hover-card-trigger.ts +43 -0
- package/src/lib/hover-card/sng-hover-card.ts +246 -0
- package/src/lib/input/cn.ts +6 -0
- package/src/lib/input/index.ts +1 -0
- package/src/lib/input/sng-input.ts +160 -0
- package/src/lib/layout/cn.ts +6 -0
- package/src/lib/layout/index.ts +98 -0
- package/src/lib/layout/sng-layout-footer.ts +37 -0
- package/src/lib/layout/sng-layout-header.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-content.ts +149 -0
- package/src/lib/layout/sng-layout-sidebar-footer.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-group-action.ts +67 -0
- package/src/lib/layout/sng-layout-sidebar-group-content.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-group-label.ts +53 -0
- package/src/lib/layout/sng-layout-sidebar-group.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-header.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-input.ts +112 -0
- package/src/lib/layout/sng-layout-sidebar-inset.ts +45 -0
- package/src/lib/layout/sng-layout-sidebar-menu-action.ts +84 -0
- package/src/lib/layout/sng-layout-sidebar-menu-badge.ts +47 -0
- package/src/lib/layout/sng-layout-sidebar-menu-button.ts +160 -0
- package/src/lib/layout/sng-layout-sidebar-menu-item.ts +40 -0
- package/src/lib/layout/sng-layout-sidebar-menu-skeleton.ts +71 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-button.ts +142 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-item.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub.ts +48 -0
- package/src/lib/layout/sng-layout-sidebar-menu.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-provider.ts +189 -0
- package/src/lib/layout/sng-layout-sidebar-rail.ts +60 -0
- package/src/lib/layout/sng-layout-sidebar-separator.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-trigger.ts +97 -0
- package/src/lib/layout/sng-layout-sidebar.ts +254 -0
- package/src/lib/menu/cn.ts +6 -0
- package/src/lib/menu/index.ts +21 -0
- package/src/lib/menu/sng-context-trigger.ts +128 -0
- package/src/lib/menu/sng-menu-checkbox-item.ts +91 -0
- package/src/lib/menu/sng-menu-item.ts +80 -0
- package/src/lib/menu/sng-menu-label.ts +47 -0
- package/src/lib/menu/sng-menu-radio-group.ts +38 -0
- package/src/lib/menu/sng-menu-radio-item.ts +94 -0
- package/src/lib/menu/sng-menu-separator.ts +27 -0
- package/src/lib/menu/sng-menu-shortcut.ts +25 -0
- package/src/lib/menu/sng-menu-sub-content.ts +267 -0
- package/src/lib/menu/sng-menu-sub-trigger.ts +68 -0
- package/src/lib/menu/sng-menu-sub.ts +124 -0
- package/src/lib/menu/sng-menu-tokens.ts +52 -0
- package/src/lib/menu/sng-menu-trigger.ts +266 -0
- package/src/lib/menu/sng-menu.ts +100 -0
- package/src/lib/nav-menu/cn.ts +6 -0
- package/src/lib/nav-menu/index.ts +6 -0
- package/src/lib/nav-menu/sng-nav-menu-content.ts +72 -0
- package/src/lib/nav-menu/sng-nav-menu-item.ts +109 -0
- package/src/lib/nav-menu/sng-nav-menu-link.ts +54 -0
- package/src/lib/nav-menu/sng-nav-menu-list.ts +43 -0
- package/src/lib/nav-menu/sng-nav-menu-trigger.ts +98 -0
- package/src/lib/nav-menu/sng-nav-menu.ts +99 -0
- package/src/lib/otp-input/cn.ts +6 -0
- package/src/lib/otp-input/index.ts +14 -0
- package/src/lib/otp-input/sng-otp-input-group.ts +38 -0
- package/src/lib/otp-input/sng-otp-input-separator.ts +43 -0
- package/src/lib/otp-input/sng-otp-input-slot.ts +128 -0
- package/src/lib/otp-input/sng-otp-input-tokens.ts +20 -0
- package/src/lib/otp-input/sng-otp-input.ts +301 -0
- package/src/lib/popover/cn.ts +6 -0
- package/src/lib/popover/index.ts +3 -0
- package/src/lib/popover/sng-popover-content.ts +66 -0
- package/src/lib/popover/sng-popover-trigger.ts +44 -0
- package/src/lib/popover/sng-popover.ts +218 -0
- package/src/lib/preview-box/cn.ts +6 -0
- package/src/lib/preview-box/index.ts +5 -0
- package/src/lib/preview-box/sng-code-block.ts +80 -0
- package/src/lib/preview-box/sng-html-block.ts +79 -0
- package/src/lib/preview-box/sng-preview-block.ts +47 -0
- package/src/lib/preview-box/sng-preview-box.ts +369 -0
- package/src/lib/preview-box/sng-style-block.ts +80 -0
- package/src/lib/progress/cn.ts +6 -0
- package/src/lib/progress/index.ts +1 -0
- package/src/lib/progress/sng-progress.ts +65 -0
- package/src/lib/radio/cn.ts +6 -0
- package/src/lib/radio/index.ts +5 -0
- package/src/lib/radio/sng-radio-item.ts +100 -0
- package/src/lib/radio/sng-radio.ts +54 -0
- package/src/lib/resizable/cn.ts +6 -0
- package/src/lib/resizable/index.ts +3 -0
- package/src/lib/resizable/sng-resizable-group.ts +188 -0
- package/src/lib/resizable/sng-resizable-handle.ts +236 -0
- package/src/lib/resizable/sng-resizable-panel.ts +71 -0
- package/src/lib/search-input/cn.ts +6 -0
- package/src/lib/search-input/index.ts +16 -0
- package/src/lib/search-input/sng-search-input-context.ts +24 -0
- package/src/lib/search-input/sng-search-input-empty.ts +42 -0
- package/src/lib/search-input/sng-search-input-group.ts +69 -0
- package/src/lib/search-input/sng-search-input-item.ts +164 -0
- package/src/lib/search-input/sng-search-input-list.ts +34 -0
- package/src/lib/search-input/sng-search-input-separator.ts +32 -0
- package/src/lib/search-input/sng-search-input-shortcut.ts +29 -0
- package/src/lib/search-input/sng-search-input.ts +368 -0
- package/src/lib/select/cn.ts +6 -0
- package/src/lib/select/index.ts +7 -0
- package/src/lib/select/sng-select-content.ts +27 -0
- package/src/lib/select/sng-select-empty.ts +48 -0
- package/src/lib/select/sng-select-group.ts +29 -0
- package/src/lib/select/sng-select-item.ts +140 -0
- package/src/lib/select/sng-select-label.ts +29 -0
- package/src/lib/select/sng-select-separator.ts +29 -0
- package/src/lib/select/sng-select.ts +326 -0
- package/src/lib/separator/cn.ts +6 -0
- package/src/lib/separator/index.ts +1 -0
- package/src/lib/separator/sng-separator.ts +40 -0
- package/src/lib/skeleton/cn.ts +6 -0
- package/src/lib/skeleton/index.ts +1 -0
- package/src/lib/skeleton/sng-skeleton.ts +49 -0
- package/src/lib/slider/cn.ts +6 -0
- package/src/lib/slider/index.ts +2 -0
- package/src/lib/slider/sng-slider.ts +137 -0
- package/src/lib/sng-table/cn.ts +6 -0
- package/src/lib/sng-table/flex-render.ts +222 -0
- package/src/lib/sng-table/index.ts +85 -0
- package/src/lib/sng-table/sng-table-body.ts +59 -0
- package/src/lib/sng-table/sng-table-caption.ts +49 -0
- package/src/lib/sng-table/sng-table-cell.ts +62 -0
- package/src/lib/sng-table/sng-table-footer.ts +60 -0
- package/src/lib/sng-table/sng-table-head.ts +66 -0
- package/src/lib/sng-table/sng-table-header.ts +48 -0
- package/src/lib/sng-table/sng-table-pagination.ts +265 -0
- package/src/lib/sng-table/sng-table-row.ts +65 -0
- package/src/lib/sng-table/sng-table.ts +67 -0
- package/src/lib/sng-table-core/core/create-cell.ts +117 -0
- package/src/lib/sng-table-core/core/create-column.ts +266 -0
- package/src/lib/sng-table-core/core/create-header.ts +271 -0
- package/src/lib/sng-table-core/core/create-row.ts +293 -0
- package/src/lib/sng-table-core/core/create-table.ts +534 -0
- package/src/lib/sng-table-core/core/types.ts +1197 -0
- package/src/lib/sng-table-core/core/utils.ts +307 -0
- package/src/lib/sng-table-core/features/column-filtering.ts +376 -0
- package/src/lib/sng-table-core/features/column-ordering.ts +159 -0
- package/src/lib/sng-table-core/features/column-pinning.ts +219 -0
- package/src/lib/sng-table-core/features/column-sizing.ts +268 -0
- package/src/lib/sng-table-core/features/column-visibility.ts +128 -0
- package/src/lib/sng-table-core/features/faceting.ts +279 -0
- package/src/lib/sng-table-core/features/fuzzy-filtering.ts +188 -0
- package/src/lib/sng-table-core/features/global-filtering.ts +128 -0
- package/src/lib/sng-table-core/features/pagination.ts +179 -0
- package/src/lib/sng-table-core/features/row-expanding.ts +181 -0
- package/src/lib/sng-table-core/features/row-grouping.ts +235 -0
- package/src/lib/sng-table-core/features/row-pinning.ts +196 -0
- package/src/lib/sng-table-core/features/row-selection.ts +298 -0
- package/src/lib/sng-table-core/features/sorting.ts +425 -0
- package/src/lib/sng-table-core/features/virtualization.ts +298 -0
- package/src/lib/sng-table-core/index.ts +235 -0
- package/src/lib/sng-table-core/row-models/core-row-model.ts +256 -0
- package/src/lib/sng-table-core/row-models/expanded-row-model.ts +175 -0
- package/src/lib/sng-table-core/row-models/filtered-row-model.ts +307 -0
- package/src/lib/sng-table-core/row-models/grouped-row-model.ts +290 -0
- package/src/lib/sng-table-core/row-models/paginated-row-model.ts +135 -0
- package/src/lib/sng-table-core/row-models/sorted-row-model.ts +197 -0
- package/src/lib/styles/sng-themes.css +164 -0
- package/src/lib/switch/cn.ts +6 -0
- package/src/lib/switch/index.ts +1 -0
- package/src/lib/switch/sng-switch.ts +137 -0
- package/src/lib/tabs/cn.ts +6 -0
- package/src/lib/tabs/index.ts +4 -0
- package/src/lib/tabs/sng-tabs-content.ts +66 -0
- package/src/lib/tabs/sng-tabs-list.ts +55 -0
- package/src/lib/tabs/sng-tabs-trigger.ts +86 -0
- package/src/lib/tabs/sng-tabs.ts +83 -0
- package/src/lib/toast/cn.ts +6 -0
- package/src/lib/toast/index.ts +3 -0
- package/src/lib/toast/sng-toast.service.ts +258 -0
- package/src/lib/toast/sng-toast.ts +101 -0
- package/src/lib/toast/sng-toaster.ts +67 -0
- package/src/lib/toggle/cn.ts +6 -0
- package/src/lib/toggle/index.ts +6 -0
- package/src/lib/toggle/sng-toggle-group-item.ts +89 -0
- package/src/lib/toggle/sng-toggle-group.ts +85 -0
- package/src/lib/toggle/sng-toggle.ts +78 -0
- package/src/lib/toggle-group/index.ts +6 -0
- package/src/lib/tooltip/cn.ts +6 -0
- package/src/lib/tooltip/index.ts +5 -0
- package/src/lib/tooltip/sng-tooltip-content.ts +64 -0
- package/src/lib/tooltip/sng-tooltip.ts +216 -0
- package/src/public-api.ts +207 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +11 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
input,
|
|
6
|
+
} from '@angular/core';
|
|
7
|
+
import { SngCodeBlock, type ShikiTheme } from '../code-block/sng-code-block';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SngPreviewCodeBlock - TypeScript/code snippet for Code tab in preview-box.
|
|
11
|
+
*
|
|
12
|
+
* Displays syntax-highlighted TypeScript or other code in the Code tab of preview-box.
|
|
13
|
+
* Wraps sng-code-block internally for consistent styling.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```html
|
|
17
|
+
* <sng-preview-box>
|
|
18
|
+
* <sng-preview-block>
|
|
19
|
+
* <sng-button>Click me</sng-button>
|
|
20
|
+
* </sng-preview-block>
|
|
21
|
+
* <sng-html-block [code]="htmlCode" />
|
|
22
|
+
* <sng-preview-code-block [code]="tsCode" [theme]="'github-dark'" />
|
|
23
|
+
* </sng-preview-box>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
@Component({
|
|
27
|
+
selector: 'sng-preview-code-block',
|
|
28
|
+
standalone: true,
|
|
29
|
+
imports: [SngCodeBlock],
|
|
30
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
31
|
+
encapsulation: ViewEncapsulation.None,
|
|
32
|
+
host: {},
|
|
33
|
+
styles: [`
|
|
34
|
+
sng-preview-code-block {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
height: 100%;
|
|
38
|
+
}
|
|
39
|
+
sng-preview-code-block sng-code-block {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
height: 100%;
|
|
43
|
+
}
|
|
44
|
+
sng-preview-code-block .code-container {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
height: 100%;
|
|
48
|
+
border: none;
|
|
49
|
+
border-radius: 0;
|
|
50
|
+
}
|
|
51
|
+
sng-preview-code-block .code-content {
|
|
52
|
+
flex: 1;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
}
|
|
55
|
+
`],
|
|
56
|
+
template: `
|
|
57
|
+
<sng-code-block
|
|
58
|
+
[code]="code()"
|
|
59
|
+
[language]="language()"
|
|
60
|
+
[theme]="theme()"
|
|
61
|
+
[showHeader]="false"
|
|
62
|
+
/>
|
|
63
|
+
`
|
|
64
|
+
})
|
|
65
|
+
export class SngPreviewCodeBlock {
|
|
66
|
+
/**
|
|
67
|
+
* The TypeScript or other code string to display with syntax highlighting.
|
|
68
|
+
*/
|
|
69
|
+
code = input.required<string>();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The language for syntax highlighting.
|
|
73
|
+
*/
|
|
74
|
+
language = input<string>('typescript');
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The Shiki theme for syntax highlighting.
|
|
78
|
+
*/
|
|
79
|
+
theme = input<ShikiTheme>('github-light');
|
|
80
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
input,
|
|
6
|
+
} from '@angular/core';
|
|
7
|
+
import { SngCodeBlock, type ShikiTheme } from '../code-block/sng-code-block';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SngHtmlBlock - HTML code snippet for HTML tab in preview-box.
|
|
11
|
+
*
|
|
12
|
+
* Displays syntax-highlighted HTML code in the HTML tab of preview-box.
|
|
13
|
+
* Wraps sng-code-block internally for consistent styling.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```html
|
|
17
|
+
* <sng-preview-box>
|
|
18
|
+
* <sng-preview-block>
|
|
19
|
+
* <sng-button>Click me</sng-button>
|
|
20
|
+
* </sng-preview-block>
|
|
21
|
+
* <sng-html-block [code]="htmlSnippet" [theme]="'github-dark'" />
|
|
22
|
+
* </sng-preview-box>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
@Component({
|
|
26
|
+
selector: 'sng-html-block',
|
|
27
|
+
standalone: true,
|
|
28
|
+
imports: [SngCodeBlock],
|
|
29
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
30
|
+
encapsulation: ViewEncapsulation.None,
|
|
31
|
+
host: {},
|
|
32
|
+
styles: [`
|
|
33
|
+
sng-html-block {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
height: 100%;
|
|
37
|
+
}
|
|
38
|
+
sng-html-block sng-code-block {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
sng-html-block .code-container {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
height: 100%;
|
|
47
|
+
border: none;
|
|
48
|
+
border-radius: 0;
|
|
49
|
+
}
|
|
50
|
+
sng-html-block .code-content {
|
|
51
|
+
flex: 1;
|
|
52
|
+
overflow: auto;
|
|
53
|
+
}
|
|
54
|
+
`],
|
|
55
|
+
template: `
|
|
56
|
+
<sng-code-block
|
|
57
|
+
[code]="code()"
|
|
58
|
+
[language]="language()"
|
|
59
|
+
[theme]="theme()"
|
|
60
|
+
[showHeader]="false"
|
|
61
|
+
/>
|
|
62
|
+
`
|
|
63
|
+
})
|
|
64
|
+
export class SngHtmlBlock {
|
|
65
|
+
/**
|
|
66
|
+
* The HTML code string to display with syntax highlighting.
|
|
67
|
+
*/
|
|
68
|
+
code = input.required<string>();
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The language for syntax highlighting.
|
|
72
|
+
*/
|
|
73
|
+
language = input<string>('html');
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The Shiki theme for syntax highlighting.
|
|
77
|
+
*/
|
|
78
|
+
theme = input<ShikiTheme>('github-light');
|
|
79
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
input,
|
|
6
|
+
computed,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
import { cn } from './cn';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Content wrapper for live demo in preview-box. Centers content with padding.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```html
|
|
15
|
+
* <sng-preview-block>
|
|
16
|
+
* <sng-button>Click me</sng-button>
|
|
17
|
+
* </sng-preview-block>
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
@Component({
|
|
21
|
+
selector: 'sng-preview-block',
|
|
22
|
+
standalone: true,
|
|
23
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
24
|
+
encapsulation: ViewEncapsulation.None,
|
|
25
|
+
host: {
|
|
26
|
+
'[class]': 'hostClasses()',
|
|
27
|
+
},
|
|
28
|
+
styles: [`
|
|
29
|
+
sng-preview-block {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
width: 100%;
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
}
|
|
36
|
+
`],
|
|
37
|
+
template: `<ng-content />`
|
|
38
|
+
})
|
|
39
|
+
export class SngPreviewBlock {
|
|
40
|
+
/** Custom CSS classes. */
|
|
41
|
+
class = input<string>('');
|
|
42
|
+
|
|
43
|
+
hostClasses = computed(() => cn(
|
|
44
|
+
'flex items-center justify-center p-6',
|
|
45
|
+
this.class()
|
|
46
|
+
));
|
|
47
|
+
}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
signal,
|
|
6
|
+
ElementRef,
|
|
7
|
+
viewChildren,
|
|
8
|
+
AfterViewInit,
|
|
9
|
+
effect,
|
|
10
|
+
inject,
|
|
11
|
+
Injector,
|
|
12
|
+
contentChild,
|
|
13
|
+
TemplateRef,
|
|
14
|
+
computed,
|
|
15
|
+
input,
|
|
16
|
+
afterNextRender,
|
|
17
|
+
} from '@angular/core';
|
|
18
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
19
|
+
import { SngHtmlBlock } from './sng-html-block';
|
|
20
|
+
import { SngCodeBlock } from '../code-block/sng-code-block';
|
|
21
|
+
import { SngPreviewCodeBlock } from './sng-code-block';
|
|
22
|
+
import { SngStyleBlock } from './sng-style-block';
|
|
23
|
+
import { cn } from './cn';
|
|
24
|
+
|
|
25
|
+
type TabType = 'preview' | 'html' | 'code' | 'style';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* ShadNG Preview Box - Component showcase with code examples.
|
|
29
|
+
*
|
|
30
|
+
* A tabbed container for displaying live component previews alongside their
|
|
31
|
+
* HTML, TypeScript, and CSS code. Supports fullscreen mode and background toggling.
|
|
32
|
+
*
|
|
33
|
+
* Height control via Tailwind classes:
|
|
34
|
+
* - Default: h-[350px]
|
|
35
|
+
* - Custom: `<sng-preview-box class="h-[700px]">`
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```html
|
|
39
|
+
* <sng-preview-box class="h-[500px]">
|
|
40
|
+
* <sng-preview-block>
|
|
41
|
+
* <sng-button>Click me</sng-button>
|
|
42
|
+
* </sng-preview-block>
|
|
43
|
+
* <sng-html-block [code]="htmlCode" />
|
|
44
|
+
* <sng-code-block [code]="tsCode" />
|
|
45
|
+
* <sng-style-block [code]="cssCode" />
|
|
46
|
+
* </sng-preview-box>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
@Component({
|
|
50
|
+
selector: 'sng-preview-box',
|
|
51
|
+
standalone: true,
|
|
52
|
+
imports: [NgTemplateOutlet],
|
|
53
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
54
|
+
encapsulation: ViewEncapsulation.None,
|
|
55
|
+
host: {
|
|
56
|
+
'[class]': 'hostClasses()'
|
|
57
|
+
},
|
|
58
|
+
styles: [`
|
|
59
|
+
.sng-preview-box-code-area > sng-html-block,
|
|
60
|
+
.sng-preview-box-code-area > sng-code-block,
|
|
61
|
+
.sng-preview-box-code-area > sng-preview-code-block,
|
|
62
|
+
.sng-preview-box-code-area > sng-style-block {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
height: 100%;
|
|
66
|
+
}
|
|
67
|
+
`],
|
|
68
|
+
template: `
|
|
69
|
+
<!-- Fullscreen backdrop (decorative) -->
|
|
70
|
+
@if (isFullscreen()) {
|
|
71
|
+
<div
|
|
72
|
+
aria-hidden="true"
|
|
73
|
+
class="fixed inset-0 z-[10000] bg-black/80"
|
|
74
|
+
(click)="toggleFullscreen()"
|
|
75
|
+
></div>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
<!-- Main container -->
|
|
79
|
+
<div [class]="containerClasses()">
|
|
80
|
+
<!-- Tab bar -->
|
|
81
|
+
<div class="flex items-center justify-between h-11 px-1 border-b border-border bg-muted">
|
|
82
|
+
<!-- Tabs group -->
|
|
83
|
+
<div class="inline-flex items-center relative">
|
|
84
|
+
<!-- Sliding indicator - no transition until initialized to prevent FOUC -->
|
|
85
|
+
<div
|
|
86
|
+
[class]="indicatorClasses()"
|
|
87
|
+
[style.left.px]="indicatorLeft()"
|
|
88
|
+
[style.width.px]="indicatorWidth()"
|
|
89
|
+
></div>
|
|
90
|
+
|
|
91
|
+
<!-- Preview Tab -->
|
|
92
|
+
<button
|
|
93
|
+
#tabBtn
|
|
94
|
+
[class]="tabClasses(activeTab() === 'preview')"
|
|
95
|
+
(click)="setActiveTab('preview')"
|
|
96
|
+
>
|
|
97
|
+
<svg class="shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
98
|
+
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/>
|
|
99
|
+
<circle cx="12" cy="12" r="3"/>
|
|
100
|
+
</svg>
|
|
101
|
+
Preview
|
|
102
|
+
</button>
|
|
103
|
+
|
|
104
|
+
<!-- HTML Tab -->
|
|
105
|
+
@if (hasHtml()) {
|
|
106
|
+
<button
|
|
107
|
+
#tabBtn
|
|
108
|
+
[class]="tabClasses(activeTab() === 'html')"
|
|
109
|
+
(click)="setActiveTab('html')"
|
|
110
|
+
>
|
|
111
|
+
<svg class="shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
112
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
|
|
113
|
+
<polyline points="14 2 14 8 20 8"/>
|
|
114
|
+
<path d="m10 13-2 2 2 2"/>
|
|
115
|
+
<path d="m14 17 2-2-2-2"/>
|
|
116
|
+
</svg>
|
|
117
|
+
HTML
|
|
118
|
+
</button>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
<!-- Code Tab -->
|
|
122
|
+
@if (hasCode()) {
|
|
123
|
+
<button
|
|
124
|
+
#tabBtn
|
|
125
|
+
[class]="tabClasses(activeTab() === 'code')"
|
|
126
|
+
(click)="setActiveTab('code')"
|
|
127
|
+
>
|
|
128
|
+
<svg class="shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
129
|
+
<polyline points="16 18 22 12 16 6"/>
|
|
130
|
+
<polyline points="8 6 2 12 8 18"/>
|
|
131
|
+
</svg>
|
|
132
|
+
Code
|
|
133
|
+
</button>
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
<!-- Style Tab -->
|
|
137
|
+
@if (hasStyle()) {
|
|
138
|
+
<button
|
|
139
|
+
#tabBtn
|
|
140
|
+
[class]="tabClasses(activeTab() === 'style')"
|
|
141
|
+
(click)="setActiveTab('style')"
|
|
142
|
+
>
|
|
143
|
+
<svg class="shrink-0" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
144
|
+
<path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1"/>
|
|
145
|
+
<path d="M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1"/>
|
|
146
|
+
</svg>
|
|
147
|
+
Style
|
|
148
|
+
</button>
|
|
149
|
+
}
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- Actions group -->
|
|
153
|
+
<div class="inline-flex items-center gap-1">
|
|
154
|
+
<!-- Background Toggle -->
|
|
155
|
+
<button
|
|
156
|
+
class="flex items-center justify-center px-2 py-1 border-0 rounded-md bg-transparent cursor-pointer"
|
|
157
|
+
[title]="useThemeBg() ? 'Switch to muted background' : 'Switch to theme background'"
|
|
158
|
+
(click)="toggleBackground()"
|
|
159
|
+
>
|
|
160
|
+
<span [class]="toggleTrackClasses()">
|
|
161
|
+
<span [class]="toggleThumbClasses()"></span>
|
|
162
|
+
</span>
|
|
163
|
+
</button>
|
|
164
|
+
|
|
165
|
+
<!-- Fullscreen Button -->
|
|
166
|
+
<button
|
|
167
|
+
class="flex items-center justify-center w-8 h-8 border-0 rounded-md bg-transparent text-muted-foreground hover:text-foreground cursor-pointer transition-colors"
|
|
168
|
+
title="Fullscreen"
|
|
169
|
+
(click)="toggleFullscreen()"
|
|
170
|
+
>
|
|
171
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
172
|
+
<path d="M8 3H5a2 2 0 0 0-2 2v3"/>
|
|
173
|
+
<path d="M21 8V5a2 2 0 0 0-2-2h-3"/>
|
|
174
|
+
<path d="M3 16v3a2 2 0 0 0 2 2h3"/>
|
|
175
|
+
<path d="M16 21h3a2 2 0 0 0 2-2v-3"/>
|
|
176
|
+
</svg>
|
|
177
|
+
</button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<!-- Preview Tab Content -->
|
|
182
|
+
<div [class]="contentAreaClasses()">
|
|
183
|
+
@if (previewTemplate()) {
|
|
184
|
+
<ng-container *ngTemplateOutlet="previewTemplate()" />
|
|
185
|
+
} @else {
|
|
186
|
+
<ng-content select="sng-preview-block" />
|
|
187
|
+
}
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<!-- HTML Tab Content -->
|
|
191
|
+
<div [class]="codeAreaClasses(activeTab() === 'html')">
|
|
192
|
+
<ng-content select="sng-html-block" />
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<!-- Code Tab Content -->
|
|
196
|
+
<div [class]="codeAreaClasses(activeTab() === 'code')">
|
|
197
|
+
<ng-content select="sng-code-block, sng-preview-code-block" />
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<!-- Style Tab Content -->
|
|
201
|
+
<div [class]="codeAreaClasses(activeTab() === 'style')">
|
|
202
|
+
<ng-content select="sng-style-block" />
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
`
|
|
206
|
+
})
|
|
207
|
+
export class SngPreviewBoxComponent implements AfterViewInit {
|
|
208
|
+
private injector = inject(Injector);
|
|
209
|
+
|
|
210
|
+
tabButtons = viewChildren<ElementRef<HTMLButtonElement>>('tabBtn');
|
|
211
|
+
|
|
212
|
+
/** Custom CSS classes. */
|
|
213
|
+
class = input<string>('');
|
|
214
|
+
|
|
215
|
+
// Host classes: default h-[350px], user can override with class="h-[700px]"
|
|
216
|
+
hostClasses = computed(() => cn(
|
|
217
|
+
'block h-[350px]',
|
|
218
|
+
this.class()
|
|
219
|
+
));
|
|
220
|
+
|
|
221
|
+
// Container classes
|
|
222
|
+
containerClasses = computed(() => cn(
|
|
223
|
+
'flex flex-col h-full border border-border rounded-lg overflow-hidden',
|
|
224
|
+
this.isFullscreen() && 'fixed inset-6 z-[10001] rounded-xl shadow-2xl bg-background'
|
|
225
|
+
));
|
|
226
|
+
|
|
227
|
+
// Tab button classes
|
|
228
|
+
tabClasses(isActive: boolean) {
|
|
229
|
+
return cn(
|
|
230
|
+
'inline-flex items-center gap-2 px-3.5 py-2 border-0 rounded-md bg-transparent text-sm text-muted-foreground cursor-pointer transition-colors relative z-[1]',
|
|
231
|
+
'hover:text-foreground',
|
|
232
|
+
isActive && 'text-foreground font-medium'
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Toggle track classes - no transition to prevent FOUC
|
|
237
|
+
toggleTrackClasses = computed(() => cn(
|
|
238
|
+
'block w-9 h-5 rounded-full relative border',
|
|
239
|
+
this.useThemeBg()
|
|
240
|
+
? 'bg-muted border-border hover:border-muted-foreground'
|
|
241
|
+
: 'bg-primary border-primary'
|
|
242
|
+
));
|
|
243
|
+
|
|
244
|
+
// Toggle thumb classes - no transition to prevent FOUC
|
|
245
|
+
toggleThumbClasses = computed(() => cn(
|
|
246
|
+
'block w-3.5 h-3.5 rounded-full absolute top-[2px] left-[2px]',
|
|
247
|
+
this.useThemeBg()
|
|
248
|
+
? 'bg-muted-foreground'
|
|
249
|
+
: 'bg-primary-foreground translate-x-4'
|
|
250
|
+
));
|
|
251
|
+
|
|
252
|
+
// Content area classes (preview tab)
|
|
253
|
+
contentAreaClasses = computed(() => cn(
|
|
254
|
+
'bg-background relative',
|
|
255
|
+
this.activeTab() === 'preview'
|
|
256
|
+
? 'flex flex-col items-stretch justify-start flex-1 min-h-0 overflow-y-auto'
|
|
257
|
+
: 'hidden',
|
|
258
|
+
!this.useThemeBg() && 'bg-muted'
|
|
259
|
+
));
|
|
260
|
+
|
|
261
|
+
// Code area classes (html/code/style tabs)
|
|
262
|
+
codeAreaClasses(isActive: boolean) {
|
|
263
|
+
return cn(
|
|
264
|
+
'sng-preview-box-code-area p-0 bg-muted overflow-hidden',
|
|
265
|
+
isActive ? 'flex flex-col flex-1' : 'hidden',
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Content child for template-based preview
|
|
270
|
+
previewTemplate = contentChild<TemplateRef<unknown>>('preview');
|
|
271
|
+
|
|
272
|
+
// Content children to detect tab content
|
|
273
|
+
htmlBlock = contentChild(SngHtmlBlock);
|
|
274
|
+
codeBlock = contentChild(SngCodeBlock);
|
|
275
|
+
previewCodeBlock = contentChild(SngPreviewCodeBlock);
|
|
276
|
+
styleBlock = contentChild(SngStyleBlock);
|
|
277
|
+
|
|
278
|
+
// Computed signals to check if tabs have content
|
|
279
|
+
hasHtml = computed(() => {
|
|
280
|
+
const block = this.htmlBlock();
|
|
281
|
+
return block && block.code()?.trim().length > 0;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
hasCode = computed(() => {
|
|
285
|
+
const previewCodeBlock = this.previewCodeBlock();
|
|
286
|
+
if (previewCodeBlock) {
|
|
287
|
+
return previewCodeBlock.code()?.trim().length > 0;
|
|
288
|
+
}
|
|
289
|
+
const block = this.codeBlock();
|
|
290
|
+
return block && block.code()?.trim().length > 0;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
hasStyle = computed(() => {
|
|
294
|
+
const block = this.styleBlock();
|
|
295
|
+
return block && block.code()?.trim().length > 0;
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
activeTab = signal<TabType>('preview');
|
|
299
|
+
isFullscreen = signal(false);
|
|
300
|
+
useThemeBg = signal(true); // true = theme bg (default), false = muted grey
|
|
301
|
+
indicatorLeft = signal(0);
|
|
302
|
+
indicatorWidth = signal(0);
|
|
303
|
+
isIndicatorInitialized = signal(false);
|
|
304
|
+
|
|
305
|
+
// Indicator classes - only add transition after initial positioning to prevent FOUC
|
|
306
|
+
indicatorClasses = computed(() => cn(
|
|
307
|
+
'absolute h-full top-0 bg-background border border-border rounded-md shadow-sm pointer-events-none',
|
|
308
|
+
this.isIndicatorInitialized() && 'transition-all duration-200 ease-out'
|
|
309
|
+
));
|
|
310
|
+
|
|
311
|
+
constructor() {
|
|
312
|
+
// Update indicator when tab buttons are available
|
|
313
|
+
effect(() => {
|
|
314
|
+
const buttons = this.tabButtons();
|
|
315
|
+
const tab = this.activeTab();
|
|
316
|
+
if (buttons.length > 0) {
|
|
317
|
+
this.updateIndicator(tab, buttons);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
ngAfterViewInit() {
|
|
323
|
+
// Initial indicator position
|
|
324
|
+
afterNextRender(() => {
|
|
325
|
+
const buttons = this.tabButtons();
|
|
326
|
+
if (buttons.length > 0) {
|
|
327
|
+
this.updateIndicator('preview', buttons);
|
|
328
|
+
// Enable transitions after initial positioning (next frame)
|
|
329
|
+
requestAnimationFrame(() => this.isIndicatorInitialized.set(true));
|
|
330
|
+
}
|
|
331
|
+
}, { injector: this.injector });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private updateIndicator(tab: TabType, buttons: readonly ElementRef<HTMLButtonElement>[]) {
|
|
335
|
+
// Calculate dynamic tab index based on visible tabs
|
|
336
|
+
let tabIndex = 0;
|
|
337
|
+
if (tab === 'preview') {
|
|
338
|
+
tabIndex = 0;
|
|
339
|
+
} else if (tab === 'html') {
|
|
340
|
+
tabIndex = 1;
|
|
341
|
+
} else if (tab === 'code') {
|
|
342
|
+
tabIndex = 1 + (this.hasHtml() ? 1 : 0);
|
|
343
|
+
} else if (tab === 'style') {
|
|
344
|
+
tabIndex = 1 + (this.hasHtml() ? 1 : 0) + (this.hasCode() ? 1 : 0);
|
|
345
|
+
}
|
|
346
|
+
const button = buttons[tabIndex]?.nativeElement;
|
|
347
|
+
if (button) {
|
|
348
|
+
const parent = button.parentElement;
|
|
349
|
+
if (parent) {
|
|
350
|
+
const parentRect = parent.getBoundingClientRect();
|
|
351
|
+
const buttonRect = button.getBoundingClientRect();
|
|
352
|
+
this.indicatorLeft.set(buttonRect.left - parentRect.left);
|
|
353
|
+
this.indicatorWidth.set(buttonRect.width);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
setActiveTab(tab: TabType) {
|
|
359
|
+
this.activeTab.set(tab);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
toggleBackground() {
|
|
363
|
+
this.useThemeBg.update(v => !v);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
toggleFullscreen() {
|
|
367
|
+
this.isFullscreen.update(v => !v);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
input,
|
|
6
|
+
} from '@angular/core';
|
|
7
|
+
import { SngCodeBlock, type ShikiTheme } from '../code-block/sng-code-block';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SngStyleBlock - CSS/Tailwind styles for Style tab in preview-box.
|
|
11
|
+
*
|
|
12
|
+
* Displays syntax-highlighted CSS or style code in the Style tab of preview-box.
|
|
13
|
+
* Wraps sng-code-block internally for consistent styling.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```html
|
|
17
|
+
* <sng-preview-box>
|
|
18
|
+
* <sng-preview-block>
|
|
19
|
+
* <div class="custom-card">Card content</div>
|
|
20
|
+
* </sng-preview-block>
|
|
21
|
+
* <sng-html-block [code]="htmlCode" />
|
|
22
|
+
* <sng-style-block [code]="cssStyles" [theme]="'github-dark'" />
|
|
23
|
+
* </sng-preview-box>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
@Component({
|
|
27
|
+
selector: 'sng-style-block',
|
|
28
|
+
standalone: true,
|
|
29
|
+
imports: [SngCodeBlock],
|
|
30
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
31
|
+
encapsulation: ViewEncapsulation.None,
|
|
32
|
+
host: {},
|
|
33
|
+
styles: [`
|
|
34
|
+
sng-style-block {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
height: 100%;
|
|
38
|
+
}
|
|
39
|
+
sng-style-block sng-code-block {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
height: 100%;
|
|
43
|
+
}
|
|
44
|
+
sng-style-block .code-container {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
height: 100%;
|
|
48
|
+
border: none;
|
|
49
|
+
border-radius: 0;
|
|
50
|
+
}
|
|
51
|
+
sng-style-block .code-content {
|
|
52
|
+
flex: 1;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
}
|
|
55
|
+
`],
|
|
56
|
+
template: `
|
|
57
|
+
<sng-code-block
|
|
58
|
+
[code]="code()"
|
|
59
|
+
[language]="language()"
|
|
60
|
+
[theme]="theme()"
|
|
61
|
+
[showHeader]="false"
|
|
62
|
+
/>
|
|
63
|
+
`
|
|
64
|
+
})
|
|
65
|
+
export class SngStyleBlock {
|
|
66
|
+
/**
|
|
67
|
+
* The CSS/style code string to display with syntax highlighting.
|
|
68
|
+
*/
|
|
69
|
+
code = input.required<string>();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The language for syntax highlighting.
|
|
73
|
+
*/
|
|
74
|
+
language = input<string>('css');
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The Shiki theme for syntax highlighting.
|
|
78
|
+
*/
|
|
79
|
+
theme = input<ShikiTheme>('github-light');
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SngProgress } from './sng-progress';
|