@stacksjs/components 0.2.93 → 0.2.94
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/dist/index.js +4 -4
- package/package.json +5 -6
- package/src/components/CodeBlock.stx +0 -54
- package/src/components/Footer.stx +0 -66
- package/src/components/Hero.stx +0 -25
- package/src/components/Installation.stx +0 -37
- package/src/components/index.ts +0 -4
- package/src/composables/index.ts +0 -4
- package/src/composables/useCopyCode.ts +0 -73
- package/src/composables/useDarkMode.ts +0 -100
- package/src/composables/useSEO.ts +0 -230
- package/src/composables/utilities/index.ts +0 -7
- package/src/composables/utilities/useClickOutside.ts +0 -72
- package/src/composables/utilities/useFocusTrap.ts +0 -159
- package/src/composables/utilities/useKeyboard.ts +0 -124
- package/src/composables/utilities/useLocalStorage.ts +0 -132
- package/src/composables/utilities/useMediaQuery.ts +0 -118
- package/src/index.ts +0 -99
- package/src/stx.d.ts +0 -4
- package/src/ui/accordion/Accordion.stx +0 -146
- package/src/ui/accordion/AccordionItem.stx +0 -37
- package/src/ui/accordion/index.ts +0 -47
- package/src/ui/audio/Audio.stx +0 -50
- package/src/ui/audio/README.md +0 -41
- package/src/ui/audio/index.ts +0 -13
- package/src/ui/auth/Login.stx +0 -161
- package/src/ui/auth/README.md +0 -142
- package/src/ui/auth/Signup.stx +0 -159
- package/src/ui/auth/TwoFactorChallenge.stx +0 -111
- package/src/ui/auth/index.ts +0 -32
- package/src/ui/avatar/Avatar.stx +0 -77
- package/src/ui/avatar/index.ts +0 -12
- package/src/ui/badge/Badge.stx +0 -62
- package/src/ui/badge/index.ts +0 -10
- package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
- package/src/ui/breadcrumb/index.ts +0 -15
- package/src/ui/button/Button.stx +0 -74
- package/src/ui/button/README.md +0 -80
- package/src/ui/button/index.ts +0 -85
- package/src/ui/calendar/Calendar.stx +0 -189
- package/src/ui/calendar/README.md +0 -254
- package/src/ui/calendar/index.ts +0 -14
- package/src/ui/card/Card.stx +0 -68
- package/src/ui/card/index.ts +0 -13
- package/src/ui/checkbox/Checkbox.stx +0 -86
- package/src/ui/checkbox/index.ts +0 -16
- package/src/ui/combobox/Combobox.stx +0 -96
- package/src/ui/combobox/ComboboxButton.stx +0 -25
- package/src/ui/combobox/ComboboxInput.stx +0 -32
- package/src/ui/combobox/ComboboxOption.stx +0 -49
- package/src/ui/combobox/ComboboxOptions.stx +0 -16
- package/src/ui/combobox/README.md +0 -150
- package/src/ui/combobox/index.ts +0 -40
- package/src/ui/command-palette/CommandPalette.stx +0 -81
- package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
- package/src/ui/command-palette/README.md +0 -42
- package/src/ui/command-palette/index.ts +0 -15
- package/src/ui/dialog/Dialog.stx +0 -41
- package/src/ui/dialog/DialogBackdrop.stx +0 -9
- package/src/ui/dialog/DialogDescription.stx +0 -11
- package/src/ui/dialog/DialogPanel.stx +0 -16
- package/src/ui/dialog/DialogTitle.stx +0 -11
- package/src/ui/dialog/README.md +0 -121
- package/src/ui/dialog/index.ts +0 -32
- package/src/ui/drawer/Drawer.stx +0 -120
- package/src/ui/drawer/README.md +0 -90
- package/src/ui/drawer/index.ts +0 -9
- package/src/ui/dropdown/Dropdown.stx +0 -82
- package/src/ui/dropdown/DropdownButton.stx +0 -29
- package/src/ui/dropdown/DropdownItem.stx +0 -35
- package/src/ui/dropdown/DropdownItems.stx +0 -18
- package/src/ui/dropdown/README.md +0 -114
- package/src/ui/dropdown/index.ts +0 -29
- package/src/ui/form/Form.stx +0 -95
- package/src/ui/form/index.ts +0 -67
- package/src/ui/heatmap/Heatmap.stx +0 -294
- package/src/ui/image/Image.stx +0 -165
- package/src/ui/image/README.md +0 -164
- package/src/ui/image/index.ts +0 -22
- package/src/ui/input/EmailInput.stx +0 -30
- package/src/ui/input/NumberInput.stx +0 -126
- package/src/ui/input/PasswordInput.stx +0 -143
- package/src/ui/input/SearchInput.stx +0 -44
- package/src/ui/input/TextInput.stx +0 -132
- package/src/ui/input/index.ts +0 -180
- package/src/ui/listbox/Listbox.stx +0 -101
- package/src/ui/listbox/ListboxButton.stx +0 -28
- package/src/ui/listbox/ListboxLabel.stx +0 -11
- package/src/ui/listbox/ListboxOption.stx +0 -49
- package/src/ui/listbox/ListboxOptions.stx +0 -16
- package/src/ui/listbox/README.md +0 -135
- package/src/ui/listbox/index.ts +0 -39
- package/src/ui/navigator/Navigator.stx +0 -113
- package/src/ui/navigator/README.md +0 -352
- package/src/ui/navigator/index.ts +0 -20
- package/src/ui/notification/Notification.stx +0 -117
- package/src/ui/notification/README.md +0 -114
- package/src/ui/notification/index.ts +0 -12
- package/src/ui/pagination/Pagination.stx +0 -150
- package/src/ui/pagination/index.ts +0 -11
- package/src/ui/payment/Checkout.stx +0 -31
- package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
- package/src/ui/payment/PaymentMethods.stx +0 -104
- package/src/ui/payment/README.md +0 -345
- package/src/ui/payment/SubscriptionCheckout.stx +0 -323
- package/src/ui/payment/index.ts +0 -59
- package/src/ui/popover/Popover.stx +0 -60
- package/src/ui/popover/PopoverButton.stx +0 -29
- package/src/ui/popover/PopoverPanel.stx +0 -23
- package/src/ui/popover/README.md +0 -91
- package/src/ui/popover/index.ts +0 -22
- package/src/ui/portal/Portal.stx +0 -57
- package/src/ui/portal/index.ts +0 -6
- package/src/ui/progress/Progress.stx +0 -131
- package/src/ui/progress/index.ts +0 -12
- package/src/ui/radio/Radio.stx +0 -77
- package/src/ui/radio/index.ts +0 -15
- package/src/ui/radio-group/README.md +0 -139
- package/src/ui/radio-group/RadioGroup.stx +0 -60
- package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
- package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
- package/src/ui/radio-group/RadioGroupOption.stx +0 -58
- package/src/ui/radio-group/index.ts +0 -30
- package/src/ui/select/README.md +0 -180
- package/src/ui/select/Select.stx +0 -82
- package/src/ui/select/index.ts +0 -21
- package/src/ui/sidebar/Sidebar.stx +0 -476
- package/src/ui/sidebar/SidebarFooter.stx +0 -71
- package/src/ui/sidebar/SidebarHeader.stx +0 -103
- package/src/ui/sidebar/SidebarItem.stx +0 -86
- package/src/ui/sidebar/SidebarSection.stx +0 -83
- package/src/ui/sidebar/index.ts +0 -153
- package/src/ui/sidebar/themes.ts +0 -240
- package/src/ui/skeleton/Skeleton.stx +0 -48
- package/src/ui/skeleton/index.ts +0 -11
- package/src/ui/spinner/Spinner.stx +0 -109
- package/src/ui/spinner/index.ts +0 -9
- package/src/ui/stepper/README.md +0 -36
- package/src/ui/stepper/Stepper.stx +0 -17
- package/src/ui/stepper/StepperStep.stx +0 -57
- package/src/ui/stepper/index.ts +0 -19
- package/src/ui/storage/README.md +0 -193
- package/src/ui/storage/index.ts +0 -347
- package/src/ui/switch/README.md +0 -114
- package/src/ui/switch/Switch.stx +0 -72
- package/src/ui/switch/index.ts +0 -10
- package/src/ui/table/README.md +0 -39
- package/src/ui/table/Table.stx +0 -14
- package/src/ui/table/TableBody.stx +0 -10
- package/src/ui/table/TableCell.stx +0 -10
- package/src/ui/table/TableHead.stx +0 -10
- package/src/ui/table/TableHeader.stx +0 -20
- package/src/ui/table/TableRow.stx +0 -11
- package/src/ui/table/index.ts +0 -35
- package/src/ui/tabs/TabPanel.stx +0 -25
- package/src/ui/tabs/Tabs.stx +0 -202
- package/src/ui/tabs/index.ts +0 -50
- package/src/ui/teleport/Teleport.stx +0 -65
- package/src/ui/teleport/index.ts +0 -7
- package/src/ui/textarea/Textarea.stx +0 -108
- package/src/ui/textarea/index.ts +0 -20
- package/src/ui/tooltip/Tooltip.stx +0 -71
- package/src/ui/tooltip/index.ts +0 -10
- package/src/ui/transition/README.md +0 -30
- package/src/ui/transition/Transition.stx +0 -102
- package/src/ui/transition/index.ts +0 -25
- package/src/ui/video/README.md +0 -47
- package/src/ui/video/Video.stx +0 -45
- package/src/ui/video/index.ts +0 -16
- package/src/ui/virtual-list/VirtualList.stx +0 -67
- package/src/ui/virtual-list/index.ts +0 -10
- package/src/ui/virtual-table/VirtualTable.stx +0 -103
- package/src/ui/virtual-table/index.ts +0 -21
- package/src/utils/PROP_VALIDATION.md +0 -458
- package/src/utils/THEME_SYSTEM.md +0 -702
- package/src/utils/accessibility.ts +0 -841
- package/src/utils/animation/easing.ts +0 -368
- package/src/utils/animation/helpers.ts +0 -223
- package/src/utils/animation/index.ts +0 -5
- package/src/utils/animation/keyframes.ts +0 -230
- package/src/utils/error-handling.ts +0 -475
- package/src/utils/highlighter.ts +0 -93
- package/src/utils/i18n.ts +0 -634
- package/src/utils/keep-alive.ts +0 -819
- package/src/utils/lazy-loading.ts +0 -530
- package/src/utils/prop-validation.ts +0 -478
- package/src/utils/theme.ts +0 -626
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
2
|
+
// ../../../../../../../tmp/stx-components-build-ll8wSO/stubs/stub-0.js
|
|
3
3
|
var stub_0_default = { __stx: true, src: "./components/CodeBlock.stx" };
|
|
4
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
4
|
+
// ../../../../../../../tmp/stx-components-build-ll8wSO/stubs/stub-1.js
|
|
5
5
|
var stub_1_default = { __stx: true, src: "./components/Footer.stx" };
|
|
6
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
6
|
+
// ../../../../../../../tmp/stx-components-build-ll8wSO/stubs/stub-2.js
|
|
7
7
|
var stub_2_default = { __stx: true, src: "./components/Hero.stx" };
|
|
8
|
-
// ../../../../../../../tmp/stx-components-build-
|
|
8
|
+
// ../../../../../../../tmp/stx-components-build-ll8wSO/stubs/stub-3.js
|
|
9
9
|
var stub_3_default = { __stx: true, src: "./components/Installation.stx" };
|
|
10
10
|
// src/composables/useCopyCode.ts
|
|
11
11
|
function useCopyCode(options) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/components",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.94",
|
|
5
5
|
"description": "A modern component library built with STX, featuring headwind utility classes and TypeScript syntax highlighting.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
|
-
"bun": "./
|
|
32
|
+
"bun": "./dist/index.js",
|
|
33
33
|
"import": "./dist/index.js"
|
|
34
34
|
},
|
|
35
35
|
"./*": {
|
|
36
36
|
"types": "./dist/*/index.d.ts",
|
|
37
|
-
"bun": "./
|
|
37
|
+
"bun": "./dist/*/index.js",
|
|
38
38
|
"import": "./dist/*/index.js"
|
|
39
39
|
},
|
|
40
40
|
"./stx-plugin": {
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
"files": [
|
|
48
48
|
"README.md",
|
|
49
49
|
"dist",
|
|
50
|
-
"src",
|
|
51
50
|
"stx-plugin.ts"
|
|
52
51
|
],
|
|
53
52
|
"scripts": {
|
|
@@ -63,8 +62,8 @@
|
|
|
63
62
|
},
|
|
64
63
|
"dependencies": {
|
|
65
64
|
"@cwcss/crosswind": "^0.2.6",
|
|
66
|
-
"@stacksjs/stx": "0.2.
|
|
67
|
-
"bun-plugin-stx": "0.2.
|
|
65
|
+
"@stacksjs/stx": "0.2.94",
|
|
66
|
+
"bun-plugin-stx": "0.2.94",
|
|
68
67
|
"ts-syntax-highlighter": "^0.2.1"
|
|
69
68
|
},
|
|
70
69
|
"devDependencies": {
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
import { applyHeadwindClasses, highlight } from '../utils/highlighter'
|
|
3
|
-
|
|
4
|
-
export const code = $props.code || ''
|
|
5
|
-
export const language = $props.language || 'typescript'
|
|
6
|
-
export const theme = $props.theme || 'auto'
|
|
7
|
-
export const lineNumbers = $props.lineNumbers !== false
|
|
8
|
-
export const copyable = $props.copyable !== false
|
|
9
|
-
export const className = $props.className || ''
|
|
10
|
-
|
|
11
|
-
const result = await highlight(code, { language, theme, lineNumbers })
|
|
12
|
-
export const highlightedCode = applyHeadwindClasses(result.html, className)
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<script client>
|
|
16
|
-
const code = {{ code }}
|
|
17
|
-
const copied = state(false)
|
|
18
|
-
|
|
19
|
-
async function copyToClipboard() {
|
|
20
|
-
try {
|
|
21
|
-
await navigator.clipboard.writeText(code)
|
|
22
|
-
copied.set(true)
|
|
23
|
-
setTimeout(() => copied.set(false), 2000)
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
console.error('Failed to copy code:', err)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<div class="relative group">
|
|
32
|
-
{!! highlightedCode !!}
|
|
33
|
-
|
|
34
|
-
@if(copyable)
|
|
35
|
-
<button
|
|
36
|
-
@click="copyToClipboard()"
|
|
37
|
-
class="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 px-3 py-1.5 bg-neutral-800 hover:bg-neutral-700 text-white text-xs rounded-md font-medium"
|
|
38
|
-
aria-label="Copy code"
|
|
39
|
-
>
|
|
40
|
-
<span :show="copied()" class="flex items-center gap-1.5">
|
|
41
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
42
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
43
|
-
</svg>
|
|
44
|
-
Copied!
|
|
45
|
-
</span>
|
|
46
|
-
<span :show="!copied()" class="flex items-center gap-1.5">
|
|
47
|
-
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
48
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
49
|
-
</svg>
|
|
50
|
-
Copy
|
|
51
|
-
</span>
|
|
52
|
-
</button>
|
|
53
|
-
@endif
|
|
54
|
-
</div>
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const author = $props.author || '@chrisbbreuer'
|
|
3
|
-
export const authorUrl = $props.authorUrl || 'https://github.com/chrisbbreuer'
|
|
4
|
-
export const project = $props.project || '@stacksjs'
|
|
5
|
-
export const projectUrl = $props.projectUrl || 'https://github.com/stacksjs/stacks'
|
|
6
|
-
export const twitterUrl = $props.twitterUrl || 'https://twitter.com/chrisbbreuer'
|
|
7
|
-
export const sponsorUrl = $props.sponsorUrl || 'https://github.com/sponsors/chrisbbreuer'
|
|
8
|
-
export const coffeeUrl = $props.coffeeUrl || 'https://www.buymeacoffee.com/xlbd'
|
|
9
|
-
|
|
10
|
-
export const currentYear = new Date().getFullYear()
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<footer class="flex items-center justify-center mt-16 w-full pb-4 text-neutral-600 dark:text-neutral-400 opacity-60">
|
|
14
|
-
<div class="flex flex-col items-center justify-center">
|
|
15
|
-
<p class="text-sm">
|
|
16
|
-
With 💙 by
|
|
17
|
-
<a href="{{ authorUrl }}" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
18
|
-
{{ author }}
|
|
19
|
-
</a>
|
|
20
|
-
&
|
|
21
|
-
<a href="{{ projectUrl }}" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
22
|
-
{{ project }}
|
|
23
|
-
</a>
|
|
24
|
-
<span> © {{ currentYear }}</span>
|
|
25
|
-
</p>
|
|
26
|
-
|
|
27
|
-
<div class="mt-2 flex flex-col items-center sm:flex-row space-x-1 space-y-2 sm:space-y-0">
|
|
28
|
-
<div class="flex items-center space-x-1">
|
|
29
|
-
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
30
|
-
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
|
|
31
|
-
</svg>
|
|
32
|
-
<span class="text-sm">
|
|
33
|
-
<a href="{{ twitterUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
34
|
-
Follow me on Twitter
|
|
35
|
-
</a>
|
|
36
|
-
</span>
|
|
37
|
-
</div>
|
|
38
|
-
|
|
39
|
-
<span class="hidden px-2 text-neutral-400 sm:block">|</span>
|
|
40
|
-
|
|
41
|
-
<div class="flex items-center space-x-1">
|
|
42
|
-
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
43
|
-
<path d="M20.216 6.415l-.132-.666c-.119-.598-.388-1.163-1.001-1.379-.197-.069-.42-.098-.57-.241-.152-.143-.196-.366-.231-.572-.065-.378-.125-.756-.192-1.133-.057-.325-.102-.69-.25-.987-.195-.4-.597-.634-.996-.788a5.723 5.723 0 00-.626-.194c-1-.263-2.05-.36-3.077-.416a25.834 25.834 0 00-3.7.062c-.915.083-1.88.184-2.75.5-.318.116-.646.256-.888.501-.297.302-.393.77-.177 1.146.154.267.415.456.692.58.36.162.737.284 1.123.366 1.075.238 2.189.331 3.287.37 1.218.05 2.437.01 3.65-.118.299-.033.598-.073.896-.119.352-.054.578-.513.474-.834-.124-.383-.457-.531-.834-.473-.466.074-.96.108-1.382.146-1.177.08-2.358.082-3.536.006a22.228 22.228 0 01-1.157-.107c-.086-.01-.18-.025-.258-.036-.243-.036-.484-.08-.724-.13-.111-.027-.111-.185 0-.212h.005c.277-.06.557-.108.838-.147h.002c.131-.009.263-.032.394-.048a25.076 25.076 0 013.426-.12c.674.019 1.347.067 2.017.144l.228.031c.267.04.533.088.798.145.392.085.895.113 1.07.542.055.137.08.288.111.431l.319 1.484a.237.237 0 01-.199.284h-.003c-.037.006-.075.01-.112.015a36.704 36.704 0 01-4.743.295 37.059 37.059 0 01-4.699-.304c-.14-.017-.293-.042-.417-.06-.326-.048-.649-.108-.973-.161-.393-.065-.768-.032-1.123.161-.29.16-.527.404-.675.701-.154.316-.199.66-.267 1-.069.34-.176.707-.135 1.056.087.753.613 1.365 1.37 1.502a39.69 39.69 0 0011.343.376.483.483 0 01.535.53l-.071.697-1.018 9.907c-.041.41-.047.832-.125 1.237-.122.637-.553 1.028-1.182 1.171-.577.131-1.165.2-1.756.205-.656.004-1.31-.025-1.966-.022-.699.004-1.556-.06-2.095-.58-.475-.458-.54-1.174-.605-1.793l-.731-7.013-.322-3.094c-.037-.351-.286-.695-.678-.678-.336.015-.718.3-.678.679l.228 2.185.949 9.112c.147 1.344 1.174 2.068 2.446 2.272.742.12 1.503.144 2.257.156.966.016 1.942.053 2.892-.122 1.408-.258 2.465-1.198 2.616-2.657.34-3.332.683-6.663 1.024-9.995l.215-2.087a.484.484 0 01.39-.426c.402-.078.787-.212 1.074-.518.455-.488.546-1.124.385-1.766zm-1.478.772c-.145.137-.363.201-.578.233-2.416.359-4.866.54-7.308.46-1.748-.06-3.477-.254-5.207-.498-.17-.024-.353-.055-.47-.18-.22-.236-.111-.71-.054-.995.052-.26.152-.609.463-.646.484-.057 1.046.148 1.526.22.577.088 1.156.16 1.737.212 2.48.226 5.002.19 7.472-.14.45-.06.899-.13 1.345-.21.399-.072.84-.206 1.08.206.166.281.188.657.162.974a.544.544 0 01-.169.364zm-6.159 3.9c-.862.37-1.84.788-3.109.788a5.884 5.884 0 01-1.569-.217l.877 9.004c.065.78.717 1.38 1.5 1.38 0 0 1.243.065 1.658.065.447 0 1.786-.065 1.786-.065.783 0 1.434-.6 1.499-1.38l.94-9.95a3.996 3.996 0 00-1.322-.238c-.826 0-1.491.284-2.26.613z" />
|
|
44
|
-
</svg>
|
|
45
|
-
<span class="text-sm">
|
|
46
|
-
<a href="{{ coffeeUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
47
|
-
Buy me a coffee
|
|
48
|
-
</a>
|
|
49
|
-
</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<span class="hidden px-2 text-neutral-400 sm:block">|</span>
|
|
53
|
-
|
|
54
|
-
<div class="flex items-center space-x-1">
|
|
55
|
-
<svg class="w-4 h-4 text-blue-500" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
56
|
-
<path d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z" />
|
|
57
|
-
</svg>
|
|
58
|
-
<span class="text-sm">
|
|
59
|
-
<a href="{{ sponsorUrl }}" target="_blank" rel="noopener noreferrer" class="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
60
|
-
Sponsor me on GitHub
|
|
61
|
-
</a>
|
|
62
|
-
</span>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
</footer>
|
package/src/components/Hero.stx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const title = $props.title || 'Component'
|
|
3
|
-
export const description = $props.description || 'A modern component built with STX'
|
|
4
|
-
export const githubUrl = $props.githubUrl || '#'
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<div class="flex flex-col items-center gap-3">
|
|
8
|
-
<h1 class="text-5xl font-bold mb-3 -mt-5 bg-gradient-to-r from-blue-500 to-purple-600 bg-clip-text text-transparent">
|
|
9
|
-
{{ title }}
|
|
10
|
-
</h1>
|
|
11
|
-
<p class="mb-3 mt-0 text-lg text-neutral-600 dark:text-neutral-400">
|
|
12
|
-
{{ description }}
|
|
13
|
-
</p>
|
|
14
|
-
<div class="flex gap-2">
|
|
15
|
-
<slot name="demo" />
|
|
16
|
-
<a
|
|
17
|
-
href="{{ githubUrl }}"
|
|
18
|
-
target="_blank"
|
|
19
|
-
rel="noopener noreferrer"
|
|
20
|
-
class="inline-flex items-center justify-center h-10 px-8 rounded-md text-sm font-semibold bg-gradient-to-b from-white to-neutral-100 dark:from-neutral-800 dark:to-neutral-900 text-neutral-900 dark:text-white shadow-md hover:shadow-lg transition-all duration-200"
|
|
21
|
-
>
|
|
22
|
-
GitHub
|
|
23
|
-
</a>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const packageName = $props.packageName || '@stacksjs/component'
|
|
3
|
-
export const installCode = `bun add ${packageName}`
|
|
4
|
-
export const npmCode = `npm install ${packageName}`
|
|
5
|
-
export const pnpmCode = `pnpm add ${packageName}`
|
|
6
|
-
export const yarnCode = `yarn add ${packageName}`
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<div class="installation">
|
|
10
|
-
<h2 class="my-2 text-lg font-semibold">Installation</h2>
|
|
11
|
-
|
|
12
|
-
<p class="my-3 text-base">
|
|
13
|
-
Install the component using your preferred package manager:
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
<div class="space-y-4">
|
|
17
|
-
<div>
|
|
18
|
-
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Bun (recommended)</h3>
|
|
19
|
-
<CodeBlock :code="installCode" language="bash" />
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<div>
|
|
23
|
-
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">npm</h3>
|
|
24
|
-
<CodeBlock :code="npmCode" language="bash" />
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div>
|
|
28
|
-
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">pnpm</h3>
|
|
29
|
-
<CodeBlock :code="pnpmCode" language="bash" />
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
<div>
|
|
33
|
-
<h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Yarn</h3>
|
|
34
|
-
<CodeBlock :code="yarnCode" language="bash" />
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
package/src/components/index.ts
DELETED
package/src/composables/index.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copy code to clipboard with visual feedback
|
|
3
|
-
*/
|
|
4
|
-
export interface CopyCodeOptions {
|
|
5
|
-
code: string
|
|
6
|
-
onSuccess?: () => void
|
|
7
|
-
onError?: (error: Error) => void
|
|
8
|
-
timeout?: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface CopyCodeResult {
|
|
12
|
-
copied: boolean
|
|
13
|
-
copy: () => Promise<void>
|
|
14
|
-
reset: () => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function useCopyCode(options: CopyCodeOptions): CopyCodeResult {
|
|
18
|
-
const { code, onSuccess, onError, timeout = 2000 } = options
|
|
19
|
-
|
|
20
|
-
let copied = false
|
|
21
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
22
|
-
|
|
23
|
-
const reset = () => {
|
|
24
|
-
copied = false
|
|
25
|
-
if (timeoutId) {
|
|
26
|
-
clearTimeout(timeoutId)
|
|
27
|
-
timeoutId = null
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const copy = async () => {
|
|
32
|
-
try {
|
|
33
|
-
if (!navigator.clipboard) {
|
|
34
|
-
throw new Error('Clipboard API not available')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
await navigator.clipboard.writeText(code)
|
|
38
|
-
copied = true
|
|
39
|
-
onSuccess?.()
|
|
40
|
-
|
|
41
|
-
// Auto-reset after timeout
|
|
42
|
-
timeoutId = setTimeout(() => {
|
|
43
|
-
copied = false
|
|
44
|
-
timeoutId = null
|
|
45
|
-
}, timeout)
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
const err = error instanceof Error ? error : new Error('Failed to copy code')
|
|
49
|
-
onError?.(err)
|
|
50
|
-
console.error('Failed to copy code:', err)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
copied,
|
|
56
|
-
copy,
|
|
57
|
-
reset,
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Simple synchronous copy function for direct use
|
|
63
|
-
*/
|
|
64
|
-
export async function copyToClipboard(text: string): Promise<boolean> {
|
|
65
|
-
try {
|
|
66
|
-
await navigator.clipboard.writeText(text)
|
|
67
|
-
return true
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
console.error('Failed to copy to clipboard:', error)
|
|
71
|
-
return false
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dark mode utilities for STX components
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface DarkModeOptions {
|
|
6
|
-
storageKey?: string
|
|
7
|
-
defaultTheme?: 'light' | 'dark' | 'system'
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface DarkModeResult {
|
|
11
|
-
isDark: boolean
|
|
12
|
-
theme: 'light' | 'dark' | 'system'
|
|
13
|
-
toggle: () => void
|
|
14
|
-
setTheme: (theme: 'light' | 'dark' | 'system') => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Check if system prefers dark mode
|
|
19
|
-
*/
|
|
20
|
-
export function getSystemTheme(): 'light' | 'dark' {
|
|
21
|
-
if (typeof window === 'undefined')
|
|
22
|
-
return 'light'
|
|
23
|
-
|
|
24
|
-
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Get the effective theme (resolving 'system' to actual theme)
|
|
29
|
-
*/
|
|
30
|
-
export function getEffectiveTheme(theme: 'light' | 'dark' | 'system'): 'light' | 'dark' {
|
|
31
|
-
return theme === 'system' ? getSystemTheme() : theme
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Use dark mode hook
|
|
36
|
-
*/
|
|
37
|
-
export function useDarkMode(options: DarkModeOptions = {}): DarkModeResult {
|
|
38
|
-
const { storageKey = 'theme', defaultTheme = 'system' } = options
|
|
39
|
-
|
|
40
|
-
// Get initial theme from storage or use default
|
|
41
|
-
let theme: 'light' | 'dark' | 'system' = defaultTheme
|
|
42
|
-
|
|
43
|
-
if (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {
|
|
44
|
-
const stored = localStorage.getItem(storageKey) as 'light' | 'dark' | 'system' | null
|
|
45
|
-
if (stored)
|
|
46
|
-
theme = stored
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const isDark = getEffectiveTheme(theme) === 'dark'
|
|
50
|
-
|
|
51
|
-
// Apply theme to document
|
|
52
|
-
const applyTheme = (newTheme: 'light' | 'dark' | 'system') => {
|
|
53
|
-
const effective = getEffectiveTheme(newTheme)
|
|
54
|
-
|
|
55
|
-
if (typeof document !== 'undefined') {
|
|
56
|
-
if (effective === 'dark') {
|
|
57
|
-
document.documentElement.classList.add('dark')
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
document.documentElement.classList.remove('dark')
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (typeof localStorage !== 'undefined') {
|
|
65
|
-
localStorage.setItem(storageKey, newTheme)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Set theme
|
|
70
|
-
const setTheme = (newTheme: 'light' | 'dark' | 'system') => {
|
|
71
|
-
theme = newTheme
|
|
72
|
-
applyTheme(newTheme)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Toggle between light and dark
|
|
76
|
-
const toggle = () => {
|
|
77
|
-
const currentEffective = getEffectiveTheme(theme)
|
|
78
|
-
const newTheme = currentEffective === 'dark' ? 'light' : 'dark'
|
|
79
|
-
setTheme(newTheme)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Apply initial theme
|
|
83
|
-
applyTheme(theme)
|
|
84
|
-
|
|
85
|
-
// Listen for system theme changes if using system theme
|
|
86
|
-
if (typeof window !== 'undefined' && theme === 'system') {
|
|
87
|
-
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (_e) => {
|
|
88
|
-
if (theme === 'system') {
|
|
89
|
-
applyTheme('system')
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
isDark,
|
|
96
|
-
theme,
|
|
97
|
-
toggle,
|
|
98
|
-
setTheme,
|
|
99
|
-
}
|
|
100
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
/* eslint-disable style/max-statements-per-line */
|
|
2
|
-
/**
|
|
3
|
-
* SEO and meta tag utilities for STX components
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface SEOMetaOptions {
|
|
7
|
-
title?: string
|
|
8
|
-
description?: string
|
|
9
|
-
author?: string
|
|
10
|
-
keywords?: string[]
|
|
11
|
-
ogImage?: string
|
|
12
|
-
ogImageWidth?: string
|
|
13
|
-
ogImageHeight?: string
|
|
14
|
-
twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
15
|
-
twitterSite?: string
|
|
16
|
-
twitterCreator?: string
|
|
17
|
-
canonical?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Set document title
|
|
22
|
-
*/
|
|
23
|
-
export function setTitle(title: string, template?: string): void {
|
|
24
|
-
if (typeof document === 'undefined')
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
document.title = template ? template.replace('%s', title) : title
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Set meta tag
|
|
32
|
-
*/
|
|
33
|
-
export function setMeta(name: string, content: string, isProperty = false): void {
|
|
34
|
-
if (typeof document === 'undefined')
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
const attribute = isProperty ? 'property' : 'name'
|
|
38
|
-
let meta = document.querySelector(`meta[${attribute}="${name}"]`)
|
|
39
|
-
|
|
40
|
-
if (!meta) {
|
|
41
|
-
meta = document.createElement('meta')
|
|
42
|
-
meta.setAttribute(attribute, name)
|
|
43
|
-
document.head.appendChild(meta)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
meta.setAttribute('content', content)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Set link tag
|
|
51
|
-
*/
|
|
52
|
-
export function setLink(rel: string, href: string): void {
|
|
53
|
-
if (typeof document === 'undefined')
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
let link = document.querySelector(`link[rel="${rel}"]`) as HTMLLinkElement
|
|
57
|
-
|
|
58
|
-
if (!link) {
|
|
59
|
-
link = document.createElement('link')
|
|
60
|
-
link.setAttribute('rel', rel)
|
|
61
|
-
document.head.appendChild(link)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
link.setAttribute('href', href)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Use SEO meta tags
|
|
69
|
-
*/
|
|
70
|
-
export function useSEO(options: SEOMetaOptions): void {
|
|
71
|
-
const {
|
|
72
|
-
title,
|
|
73
|
-
description,
|
|
74
|
-
author,
|
|
75
|
-
keywords,
|
|
76
|
-
ogImage,
|
|
77
|
-
ogImageWidth,
|
|
78
|
-
ogImageHeight,
|
|
79
|
-
twitterCard = 'summary_large_image',
|
|
80
|
-
twitterSite,
|
|
81
|
-
twitterCreator,
|
|
82
|
-
canonical,
|
|
83
|
-
} = options
|
|
84
|
-
|
|
85
|
-
// Set title
|
|
86
|
-
if (title) {
|
|
87
|
-
setTitle(title)
|
|
88
|
-
setMeta('og:title', title, true)
|
|
89
|
-
setMeta('twitter:title', title)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Set description
|
|
93
|
-
if (description) {
|
|
94
|
-
setMeta('description', description)
|
|
95
|
-
setMeta('og:description', description, true)
|
|
96
|
-
setMeta('twitter:description', description)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Set author
|
|
100
|
-
if (author) {
|
|
101
|
-
setMeta('author', author)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Set keywords
|
|
105
|
-
if (keywords && keywords.length > 0) {
|
|
106
|
-
setMeta('keywords', keywords.join(', '))
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Set Open Graph image
|
|
110
|
-
if (ogImage) {
|
|
111
|
-
setMeta('og:image', ogImage, true)
|
|
112
|
-
setMeta('twitter:image', ogImage)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (ogImageWidth) {
|
|
116
|
-
setMeta('og:image:width', ogImageWidth, true)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (ogImageHeight) {
|
|
120
|
-
setMeta('og:image:height', ogImageHeight, true)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Set Twitter card
|
|
124
|
-
setMeta('twitter:card', twitterCard)
|
|
125
|
-
|
|
126
|
-
if (twitterSite) {
|
|
127
|
-
setMeta('twitter:site', twitterSite)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (twitterCreator) {
|
|
131
|
-
setMeta('twitter:creator', twitterCreator)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Set canonical URL
|
|
135
|
-
if (canonical) {
|
|
136
|
-
setLink('canonical', canonical)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Set og:type
|
|
140
|
-
setMeta('og:type', 'website', true)
|
|
141
|
-
|
|
142
|
-
// Set og:url from current URL
|
|
143
|
-
if (typeof window !== 'undefined') {
|
|
144
|
-
setMeta('og:url', window.location.href, true)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Generate SEO meta tags as HTML string for server-side rendering
|
|
150
|
-
*/
|
|
151
|
-
export function generateSEOTags(options: SEOMetaOptions): string {
|
|
152
|
-
const tags: string[] = []
|
|
153
|
-
|
|
154
|
-
const {
|
|
155
|
-
title,
|
|
156
|
-
description,
|
|
157
|
-
author,
|
|
158
|
-
keywords,
|
|
159
|
-
ogImage,
|
|
160
|
-
ogImageWidth,
|
|
161
|
-
ogImageHeight,
|
|
162
|
-
twitterCard = 'summary_large_image',
|
|
163
|
-
twitterSite,
|
|
164
|
-
twitterCreator,
|
|
165
|
-
canonical,
|
|
166
|
-
} = options
|
|
167
|
-
|
|
168
|
-
if (title) {
|
|
169
|
-
tags.push(`<title>${escapeHtml(title)}</title>`)
|
|
170
|
-
tags.push(`<meta property="og:title" content="${escapeHtml(title)}" />`)
|
|
171
|
-
tags.push(`<meta name="twitter:title" content="${escapeHtml(title)}" />`)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (description) {
|
|
175
|
-
tags.push(`<meta name="description" content="${escapeHtml(description)}" />`)
|
|
176
|
-
tags.push(`<meta property="og:description" content="${escapeHtml(description)}" />`)
|
|
177
|
-
tags.push(`<meta name="twitter:description" content="${escapeHtml(description)}" />`)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (author) {
|
|
181
|
-
tags.push(`<meta name="author" content="${escapeHtml(author)}" />`)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (keywords && keywords.length > 0) {
|
|
185
|
-
tags.push(`<meta name="keywords" content="${escapeHtml(keywords.join(', '))}" />`)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (ogImage) {
|
|
189
|
-
tags.push(`<meta property="og:image" content="${escapeHtml(ogImage)}" />`)
|
|
190
|
-
tags.push(`<meta name="twitter:image" content="${escapeHtml(ogImage)}" />`)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (ogImageWidth) {
|
|
194
|
-
tags.push(`<meta property="og:image:width" content="${escapeHtml(ogImageWidth)}" />`)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (ogImageHeight) {
|
|
198
|
-
tags.push(`<meta property="og:image:height" content="${escapeHtml(ogImageHeight)}" />`)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
tags.push(`<meta name="twitter:card" content="${escapeHtml(twitterCard)}" />`)
|
|
202
|
-
|
|
203
|
-
if (twitterSite) {
|
|
204
|
-
tags.push(`<meta name="twitter:site" content="${escapeHtml(twitterSite)}" />`)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (twitterCreator) {
|
|
208
|
-
tags.push(`<meta name="twitter:creator" content="${escapeHtml(twitterCreator)}" />`)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (canonical) {
|
|
212
|
-
tags.push(`<link rel="canonical" href="${escapeHtml(canonical)}" />`)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
tags.push('<meta property="og:type" content="website" />')
|
|
216
|
-
|
|
217
|
-
return tags.join('\n')
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Escape HTML special characters
|
|
222
|
-
*/
|
|
223
|
-
function escapeHtml(str: string): string {
|
|
224
|
-
return str
|
|
225
|
-
.replace(/&/g, '&')
|
|
226
|
-
.replace(/</g, '<')
|
|
227
|
-
.replace(/>/g, '>')
|
|
228
|
-
.replace(/"/g, '"')
|
|
229
|
-
.replace(/'/g, ''')
|
|
230
|
-
}
|