@coyalabs/bts-style 1.3.11 → 1.3.13
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/README.md +16 -0
- package/dist/Base/BaseText.svelte +163 -5
- package/dist/Base/BaseText.svelte.d.ts +6 -0
- package/dist/Base/markdown.d.ts +4 -0
- package/dist/Base/markdown.js +65 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -124,6 +124,11 @@ Typography component with three text variants.
|
|
|
124
124
|
|
|
125
125
|
**Props:**
|
|
126
126
|
- `variant: 'title' | 'content' | 'button'` - Text style variant
|
|
127
|
+
- `content?: string | null` - Raw text content to render directly
|
|
128
|
+
- `markdown?: boolean` - Parse `content` as sanitized markdown
|
|
129
|
+
- `as?: string | null` - Override the wrapper element (`div` is used automatically for markdown)
|
|
130
|
+
- `textModifier?: string` - Size adjustment
|
|
131
|
+
- `textWeightModifier?: string` - Weight adjustment
|
|
127
132
|
|
|
128
133
|
**Variants:**
|
|
129
134
|
- **`title`** - Noto Serif KR 900, 30px - For headings
|
|
@@ -134,8 +139,19 @@ Typography component with three text variants.
|
|
|
134
139
|
```svelte
|
|
135
140
|
<BaseText variant="title">Page Title</BaseText>
|
|
136
141
|
<BaseText variant="content">This is content text.</BaseText>
|
|
142
|
+
|
|
143
|
+
<BaseText
|
|
144
|
+
variant="content"
|
|
145
|
+
content={messageBody}
|
|
146
|
+
markdown={true}
|
|
147
|
+
/>
|
|
137
148
|
```
|
|
138
149
|
|
|
150
|
+
**Markdown notes:**
|
|
151
|
+
- Markdown rendering only applies when using the `content` prop.
|
|
152
|
+
- Output is sanitized before rendering.
|
|
153
|
+
- Supports GFM-style links, emphasis, headings, lists, blockquotes, tables, inline code, and fenced code blocks.
|
|
154
|
+
|
|
139
155
|
---
|
|
140
156
|
|
|
141
157
|
#### BaseIcon
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { renderMarkdown } from './markdown.js';
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
5
|
* @type {'title' | 'content' | 'button' | 'code'}
|
|
4
6
|
*/
|
|
5
7
|
export let variant = 'content';
|
|
6
|
-
|
|
8
|
+
/**
|
|
7
9
|
* @type {string}
|
|
8
10
|
*/
|
|
9
11
|
export let textModifier = '0px';
|
|
@@ -12,11 +14,47 @@
|
|
|
12
14
|
* @type {string}
|
|
13
15
|
*/
|
|
14
16
|
export let textWeightModifier = '0';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Raw text content. Use this with `markdown={true}` if you want markdown parsing.
|
|
20
|
+
* @type {string | null}
|
|
21
|
+
*/
|
|
22
|
+
export let content = null;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse the `content` prop as markdown and render sanitized HTML.
|
|
26
|
+
* @type {boolean}
|
|
27
|
+
*/
|
|
28
|
+
export let markdown = false;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Override the wrapper element. Defaults to `span`, or `div` when markdown is enabled.
|
|
32
|
+
* @type {string | null}
|
|
33
|
+
*/
|
|
34
|
+
export let as = null;
|
|
35
|
+
|
|
36
|
+
$: usesContent = content !== null && content !== undefined;
|
|
37
|
+
$: tagName = as || (markdown && usesContent ? 'div' : 'span');
|
|
38
|
+
$: renderedContent = markdown && usesContent ? renderMarkdown(content) : '';
|
|
15
39
|
</script>
|
|
16
40
|
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
41
|
+
<svelte:element
|
|
42
|
+
this={tagName}
|
|
43
|
+
class="text"
|
|
44
|
+
data-variant={variant}
|
|
45
|
+
data-markdown={markdown && usesContent}
|
|
46
|
+
style="--text-modifier: {textModifier}; --text-weight-modifier: {textWeightModifier};"
|
|
47
|
+
>
|
|
48
|
+
{#if usesContent}
|
|
49
|
+
{#if markdown}
|
|
50
|
+
{@html renderedContent}
|
|
51
|
+
{:else}
|
|
52
|
+
{content}
|
|
53
|
+
{/if}
|
|
54
|
+
{:else}
|
|
55
|
+
<slot />
|
|
56
|
+
{/if}
|
|
57
|
+
</svelte:element>
|
|
20
58
|
|
|
21
59
|
<style>
|
|
22
60
|
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200..900&display=swap');
|
|
@@ -28,6 +66,103 @@
|
|
|
28
66
|
font-family: 'Satoshi', sans-serif;
|
|
29
67
|
caret-color: #544a51;
|
|
30
68
|
}
|
|
69
|
+
.text[data-markdown='true'] {
|
|
70
|
+
display: block;
|
|
71
|
+
width: 100%;
|
|
72
|
+
line-height: 1.6;
|
|
73
|
+
}
|
|
74
|
+
.text[data-markdown='true'] :global(p),
|
|
75
|
+
.text[data-markdown='true'] :global(ul),
|
|
76
|
+
.text[data-markdown='true'] :global(ol),
|
|
77
|
+
.text[data-markdown='true'] :global(blockquote),
|
|
78
|
+
.text[data-markdown='true'] :global(pre),
|
|
79
|
+
.text[data-markdown='true'] :global(table),
|
|
80
|
+
.text[data-markdown='true'] :global(hr) {
|
|
81
|
+
margin: 0 0 0.9rem;
|
|
82
|
+
}
|
|
83
|
+
.text[data-markdown='true'] :global(h1),
|
|
84
|
+
.text[data-markdown='true'] :global(h2),
|
|
85
|
+
.text[data-markdown='true'] :global(h3),
|
|
86
|
+
.text[data-markdown='true'] :global(h4),
|
|
87
|
+
.text[data-markdown='true'] :global(h5),
|
|
88
|
+
.text[data-markdown='true'] :global(h6) {
|
|
89
|
+
margin: 1.25rem 0 0.6rem;
|
|
90
|
+
font-family: 'Noto Serif KR', serif;
|
|
91
|
+
color: #E3D8D8;
|
|
92
|
+
line-height: 1.2;
|
|
93
|
+
}
|
|
94
|
+
.text[data-markdown='true'] :global(h1:first-child),
|
|
95
|
+
.text[data-markdown='true'] :global(h2:first-child),
|
|
96
|
+
.text[data-markdown='true'] :global(h3:first-child),
|
|
97
|
+
.text[data-markdown='true'] :global(h4:first-child),
|
|
98
|
+
.text[data-markdown='true'] :global(h5:first-child),
|
|
99
|
+
.text[data-markdown='true'] :global(h6:first-child),
|
|
100
|
+
.text[data-markdown='true'] :global(p:first-child),
|
|
101
|
+
.text[data-markdown='true'] :global(ul:first-child),
|
|
102
|
+
.text[data-markdown='true'] :global(ol:first-child),
|
|
103
|
+
.text[data-markdown='true'] :global(blockquote:first-child),
|
|
104
|
+
.text[data-markdown='true'] :global(pre:first-child),
|
|
105
|
+
.text[data-markdown='true'] :global(table:first-child) {
|
|
106
|
+
margin-top: 0;
|
|
107
|
+
}
|
|
108
|
+
.text[data-markdown='true'] :global(*:last-child) {
|
|
109
|
+
margin-bottom: 0;
|
|
110
|
+
}
|
|
111
|
+
.text[data-markdown='true'] :global(ul),
|
|
112
|
+
.text[data-markdown='true'] :global(ol) {
|
|
113
|
+
padding-left: 1.4rem;
|
|
114
|
+
}
|
|
115
|
+
.text[data-markdown='true'] :global(li + li) {
|
|
116
|
+
margin-top: 0.2rem;
|
|
117
|
+
}
|
|
118
|
+
.text[data-markdown='true'] :global(blockquote) {
|
|
119
|
+
border-left: 2px solid #3E353A;
|
|
120
|
+
padding-left: 0.9rem;
|
|
121
|
+
color: #C7BDC1;
|
|
122
|
+
}
|
|
123
|
+
.text[data-markdown='true'] :global(a) {
|
|
124
|
+
color: #FFEFF6;
|
|
125
|
+
text-decoration: underline;
|
|
126
|
+
text-decoration-thickness: 1px;
|
|
127
|
+
text-underline-offset: 0.14em;
|
|
128
|
+
}
|
|
129
|
+
.text[data-markdown='true'] :global(code) {
|
|
130
|
+
font-family: 'JetBrains Mono', monospace;
|
|
131
|
+
font-size: 0.92em;
|
|
132
|
+
background: rgba(255, 255, 255, 0.06);
|
|
133
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
134
|
+
border-radius: 0.45rem;
|
|
135
|
+
padding: 0.12rem 0.32rem;
|
|
136
|
+
color: #E3D8D8;
|
|
137
|
+
}
|
|
138
|
+
.text[data-markdown='true'] :global(pre) {
|
|
139
|
+
overflow-x: auto;
|
|
140
|
+
padding: 0.85rem 1rem;
|
|
141
|
+
background: rgba(11, 7, 13, 0.8);
|
|
142
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
143
|
+
border-radius: 0.85rem;
|
|
144
|
+
}
|
|
145
|
+
.text[data-markdown='true'] :global(pre code) {
|
|
146
|
+
display: block;
|
|
147
|
+
padding: 0;
|
|
148
|
+
border: none;
|
|
149
|
+
background: transparent;
|
|
150
|
+
white-space: pre;
|
|
151
|
+
}
|
|
152
|
+
.text[data-markdown='true'] :global(table) {
|
|
153
|
+
width: 100%;
|
|
154
|
+
border-collapse: collapse;
|
|
155
|
+
}
|
|
156
|
+
.text[data-markdown='true'] :global(th),
|
|
157
|
+
.text[data-markdown='true'] :global(td) {
|
|
158
|
+
text-align: left;
|
|
159
|
+
padding: 0.45rem 0.6rem;
|
|
160
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
161
|
+
}
|
|
162
|
+
.text[data-markdown='true'] :global(hr) {
|
|
163
|
+
border: none;
|
|
164
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
165
|
+
}
|
|
31
166
|
/* Title variant */
|
|
32
167
|
.text[data-variant='title'] {
|
|
33
168
|
font-family: 'Noto Serif KR', serif;
|
|
@@ -40,7 +175,7 @@
|
|
|
40
175
|
font-family: 'Satoshi', sans-serif;
|
|
41
176
|
font-weight: calc(700 + var(--text-weight-modifier));
|
|
42
177
|
font-size: calc(18px + var(--text-modifier));
|
|
43
|
-
color: #
|
|
178
|
+
color: #9e9599;
|
|
44
179
|
}
|
|
45
180
|
/* Button variant */
|
|
46
181
|
.text[data-variant='button'] {
|
|
@@ -55,4 +190,27 @@
|
|
|
55
190
|
font-size: calc(14px + var(--text-modifier));
|
|
56
191
|
color: #E3D8D8;
|
|
57
192
|
}
|
|
193
|
+
.text[data-variant='title'][data-markdown='true'] :global(h1) {
|
|
194
|
+
font-size: calc(30px + var(--text-modifier));
|
|
195
|
+
font-weight: calc(900 + var(--text-weight-modifier));
|
|
196
|
+
}
|
|
197
|
+
.text[data-variant='title'][data-markdown='true'] :global(h2) {
|
|
198
|
+
font-size: calc(24px + var(--text-modifier));
|
|
199
|
+
font-weight: calc(900 + var(--text-weight-modifier));
|
|
200
|
+
}
|
|
201
|
+
.text[data-variant='content'][data-markdown='true'] :global(h1) {
|
|
202
|
+
font-size: calc(24px + var(--text-modifier));
|
|
203
|
+
font-weight: calc(850 + var(--text-weight-modifier));
|
|
204
|
+
}
|
|
205
|
+
.text[data-variant='content'][data-markdown='true'] :global(h2) {
|
|
206
|
+
font-size: calc(21px + var(--text-modifier));
|
|
207
|
+
font-weight: calc(800 + var(--text-weight-modifier));
|
|
208
|
+
}
|
|
209
|
+
.text[data-variant='content'][data-markdown='true'] :global(h3),
|
|
210
|
+
.text[data-variant='button'][data-markdown='true'] :global(h1),
|
|
211
|
+
.text[data-variant='button'][data-markdown='true'] :global(h2),
|
|
212
|
+
.text[data-variant='button'][data-markdown='true'] :global(h3) {
|
|
213
|
+
font-size: calc(18px + var(--text-modifier));
|
|
214
|
+
font-weight: calc(700 + var(--text-weight-modifier));
|
|
215
|
+
}
|
|
58
216
|
</style>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export default BaseText;
|
|
2
2
|
type BaseText = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
|
|
3
|
+
as?: string | null | undefined;
|
|
4
|
+
content?: string | null | undefined;
|
|
3
5
|
variant?: "button" | "code" | "title" | "content" | undefined;
|
|
4
6
|
textModifier?: string | undefined;
|
|
5
7
|
textWeightModifier?: string | undefined;
|
|
8
|
+
markdown?: boolean | undefined;
|
|
6
9
|
}, {
|
|
7
10
|
default: {};
|
|
8
11
|
}>, {
|
|
@@ -13,9 +16,12 @@ type BaseText = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
|
|
|
13
16
|
$$bindings?: string | undefined;
|
|
14
17
|
};
|
|
15
18
|
declare const BaseText: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
19
|
+
as?: string | null | undefined;
|
|
20
|
+
content?: string | null | undefined;
|
|
16
21
|
variant?: "button" | "code" | "title" | "content" | undefined;
|
|
17
22
|
textModifier?: string | undefined;
|
|
18
23
|
textWeightModifier?: string | undefined;
|
|
24
|
+
markdown?: boolean | undefined;
|
|
19
25
|
}, {
|
|
20
26
|
default: {};
|
|
21
27
|
}>, {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import sanitizeHtml from 'sanitize-html';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
|
|
4
|
+
marked.setOptions({
|
|
5
|
+
gfm: true,
|
|
6
|
+
breaks: true,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const ALLOWED_TAGS = [
|
|
10
|
+
'a',
|
|
11
|
+
'blockquote',
|
|
12
|
+
'br',
|
|
13
|
+
'code',
|
|
14
|
+
'del',
|
|
15
|
+
'em',
|
|
16
|
+
'h1',
|
|
17
|
+
'h2',
|
|
18
|
+
'h3',
|
|
19
|
+
'h4',
|
|
20
|
+
'h5',
|
|
21
|
+
'h6',
|
|
22
|
+
'hr',
|
|
23
|
+
'li',
|
|
24
|
+
'ol',
|
|
25
|
+
'p',
|
|
26
|
+
'pre',
|
|
27
|
+
'strong',
|
|
28
|
+
'table',
|
|
29
|
+
'tbody',
|
|
30
|
+
'td',
|
|
31
|
+
'th',
|
|
32
|
+
'thead',
|
|
33
|
+
'tr',
|
|
34
|
+
'ul',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const ALLOWED_ATTRIBUTES = {
|
|
38
|
+
a: ['href', 'title', 'target', 'rel'],
|
|
39
|
+
code: ['class'],
|
|
40
|
+
td: ['align'],
|
|
41
|
+
th: ['align'],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} source
|
|
46
|
+
*/
|
|
47
|
+
export function renderMarkdown(source = '') {
|
|
48
|
+
const unsafeHtml = marked.parse(String(source));
|
|
49
|
+
|
|
50
|
+
return sanitizeHtml(unsafeHtml, {
|
|
51
|
+
allowedTags: ALLOWED_TAGS,
|
|
52
|
+
allowedAttributes: ALLOWED_ATTRIBUTES,
|
|
53
|
+
allowedSchemes: ['http', 'https', 'mailto'],
|
|
54
|
+
transformTags: {
|
|
55
|
+
a: sanitizeHtml.simpleTransform(
|
|
56
|
+
'a',
|
|
57
|
+
{
|
|
58
|
+
target: '_blank',
|
|
59
|
+
rel: 'noreferrer noopener',
|
|
60
|
+
},
|
|
61
|
+
true,
|
|
62
|
+
),
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coyalabs/bts-style",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.13",
|
|
4
4
|
"description": "BTS Theme Svelte component templates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -48,5 +48,9 @@
|
|
|
48
48
|
"type": "git",
|
|
49
49
|
"url": "https://github.com/sparklescoya/svelte-bts-theme.git",
|
|
50
50
|
"directory": "@bts-theme/svelte-templates"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"marked": "^17.0.4",
|
|
54
|
+
"sanitize-html": "^2.17.1"
|
|
51
55
|
}
|
|
52
56
|
}
|