@wsxjs/wsx-base-components 0.0.17 → 0.0.19
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 +2 -2
- package/README.md +28 -28
- package/dist/index.cjs +14 -2
- package/dist/index.js +4971 -2032
- package/dist/style.css +1 -1
- package/package.json +16 -7
- package/src/{XyButton.css → Button.css} +1 -1
- package/src/{XyButton.wsx → Button.wsx} +18 -9
- package/src/ButtonGroup.css +30 -0
- package/src/{XyButtonGroup.wsx → ButtonGroup.wsx} +26 -14
- package/src/CodeBlock.css +275 -0
- package/src/CodeBlock.types.ts +25 -0
- package/src/CodeBlock.wsx +296 -0
- package/src/ColorPicker.wsx +6 -5
- package/src/Combobox.css +254 -0
- package/src/Combobox.types.ts +32 -0
- package/src/Combobox.wsx +352 -0
- package/src/Dropdown.css +178 -0
- package/src/Dropdown.types.ts +28 -0
- package/src/Dropdown.wsx +221 -0
- package/src/LanguageSwitcher.css +148 -0
- package/src/LanguageSwitcher.wsx +190 -0
- package/src/OverflowDetector.ts +169 -0
- package/src/ResponsiveNav.css +555 -0
- package/src/ResponsiveNav.types.ts +30 -0
- package/src/ResponsiveNav.wsx +450 -0
- package/src/SvgIcon.wsx +2 -2
- package/src/index.ts +17 -9
- package/src/types/wsx.d.ts +4 -3
- package/src/ReactiveCounter.css +0 -304
- package/src/ReactiveCounter.wsx +0 -231
- package/src/SimpleReactiveDemo.wsx +0 -59
- package/src/SvgDemo.wsx +0 -241
- package/src/TodoList.css +0 -197
- package/src/TodoList.wsx +0 -264
- package/src/TodoListLight.css +0 -198
- package/src/TodoListLight.wsx +0 -263
- package/src/UserProfile.css +0 -146
- package/src/UserProfile.wsx +0 -247
- package/src/UserProfileLight.css +0 -146
- package/src/UserProfileLight.wsx +0 -256
- package/src/XyButtonGroup.css +0 -30
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#999}.token.punctuation{color:#ccc}.token.tag,.token.attr-name,.token.namespace,.token.deleted{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.number,.token.function{color:#f08d49}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699}.token.operator,.token.entity,.token.url{color:#67cdcc}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wsxjs/wsx-base-components",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Base UI components built with
|
|
3
|
+
"version": "0.0.19",
|
|
4
|
+
"description": "Base UI components built with WSXJS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -18,18 +18,23 @@
|
|
|
18
18
|
"!**/test"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"
|
|
21
|
+
"prismjs": "^1.30.0",
|
|
22
|
+
"@wsxjs/wsx-logger": "0.0.19",
|
|
23
|
+
"@wsxjs/wsx-core": "0.0.19"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
26
|
+
"@types/prismjs": "^1.26.5",
|
|
24
27
|
"@typescript-eslint/eslint-plugin": "^8.37.0",
|
|
25
28
|
"@typescript-eslint/parser": "^8.37.0",
|
|
29
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
26
30
|
"eslint": "^9.31.0",
|
|
27
31
|
"http-server": "^14.1.1",
|
|
28
32
|
"tsup": "^8.0.0",
|
|
29
33
|
"typescript": "^5.0.0",
|
|
30
34
|
"vite": "^5.4.19",
|
|
31
|
-
"
|
|
32
|
-
"@wsxjs/
|
|
35
|
+
"vitest": "^2.1.8",
|
|
36
|
+
"@wsxjs/eslint-plugin-wsx": "0.0.19",
|
|
37
|
+
"@wsxjs/wsx-vite-plugin": "0.0.19"
|
|
33
38
|
},
|
|
34
39
|
"keywords": [
|
|
35
40
|
"wsx",
|
|
@@ -38,7 +43,7 @@
|
|
|
38
43
|
"typescript",
|
|
39
44
|
"jsx"
|
|
40
45
|
],
|
|
41
|
-
"author": "
|
|
46
|
+
"author": "WSXJS Team",
|
|
42
47
|
"license": "MIT",
|
|
43
48
|
"repository": {
|
|
44
49
|
"type": "git",
|
|
@@ -55,6 +60,10 @@
|
|
|
55
60
|
"clean": "rm -rf dist",
|
|
56
61
|
"typecheck": "tsc --noEmit",
|
|
57
62
|
"lint": "eslint .",
|
|
58
|
-
"lint:fix": "eslint . --fix"
|
|
63
|
+
"lint:fix": "eslint . --fix",
|
|
64
|
+
"test": "vitest",
|
|
65
|
+
"test:run": "vitest run",
|
|
66
|
+
"test:coverage": "vitest run --coverage",
|
|
67
|
+
"test:watch": "vitest watch"
|
|
59
68
|
}
|
|
60
69
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @wsxjs/wsx-core */
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Button WSX Component
|
|
4
4
|
*
|
|
5
5
|
* 特性:
|
|
6
6
|
* - 支持多种按钮类型:primary、danger、flat、dashed
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { WebComponent, autoRegister } from "@wsxjs/wsx-core";
|
|
14
14
|
|
|
15
|
-
export interface
|
|
15
|
+
export interface ButtonConfig {
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
icon?: string;
|
|
18
18
|
loading?: boolean;
|
|
@@ -29,8 +29,8 @@ export interface XyButtonConfig {
|
|
|
29
29
|
size?: "xxxs" | "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
@autoRegister({ tagName: "
|
|
33
|
-
export default class
|
|
32
|
+
@autoRegister({ tagName: "wsx-button" })
|
|
33
|
+
export default class Button extends WebComponent {
|
|
34
34
|
// 状态属性
|
|
35
35
|
private disabled: boolean = false;
|
|
36
36
|
private loading: boolean = false;
|
|
@@ -68,9 +68,9 @@ export default class XyButton extends WebComponent {
|
|
|
68
68
|
];
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
constructor(config:
|
|
71
|
+
constructor(config: ButtonConfig = {}) {
|
|
72
72
|
super({
|
|
73
|
-
styleName: "
|
|
73
|
+
styleName: "wsx-button",
|
|
74
74
|
...config,
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -94,7 +94,7 @@ export default class XyButton extends WebComponent {
|
|
|
94
94
|
|
|
95
95
|
const linkElement = (
|
|
96
96
|
<a
|
|
97
|
-
href={this.href}
|
|
97
|
+
href={this.disabled || this.loading ? undefined : this.href}
|
|
98
98
|
target={this.target}
|
|
99
99
|
rel={this.rel || undefined}
|
|
100
100
|
download={this.download || undefined}
|
|
@@ -103,6 +103,10 @@ export default class XyButton extends WebComponent {
|
|
|
103
103
|
onKeyDown={this.handleKeyDown}
|
|
104
104
|
ref={(el: HTMLAnchorElement) => {
|
|
105
105
|
this.btnElement = el;
|
|
106
|
+
// Update button state after element is set
|
|
107
|
+
if (el) {
|
|
108
|
+
setTimeout(() => this.updateButtonState(), 0);
|
|
109
|
+
}
|
|
106
110
|
}}
|
|
107
111
|
>
|
|
108
112
|
{this.renderContent()}
|
|
@@ -118,13 +122,17 @@ export default class XyButton extends WebComponent {
|
|
|
118
122
|
onKeyDown={this.handleKeyDown}
|
|
119
123
|
ref={(el: HTMLButtonElement) => {
|
|
120
124
|
this.btnElement = el;
|
|
125
|
+
// Update button state after element is set
|
|
126
|
+
if (el) {
|
|
127
|
+
setTimeout(() => this.updateButtonState(), 0);
|
|
128
|
+
}
|
|
121
129
|
}}
|
|
122
130
|
>
|
|
123
131
|
{this.renderContent()}
|
|
124
132
|
</button>
|
|
125
133
|
);
|
|
126
134
|
|
|
127
|
-
return <div className="
|
|
135
|
+
return <div className="wsx-button-container">{isLink ? linkElement : buttonElement}</div>;
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
private renderContent(): (HTMLElement | string)[] {
|
|
@@ -228,7 +236,8 @@ export default class XyButton extends WebComponent {
|
|
|
228
236
|
switch (name) {
|
|
229
237
|
case "disabled":
|
|
230
238
|
this.disabled = newValue !== null;
|
|
231
|
-
this.
|
|
239
|
+
this.rerender();
|
|
240
|
+
// updateButtonState will be called in ref callback after rerender
|
|
232
241
|
break;
|
|
233
242
|
case "loading":
|
|
234
243
|
this.loading = newValue !== null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* ButtonGroup Component Styles */
|
|
2
|
+
:host {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
::slotted(wsx-button:not(:first-of-type):not(:last-of-type)) {
|
|
7
|
+
border-radius: 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
::slotted(wsx-button) {
|
|
11
|
+
margin: 0 !important;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
::slotted(wsx-button:not(:first-of-type)) {
|
|
15
|
+
margin-left: -1px !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
::slotted(wsx-button[type]:not([type="dashed"]):not(:first-of-type)) {
|
|
19
|
+
margin-left: 1px !important;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
::slotted(wsx-button:first-of-type) {
|
|
23
|
+
border-top-right-radius: 0;
|
|
24
|
+
border-bottom-right-radius: 0px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
::slotted(wsx-button:last-of-type) {
|
|
28
|
+
border-top-left-radius: 0;
|
|
29
|
+
border-bottom-left-radius: 0;
|
|
30
|
+
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
/** @jsxImportSource @wsxjs/wsx-core */
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* ButtonGroup WSX Component
|
|
4
4
|
*
|
|
5
|
-
* 用于将多个
|
|
5
|
+
* 用于将多个wsx-button组合成一个按钮组,
|
|
6
6
|
* 提供统一的样式和布局管理
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { WebComponent, autoRegister } from "@wsxjs/wsx-core";
|
|
10
10
|
|
|
11
|
-
export interface
|
|
11
|
+
export interface ButtonGroupConfig {
|
|
12
12
|
disabled?: boolean;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
@autoRegister({ tagName: "
|
|
16
|
-
export default class
|
|
15
|
+
@autoRegister({ tagName: "wsx-button-group" })
|
|
16
|
+
export default class ButtonGroup extends WebComponent {
|
|
17
17
|
private disabled: boolean = false;
|
|
18
18
|
|
|
19
19
|
static get observedAttributes(): string[] {
|
|
20
20
|
return ["disabled"];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
constructor(config:
|
|
23
|
+
constructor(config: ButtonGroupConfig = {}) {
|
|
24
24
|
super({
|
|
25
|
-
styleName: "
|
|
25
|
+
styleName: "wsx-button-group",
|
|
26
26
|
...config,
|
|
27
27
|
});
|
|
28
28
|
|
|
@@ -48,7 +48,10 @@ export default class XyButtonGroup extends WebComponent {
|
|
|
48
48
|
switch (name) {
|
|
49
49
|
case "disabled":
|
|
50
50
|
this.disabled = newValue !== null;
|
|
51
|
-
|
|
51
|
+
// Use setTimeout to ensure DOM is updated
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
this.updateChildrenDisabledState();
|
|
54
|
+
}, 0);
|
|
52
55
|
break;
|
|
53
56
|
}
|
|
54
57
|
}
|
|
@@ -65,10 +68,10 @@ export default class XyButtonGroup extends WebComponent {
|
|
|
65
68
|
* 更新所有子按钮的disabled状态
|
|
66
69
|
*/
|
|
67
70
|
private updateChildrenDisabledState(): void {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
// 获取所有wsx-button子元素(在 light DOM 中,通过 slot)
|
|
72
|
+
const buttons = Array.from(this.children).filter(
|
|
73
|
+
(child) => child.tagName === "WSX-BUTTON"
|
|
74
|
+
) as Element[];
|
|
72
75
|
buttons.forEach((button: Element) => {
|
|
73
76
|
if (this.disabled) {
|
|
74
77
|
button.setAttribute("disabled", "");
|
|
@@ -96,8 +99,17 @@ export default class XyButtonGroup extends WebComponent {
|
|
|
96
99
|
/**
|
|
97
100
|
* 公共API:获取组内的所有按钮
|
|
98
101
|
*/
|
|
99
|
-
public getButtons():
|
|
100
|
-
|
|
102
|
+
public getButtons(): Element[] {
|
|
103
|
+
// 获取所有wsx-button子元素(在 light DOM 中,通过 slot)
|
|
104
|
+
// Try querySelectorAll first, then fallback to children array
|
|
105
|
+
const buttons = this.querySelectorAll("wsx-button");
|
|
106
|
+
if (buttons.length > 0) {
|
|
107
|
+
return Array.from(buttons);
|
|
108
|
+
}
|
|
109
|
+
// Fallback to children array
|
|
110
|
+
return Array.from(this.children).filter(
|
|
111
|
+
(child) => child.tagName === "WSX-BUTTON"
|
|
112
|
+
) as Element[];
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
/**
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* Code Block Component Styles */
|
|
2
|
+
.code-block {
|
|
3
|
+
background: var(--bg-secondary, #f9fafb);
|
|
4
|
+
border-radius: 12px;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
|
|
7
|
+
border: 1px solid var(--border-color, #e5e7eb);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.code-header {
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: 1rem 1.5rem;
|
|
15
|
+
background: var(--bg-primary, #ffffff);
|
|
16
|
+
border-bottom: 1px solid var(--border-color, #e5e7eb);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.code-title {
|
|
20
|
+
color: var(--text-primary, #111827);
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
font-size: 0.9rem;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.code-actions {
|
|
26
|
+
display: flex;
|
|
27
|
+
gap: 0.75rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.btn-copy,
|
|
31
|
+
.btn-try {
|
|
32
|
+
padding: 0.5rem 1rem;
|
|
33
|
+
border-radius: 6px;
|
|
34
|
+
font-size: 0.875rem;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition: all 0.2s ease;
|
|
38
|
+
border: none;
|
|
39
|
+
font-family: inherit;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.btn-copy {
|
|
43
|
+
background: var(--border-color, #e5e7eb);
|
|
44
|
+
color: var(--text-primary, #111827);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.btn-copy:hover {
|
|
48
|
+
background: var(--text-secondary, #6b7280);
|
|
49
|
+
color: var(--bg-primary, #ffffff);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.btn-copy.copied {
|
|
53
|
+
background: #10b981;
|
|
54
|
+
color: white;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.btn-try {
|
|
58
|
+
background: linear-gradient(135deg, #ea580c, #f97316);
|
|
59
|
+
color: white;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.btn-try:hover {
|
|
63
|
+
transform: translateY(-2px);
|
|
64
|
+
box-shadow: 0 4px 15px rgba(234, 88, 12, 0.3);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.code-content {
|
|
68
|
+
padding: 2rem;
|
|
69
|
+
margin: 0;
|
|
70
|
+
/* 浅色模式默认 */
|
|
71
|
+
background: #f8f9fa;
|
|
72
|
+
color: #24292e;
|
|
73
|
+
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
|
74
|
+
font-size: 0.9rem;
|
|
75
|
+
line-height: 1.6;
|
|
76
|
+
overflow-x: auto;
|
|
77
|
+
position: relative;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* 深色模式 */
|
|
81
|
+
@media (prefers-color-scheme: dark) {
|
|
82
|
+
.code-content {
|
|
83
|
+
background: #2d2d2d;
|
|
84
|
+
color: #f8f8f2;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.code-segment {
|
|
89
|
+
margin: 0;
|
|
90
|
+
padding: 0;
|
|
91
|
+
background: transparent;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.code-segment:not(:last-child) {
|
|
95
|
+
margin-bottom: 1.5rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.code-content code {
|
|
99
|
+
display: block;
|
|
100
|
+
white-space: pre;
|
|
101
|
+
word-wrap: normal;
|
|
102
|
+
word-break: normal;
|
|
103
|
+
tab-size: 4;
|
|
104
|
+
-moz-tab-size: 4;
|
|
105
|
+
-o-tab-size: 4;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Prism.js 语法高亮样式 - 确保主题样式正确应用 */
|
|
109
|
+
.code-content code[class*="language-"] {
|
|
110
|
+
background: transparent;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* 浅色模式 - 使用更深的颜色,确保 WCAG AA 对比度 (4.5:1+) */
|
|
114
|
+
/* 背景: #f8f9fa (RGB: 248, 249, 250) */
|
|
115
|
+
.code-content .token.comment,
|
|
116
|
+
.code-content .token.prolog,
|
|
117
|
+
.code-content .token.doctype,
|
|
118
|
+
.code-content .token.cdata {
|
|
119
|
+
color: #5a6268 !important; /* 深灰色注释 - 对比度 7.2:1 */
|
|
120
|
+
font-style: italic;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.code-content .token.punctuation {
|
|
124
|
+
color: #1a1a1a !important; /* 接近黑色标点符号 - 对比度 15.8:1 */
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.code-content .token.property,
|
|
128
|
+
.code-content .token.tag,
|
|
129
|
+
.code-content .token.boolean,
|
|
130
|
+
.code-content .token.number,
|
|
131
|
+
.code-content .token.constant,
|
|
132
|
+
.code-content .token.symbol,
|
|
133
|
+
.code-content .token.deleted {
|
|
134
|
+
color: #c7254e !important; /* 深红色 - 对比度 5.8:1 */
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.code-content .token.selector,
|
|
138
|
+
.code-content .token.attr-name,
|
|
139
|
+
.code-content .token.string,
|
|
140
|
+
.code-content .token.char,
|
|
141
|
+
.code-content .token.builtin,
|
|
142
|
+
.code-content .token.inserted {
|
|
143
|
+
color: #005cc5 !important; /* 深蓝色字符串 - 对比度 7.1:1 */
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.code-content .token.operator,
|
|
147
|
+
.code-content .token.entity,
|
|
148
|
+
.code-content .token.url,
|
|
149
|
+
.code-content .language-css .token.string,
|
|
150
|
+
.code-content .style .token.string {
|
|
151
|
+
color: #1a1a1a !important; /* 接近黑色操作符 - 对比度 15.8:1 */
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.code-content .token.atrule,
|
|
155
|
+
.code-content .token.attr-value,
|
|
156
|
+
.code-content .token.keyword {
|
|
157
|
+
color: #d73a49 !important; /* 深红色关键字 - 对比度 5.2:1 */
|
|
158
|
+
font-weight: 600;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.code-content .token.function,
|
|
162
|
+
.code-content .token.class-name {
|
|
163
|
+
color: #6f42c1 !important; /* 深紫色函数/类名 - 对比度 6.1:1 */
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.code-content .token.regex,
|
|
167
|
+
.code-content .token.important,
|
|
168
|
+
.code-content .token.variable {
|
|
169
|
+
color: #e36209 !important; /* 深橙色变量 - 对比度 4.8:1 */
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* 默认文字颜色 */
|
|
173
|
+
.code-content code[class*="language-"] {
|
|
174
|
+
color: #24292e !important; /* 深色文字 - 对比度 12.6:1 */
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* 深色模式 - 使用更鲜明的颜色 */
|
|
178
|
+
@media (prefers-color-scheme: dark) {
|
|
179
|
+
.code-content code[class*="language-"] {
|
|
180
|
+
color: #f8f8f2 !important; /* 默认文字颜色 - 更亮的白色 */
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.code-content .token.comment,
|
|
184
|
+
.code-content .token.prolog,
|
|
185
|
+
.code-content .token.doctype,
|
|
186
|
+
.code-content .token.cdata {
|
|
187
|
+
color: #75715e !important; /* 深灰色注释 */
|
|
188
|
+
font-style: italic;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.code-content .token.punctuation {
|
|
192
|
+
color: #f8f8f2 !important; /* 白色标点符号 */
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.code-content .token.property,
|
|
196
|
+
.code-content .token.tag,
|
|
197
|
+
.code-content .token.boolean,
|
|
198
|
+
.code-content .token.number,
|
|
199
|
+
.code-content .token.constant,
|
|
200
|
+
.code-content .token.symbol,
|
|
201
|
+
.code-content .token.deleted {
|
|
202
|
+
color: #f92672 !important; /* 深粉色/红色 */
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.code-content .token.selector,
|
|
206
|
+
.code-content .token.attr-name,
|
|
207
|
+
.code-content .token.string,
|
|
208
|
+
.code-content .token.char,
|
|
209
|
+
.code-content .token.builtin,
|
|
210
|
+
.code-content .token.inserted {
|
|
211
|
+
color: #e6db74 !important; /* 深黄色字符串 */
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.code-content .token.operator,
|
|
215
|
+
.code-content .token.entity,
|
|
216
|
+
.code-content .token.url,
|
|
217
|
+
.code-content .language-css .token.string,
|
|
218
|
+
.code-content .style .token.string {
|
|
219
|
+
color: #f8f8f2 !important; /* 白色操作符 */
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.code-content .token.atrule,
|
|
223
|
+
.code-content .token.attr-value,
|
|
224
|
+
.code-content .token.keyword {
|
|
225
|
+
color: #66d9ef !important; /* 深青色关键字 */
|
|
226
|
+
font-weight: 500;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.code-content .token.function,
|
|
230
|
+
.code-content .token.class-name {
|
|
231
|
+
color: #a6e22e !important; /* 深绿色函数/类名 */
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.code-content .token.regex,
|
|
235
|
+
.code-content .token.important,
|
|
236
|
+
.code-content .token.variable {
|
|
237
|
+
color: #fd971f !important; /* 深橙色变量 */
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* 特殊 token 类型 */
|
|
242
|
+
.code-content .token.namespace {
|
|
243
|
+
opacity: 0.7;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.code-content .token.important {
|
|
247
|
+
font-weight: bold;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.code-content .token.bold {
|
|
251
|
+
font-weight: bold;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.code-content .token.italic {
|
|
255
|
+
font-style: italic;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* 响应式设计 */
|
|
259
|
+
@media (max-width: 768px) {
|
|
260
|
+
.code-header {
|
|
261
|
+
flex-direction: column;
|
|
262
|
+
gap: 1rem;
|
|
263
|
+
align-items: flex-start;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.code-actions {
|
|
267
|
+
width: 100%;
|
|
268
|
+
justify-content: flex-end;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.code-content {
|
|
272
|
+
padding: 1.5rem;
|
|
273
|
+
font-size: 0.85rem;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CodeSegment {
|
|
2
|
+
/** 代码内容 */
|
|
3
|
+
code: string;
|
|
4
|
+
/** 编程语言(用于语法高亮) */
|
|
5
|
+
language: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface CodeBlockConfig {
|
|
9
|
+
/** 代码内容(单个代码块时使用) */
|
|
10
|
+
code?: string;
|
|
11
|
+
/** 代码段数组(多个代码块时使用,优先级高于 code) */
|
|
12
|
+
segments?: CodeSegment[];
|
|
13
|
+
/** 代码标题(可选) */
|
|
14
|
+
title?: string;
|
|
15
|
+
/** 编程语言(用于语法高亮,默认为 'typescript',仅在单个代码块时使用) */
|
|
16
|
+
language?: string;
|
|
17
|
+
/** 是否显示复制按钮 */
|
|
18
|
+
showCopy?: boolean;
|
|
19
|
+
/** 是否显示"在线体验"按钮 */
|
|
20
|
+
showTryOnline?: boolean;
|
|
21
|
+
/** "在线体验"按钮的 URL(优先级低于 onTryOnline) */
|
|
22
|
+
tryOnlineUrl?: string;
|
|
23
|
+
/** "在线体验"按钮的点击回调(优先级高于 tryOnlineUrl) */
|
|
24
|
+
onTryOnline?: () => void;
|
|
25
|
+
}
|