@21st-sdk/react 0.1.2 → 0.1.4
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 +1 -1
- package/README.md +25 -25
- package/dist/index.cjs +17 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -36
- package/dist/index.d.ts +48 -36
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/docs/01-overview.md +7 -7
- package/docs/02-getting-started.md +15 -15
- package/docs/03-defining-agents.md +3 -3
- package/docs/04-react-ui.md +19 -19
- package/docs/05-nextjs.md +20 -20
- package/docs/06-node-sdk.md +10 -10
- package/docs/07-cli.md +9 -9
- package/docs/08-custom-tools.md +4 -4
- package/package.json +6 -5
- package/src/an-agent-chat.tsx +6 -3
- package/src/components/input/context-items.tsx +2 -2
- package/src/components/input/model-selector.tsx +3 -3
- package/src/components/input-bar.tsx +2 -2
- package/src/create-an-chat.ts +7 -4
- package/src/index.ts +11 -5
- package/src/models.ts +11 -6
- package/src/theme-config.ts +9 -6
- package/src/theme.ts +2 -2
- package/src/tools/tool-router.ts +3 -3
- package/src/types.ts +23 -15
- package/styles/index.css +161 -0
package/src/create-an-chat.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Chat } from "@ai-sdk/react"
|
|
2
2
|
import { DefaultChatTransport, type UIMessage } from "ai"
|
|
3
|
-
import type {
|
|
3
|
+
import type { CreateAgentChatOptions } from "./types"
|
|
4
4
|
|
|
5
5
|
const DEFAULT_API_URL = "https://relay.an.dev"
|
|
6
6
|
|
|
@@ -29,8 +29,8 @@ function createTokenFetcher(tokenUrl: string, agent: string) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/** Create an AI SDK Chat instance pointed at the
|
|
33
|
-
export function
|
|
32
|
+
/** Create an AI SDK Chat instance pointed at the relay API */
|
|
33
|
+
export function createAgentChat(options: CreateAgentChatOptions): Chat<UIMessage> {
|
|
34
34
|
const {
|
|
35
35
|
agent,
|
|
36
36
|
tokenUrl,
|
|
@@ -44,7 +44,7 @@ export function createAnChat(options: CreateAnChatOptions): Chat<UIMessage> {
|
|
|
44
44
|
|
|
45
45
|
const getToken = getTokenFn || (tokenUrl ? createTokenFetcher(tokenUrl, agent) : null)
|
|
46
46
|
if (!getToken) {
|
|
47
|
-
throw new Error("
|
|
47
|
+
throw new Error("createAgentChat: provide either tokenUrl or getToken")
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return new Chat({
|
|
@@ -64,3 +64,6 @@ export function createAnChat(options: CreateAnChatOptions): Chat<UIMessage> {
|
|
|
64
64
|
onError,
|
|
65
65
|
})
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
// Legacy factory alias kept for compatibility.
|
|
69
|
+
export const createAnChat = createAgentChat
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Main drop-in component
|
|
2
|
-
export { AnAgentChat } from "./an-agent-chat"
|
|
2
|
+
export { AgentChat, AnAgentChat } from "./an-agent-chat"
|
|
3
3
|
|
|
4
4
|
// Chat factory
|
|
5
|
-
export { createAnChat } from "./create-an-chat"
|
|
5
|
+
export { createAgentChat, createAnChat } from "./create-an-chat"
|
|
6
6
|
|
|
7
7
|
// Theme
|
|
8
8
|
export { applyTheme } from "./theme"
|
|
@@ -71,11 +71,17 @@ export { FileExtIcon } from "./icons/file-ext-icon"
|
|
|
71
71
|
export { PaperclipIcon } from "./icons/shared-icons"
|
|
72
72
|
|
|
73
73
|
// Models
|
|
74
|
-
export { AN_CLAUDE_MODELS, AN_DEFAULT_MODEL_ID } from "./models"
|
|
75
|
-
export type { AnClaudeModelId } from "./models"
|
|
74
|
+
export { CLAUDE_MODELS, DEFAULT_MODEL_ID, AN_CLAUDE_MODELS, AN_DEFAULT_MODEL_ID } from "./models"
|
|
75
|
+
export type { ClaudeModelId, AnClaudeModelId } from "./models"
|
|
76
76
|
|
|
77
77
|
// Types
|
|
78
78
|
export type {
|
|
79
|
+
ChatTheme,
|
|
80
|
+
ChatClassNames,
|
|
81
|
+
ChatSlots,
|
|
82
|
+
ModelOption,
|
|
83
|
+
CreateAgentChatOptions,
|
|
84
|
+
AgentChatProps,
|
|
79
85
|
AnTheme,
|
|
80
86
|
AnClassNames,
|
|
81
87
|
AnSlots,
|
|
@@ -84,7 +90,7 @@ export type {
|
|
|
84
90
|
AnAgentChatProps,
|
|
85
91
|
CustomToolRendererProps,
|
|
86
92
|
} from "./types"
|
|
87
|
-
export type { AnThemeConfig } from "./theme-config"
|
|
93
|
+
export type { ChatThemeConfig, AnThemeConfig } from "./theme-config"
|
|
88
94
|
export type { TimelineStep, StepState } from "./types/timeline"
|
|
89
95
|
export type { ToolSize } from "./types/tool-styles"
|
|
90
96
|
export type { SourceType } from "./icons/source-icons"
|
package/src/models.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ModelOption } from "./types"
|
|
2
2
|
|
|
3
|
-
/** Claude model IDs supported by the
|
|
4
|
-
export type
|
|
3
|
+
/** Claude model IDs supported by the relay */
|
|
4
|
+
export type ClaudeModelId = "opus" | "sonnet" | "haiku"
|
|
5
5
|
|
|
6
|
-
/** Pre-defined Claude models available through
|
|
7
|
-
export const
|
|
6
|
+
/** Pre-defined Claude models available through the relay */
|
|
7
|
+
export const CLAUDE_MODELS: ModelOption[] = [
|
|
8
8
|
{ id: "sonnet", name: "Sonnet", version: "4.6" },
|
|
9
9
|
{ id: "opus", name: "Opus", version: "4.6" },
|
|
10
10
|
{ id: "haiku", name: "Haiku", version: "4.5" },
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
/** Default model ID */
|
|
14
|
-
export const
|
|
14
|
+
export const DEFAULT_MODEL_ID: ClaudeModelId = "sonnet"
|
|
15
|
+
|
|
16
|
+
// Legacy model aliases kept for compatibility.
|
|
17
|
+
export type AnClaudeModelId = ClaudeModelId
|
|
18
|
+
export const AN_CLAUDE_MODELS = CLAUDE_MODELS
|
|
19
|
+
export const AN_DEFAULT_MODEL_ID = DEFAULT_MODEL_ID
|
package/src/theme-config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { createContext, useContext } from "react"
|
|
2
|
-
import type {
|
|
2
|
+
import type { ChatTheme } from "./types"
|
|
3
3
|
|
|
4
|
-
export interface
|
|
4
|
+
export interface ChatThemeConfig {
|
|
5
5
|
messageStyle: "bubble-right" | "full-width"
|
|
6
6
|
messageDensity: "relaxed" | "compact" | "dense"
|
|
7
7
|
inputStyle: "rounded" | "flat" | "bordered"
|
|
@@ -31,7 +31,10 @@ export interface AnThemeConfig {
|
|
|
31
31
|
attachmentPreviewStyle: "thumbnail" | "chip" | "hidden"
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
// Legacy type alias kept for compatibility.
|
|
35
|
+
export type AnThemeConfig = ChatThemeConfig
|
|
36
|
+
|
|
37
|
+
export const DEFAULT_THEME_CONFIG: ChatThemeConfig = {
|
|
35
38
|
messageStyle: "bubble-right",
|
|
36
39
|
messageDensity: "relaxed",
|
|
37
40
|
inputStyle: "bordered",
|
|
@@ -95,7 +98,7 @@ function readEnum<T extends string>(
|
|
|
95
98
|
return fallback
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
export function extractThemeConfig(theme?:
|
|
101
|
+
export function extractThemeConfig(theme?: ChatTheme): ChatThemeConfig {
|
|
99
102
|
if (!theme?.theme) return DEFAULT_THEME_CONFIG
|
|
100
103
|
const t = theme.theme
|
|
101
104
|
|
|
@@ -130,8 +133,8 @@ export function extractThemeConfig(theme?: AnTheme): AnThemeConfig {
|
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
|
|
133
|
-
export const ThemeConfigContext = createContext<
|
|
136
|
+
export const ThemeConfigContext = createContext<ChatThemeConfig>(DEFAULT_THEME_CONFIG)
|
|
134
137
|
|
|
135
|
-
export function useThemeConfig():
|
|
138
|
+
export function useThemeConfig(): ChatThemeConfig {
|
|
136
139
|
return useContext(ThemeConfigContext)
|
|
137
140
|
}
|
package/src/theme.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ChatTheme } from "./types"
|
|
2
2
|
import { contrastText } from "./utils/contrast"
|
|
3
3
|
|
|
4
4
|
export type ResolvedColorMode = "light" | "dark"
|
|
@@ -16,7 +16,7 @@ export function resolveColorMode(
|
|
|
16
16
|
/** Apply theme CSS variables from playground JSON to a DOM element */
|
|
17
17
|
export function applyTheme(
|
|
18
18
|
element: HTMLElement,
|
|
19
|
-
theme:
|
|
19
|
+
theme: ChatTheme,
|
|
20
20
|
colorMode: "light" | "dark" | "auto" = "auto",
|
|
21
21
|
) {
|
|
22
22
|
// Apply shared vars
|
package/src/tools/tool-router.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { TimelineStep, StepState } from "../types/timeline"
|
|
2
2
|
import type { ToolSize } from "../types/tool-styles"
|
|
3
|
-
import type {
|
|
3
|
+
import type { ChatThemeConfig } from "../theme-config"
|
|
4
4
|
import React from "react"
|
|
5
5
|
|
|
6
|
-
export function resolveToolSize(config:
|
|
6
|
+
export function resolveToolSize(config: ChatThemeConfig): ToolSize {
|
|
7
7
|
return config.toolCallStyle === "compact" ? "compact" : "normal"
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ function routeToolCall(
|
|
|
16
16
|
step: Extract<TimelineStep, { type: "tool-call" }>,
|
|
17
17
|
state: StepState,
|
|
18
18
|
onComplete: () => void,
|
|
19
|
-
config:
|
|
19
|
+
config: ChatThemeConfig,
|
|
20
20
|
actionIndex: number,
|
|
21
21
|
): React.ReactNode {
|
|
22
22
|
// Lazy imports to prevent circular dependency issues
|
package/src/types.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type React from "react"
|
|
2
2
|
import type { UIMessage, ChatStatus } from "ai"
|
|
3
3
|
|
|
4
|
-
/** Theme JSON generated by the
|
|
5
|
-
export interface
|
|
4
|
+
/** Theme JSON generated by the playground */
|
|
5
|
+
export interface ChatTheme {
|
|
6
6
|
theme: Record<string, string>
|
|
7
7
|
light: Record<string, string>
|
|
8
8
|
dark: Record<string, string>
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/** Per-element CSS class overrides */
|
|
12
|
-
export interface
|
|
12
|
+
export interface ChatClassNames {
|
|
13
13
|
root: string
|
|
14
14
|
messageList: string
|
|
15
15
|
userMessage: string
|
|
@@ -28,7 +28,7 @@ export interface AnClassNames {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/** Component slot overrides */
|
|
31
|
-
export interface
|
|
31
|
+
export interface ChatSlots {
|
|
32
32
|
InputBar: React.ComponentType<any>
|
|
33
33
|
UserMessage: React.ComponentType<any>
|
|
34
34
|
AssistantMessage: React.ComponentType<any>
|
|
@@ -36,8 +36,8 @@ export interface AnSlots {
|
|
|
36
36
|
MessageActions: React.ComponentType<any>
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/** Props for
|
|
40
|
-
export interface
|
|
39
|
+
/** Props for createAgentChat() */
|
|
40
|
+
export interface CreateAgentChatOptions {
|
|
41
41
|
agent: string
|
|
42
42
|
/** Provide either tokenUrl (simple) or getToken (full control) */
|
|
43
43
|
tokenUrl?: string
|
|
@@ -54,10 +54,10 @@ export interface CreateAnChatOptions {
|
|
|
54
54
|
*
|
|
55
55
|
* @example
|
|
56
56
|
* // Per-user sandbox
|
|
57
|
-
*
|
|
57
|
+
* createAgentChat({ agent: "my-agent", tokenUrl: "/api/an/token", sandboxId: `user-${userId}` })
|
|
58
58
|
*
|
|
59
59
|
* // Continue existing sandbox
|
|
60
|
-
*
|
|
60
|
+
* createAgentChat({ agent: "my-agent", tokenUrl: "/api/an/token", sandboxId: sandbox.id })
|
|
61
61
|
*/
|
|
62
62
|
sandboxId?: string
|
|
63
63
|
/**
|
|
@@ -78,25 +78,25 @@ export interface CustomToolRendererProps {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/** A model option for the model selector */
|
|
81
|
-
export interface
|
|
81
|
+
export interface ModelOption {
|
|
82
82
|
id: string
|
|
83
83
|
name: string
|
|
84
84
|
version?: string
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/** Props for the <
|
|
88
|
-
export interface
|
|
87
|
+
/** Props for the <AgentChat> drop-in component */
|
|
88
|
+
export interface AgentChatProps {
|
|
89
89
|
messages: UIMessage[]
|
|
90
90
|
onSend: (message: { role: "user"; content: string }) => void
|
|
91
91
|
status: ChatStatus
|
|
92
92
|
onStop: () => void
|
|
93
93
|
error?: Error
|
|
94
94
|
|
|
95
|
-
theme?:
|
|
95
|
+
theme?: ChatTheme
|
|
96
96
|
colorMode?: "light" | "dark" | "auto"
|
|
97
97
|
|
|
98
|
-
classNames?: Partial<
|
|
99
|
-
slots?: Partial<
|
|
98
|
+
classNames?: Partial<ChatClassNames>
|
|
99
|
+
slots?: Partial<ChatSlots>
|
|
100
100
|
toolRenderers?: Record<string, React.ComponentType<CustomToolRendererProps>>
|
|
101
101
|
|
|
102
102
|
/** Show window chrome header (traffic lights + agent indicator) */
|
|
@@ -104,7 +104,7 @@ export interface AnAgentChatProps {
|
|
|
104
104
|
|
|
105
105
|
/** Model selector configuration */
|
|
106
106
|
modelSelector?: {
|
|
107
|
-
models:
|
|
107
|
+
models: ModelOption[]
|
|
108
108
|
activeModelId?: string
|
|
109
109
|
onModelChange?: (id: string) => void
|
|
110
110
|
display?: "popover" | "badge"
|
|
@@ -133,3 +133,11 @@ export interface AnAgentChatProps {
|
|
|
133
133
|
className?: string
|
|
134
134
|
style?: React.CSSProperties
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
// Legacy type aliases kept for compatibility.
|
|
138
|
+
export type AnTheme = ChatTheme
|
|
139
|
+
export type AnClassNames = ChatClassNames
|
|
140
|
+
export type AnSlots = ChatSlots
|
|
141
|
+
export type CreateAnChatOptions = CreateAgentChatOptions
|
|
142
|
+
export type AnModelOption = ModelOption
|
|
143
|
+
export type AnAgentChatProps = AgentChatProps
|
package/styles/index.css
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* AN Agent Chat - CSS Custom Properties
|
|
7
|
+
* These are the default values. Consumers override via <AnAgentChat theme={...} />
|
|
8
|
+
* which calls applyTheme() to set these vars on the root element.
|
|
9
|
+
*/
|
|
10
|
+
:root, .an-root {
|
|
11
|
+
/* Typography */
|
|
12
|
+
--an-font-family: system-ui, sans-serif;
|
|
13
|
+
--an-text-size: 14px;
|
|
14
|
+
--an-text-size-sm: 13px;
|
|
15
|
+
--an-text-size-xs: 11px;
|
|
16
|
+
--an-line-height: 1.6;
|
|
17
|
+
--an-font-weight: 400;
|
|
18
|
+
--an-font-weight-medium: 500;
|
|
19
|
+
--an-font-weight-semibold: 600;
|
|
20
|
+
|
|
21
|
+
/* Geometry — all radii derive from --an-border-radius */
|
|
22
|
+
--an-border-radius: 16px;
|
|
23
|
+
--an-message-border-radius: var(--an-border-radius);
|
|
24
|
+
--an-input-border-radius: var(--an-border-radius);
|
|
25
|
+
--an-tool-border-radius: var(--an-border-radius);
|
|
26
|
+
--an-code-border-radius: var(--an-border-radius);
|
|
27
|
+
|
|
28
|
+
/* Layout — --an-message-gap is intentionally unset; density config provides the default */
|
|
29
|
+
--an-user-message-padding: 10px 14px;
|
|
30
|
+
--an-input-padding: 12px 16px;
|
|
31
|
+
|
|
32
|
+
/* Sizes */
|
|
33
|
+
--an-send-button-size: 32px;
|
|
34
|
+
--an-stop-button-size: 32px;
|
|
35
|
+
--an-send-button-border-radius: 9999px;
|
|
36
|
+
|
|
37
|
+
/* Colors - Light mode defaults */
|
|
38
|
+
--an-background: #ffffff;
|
|
39
|
+
--an-background-secondary: #f5f5f5;
|
|
40
|
+
--an-background-tertiary: #fafafa;
|
|
41
|
+
--an-foreground: #1a1a1a;
|
|
42
|
+
--an-foreground-muted: #737373;
|
|
43
|
+
--an-foreground-subtle: #a3a3a3;
|
|
44
|
+
--an-border-color: #e5e5e5;
|
|
45
|
+
--an-border-color-light: #f0f0f0;
|
|
46
|
+
--an-primary-color: #3b82f6;
|
|
47
|
+
|
|
48
|
+
/* User Messages */
|
|
49
|
+
--an-user-message-bg: #f5f5f5;
|
|
50
|
+
--an-user-message-text: #1a1a1a;
|
|
51
|
+
|
|
52
|
+
/* Input */
|
|
53
|
+
--an-input-background: #ffffff;
|
|
54
|
+
--an-input-border-color: #e5e5e5;
|
|
55
|
+
--an-input-color: #1a1a1a;
|
|
56
|
+
--an-input-placeholder-color: #a3a3a3;
|
|
57
|
+
|
|
58
|
+
/* Send/Stop Buttons */
|
|
59
|
+
--an-send-button-bg: #3b82f6;
|
|
60
|
+
--an-send-button-color: #ffffff;
|
|
61
|
+
--an-stop-button-bg: #1a1a1a;
|
|
62
|
+
--an-stop-button-color: #ffffff;
|
|
63
|
+
|
|
64
|
+
/* Tools */
|
|
65
|
+
--an-tool-background: #fafafa;
|
|
66
|
+
--an-tool-border-color: #e5e5e5;
|
|
67
|
+
--an-tool-color: #1a1a1a;
|
|
68
|
+
--an-tool-color-muted: #737373;
|
|
69
|
+
|
|
70
|
+
/* Code */
|
|
71
|
+
--an-code-background: #1e1e1e;
|
|
72
|
+
--an-code-color: #d4d4d4;
|
|
73
|
+
--an-code-font-family: ui-monospace, monospace;
|
|
74
|
+
--an-code-font-size: 13px;
|
|
75
|
+
|
|
76
|
+
/* Diff colors */
|
|
77
|
+
--an-diff-added-bg: rgba(34, 197, 94, 0.1);
|
|
78
|
+
--an-diff-added-border: rgba(34, 197, 94, 0.5);
|
|
79
|
+
--an-diff-added-text: #15803d;
|
|
80
|
+
--an-diff-removed-bg: rgba(239, 68, 68, 0.1);
|
|
81
|
+
--an-diff-removed-border: rgba(239, 68, 68, 0.5);
|
|
82
|
+
--an-diff-removed-text: #dc2626;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Dark mode defaults */
|
|
86
|
+
.dark, .an-root.dark, .dark .an-root {
|
|
87
|
+
--an-background: #0a0a0a;
|
|
88
|
+
--an-background-secondary: #1a1a1a;
|
|
89
|
+
--an-background-tertiary: #141414;
|
|
90
|
+
--an-foreground: #fafafa;
|
|
91
|
+
--an-foreground-muted: #a3a3a3;
|
|
92
|
+
--an-foreground-subtle: #71717a;
|
|
93
|
+
--an-border-color: #2a2a2a;
|
|
94
|
+
--an-border-color-light: #1f1f1f;
|
|
95
|
+
--an-primary-color: #60a5fa;
|
|
96
|
+
|
|
97
|
+
--an-user-message-bg: #1a1a1a;
|
|
98
|
+
--an-user-message-text: #fafafa;
|
|
99
|
+
|
|
100
|
+
--an-input-background: #0a0a0a;
|
|
101
|
+
--an-input-border-color: #2a2a2a;
|
|
102
|
+
--an-input-color: #fafafa;
|
|
103
|
+
--an-input-placeholder-color: #71717a;
|
|
104
|
+
|
|
105
|
+
--an-send-button-bg: #60a5fa;
|
|
106
|
+
--an-send-button-color: #ffffff;
|
|
107
|
+
--an-stop-button-bg: #fafafa;
|
|
108
|
+
--an-stop-button-color: #0a0a0a;
|
|
109
|
+
|
|
110
|
+
--an-tool-background: #141414;
|
|
111
|
+
--an-tool-border-color: #2a2a2a;
|
|
112
|
+
--an-tool-color: #fafafa;
|
|
113
|
+
--an-tool-color-muted: #a3a3a3;
|
|
114
|
+
|
|
115
|
+
--an-code-background: #0a0a0a;
|
|
116
|
+
--an-code-color: #d4d4d4;
|
|
117
|
+
|
|
118
|
+
--an-diff-added-bg: rgba(34, 197, 94, 0.15);
|
|
119
|
+
--an-diff-added-border: rgba(34, 197, 94, 0.4);
|
|
120
|
+
--an-diff-added-text: #4ade80;
|
|
121
|
+
--an-diff-removed-bg: rgba(239, 68, 68, 0.15);
|
|
122
|
+
--an-diff-removed-border: rgba(239, 68, 68, 0.4);
|
|
123
|
+
--an-diff-removed-text: #f87171;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* TextShimmer animation */
|
|
127
|
+
@keyframes an-shimmer {
|
|
128
|
+
from { background-position: 100% center; }
|
|
129
|
+
to { background-position: 0% center; }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.an-text-shimmer {
|
|
133
|
+
display: inline-block;
|
|
134
|
+
background-size: 250% 100%;
|
|
135
|
+
background-clip: text;
|
|
136
|
+
-webkit-background-clip: text;
|
|
137
|
+
color: transparent;
|
|
138
|
+
background-image:
|
|
139
|
+
linear-gradient(90deg, transparent calc(50% - var(--an-shimmer-spread, 100px)), var(--an-foreground-muted, #737373), transparent calc(50% + var(--an-shimmer-spread, 100px))),
|
|
140
|
+
linear-gradient(var(--an-foreground-subtle, #a3a3a3), var(--an-foreground-subtle, #a3a3a3));
|
|
141
|
+
background-repeat: no-repeat, padding-box;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.an-text-shimmer--active {
|
|
145
|
+
animation: an-shimmer var(--an-shimmer-duration, 2s) linear infinite;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Scrollbar hide utility */
|
|
149
|
+
.scrollbar-hide {
|
|
150
|
+
-ms-overflow-style: none;
|
|
151
|
+
scrollbar-width: none;
|
|
152
|
+
}
|
|
153
|
+
.scrollbar-hide::-webkit-scrollbar {
|
|
154
|
+
display: none;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Spinner animation */
|
|
158
|
+
@keyframes an-spinner-rotate {
|
|
159
|
+
from { transform: rotate(0deg); }
|
|
160
|
+
to { transform: rotate(360deg); }
|
|
161
|
+
}
|