feat(ui): add base component tokens and primitives
This commit is contained in:
1 parent
febb28aa6f
commit
0284603847
10 files changed
+1130
No files matched your search
@@ -4,6 +4,10 @@ import App from './App'
|
|||||||
import { SettingsWindow } from './components/SettingsDialog'
|
import { SettingsWindow } from './components/SettingsDialog'
|
||||||
import './workbuddy/typography/tokens.css'
|
import './workbuddy/typography/tokens.css'
|
||||||
import './styles/tokens.css'
|
import './styles/tokens.css'
|
||||||
|
import './ui/tokens.css'
|
||||||
|
import './ui/button.css'
|
||||||
|
import './ui/input.css'
|
||||||
|
import './ui/switch.css'
|
||||||
import './styles/app.css'
|
import './styles/app.css'
|
||||||
import './styles/sidebar.css'
|
import './styles/sidebar.css'
|
||||||
import './workbuddy/conversation/source-styles.css'
|
import './workbuddy/conversation/source-styles.css'
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { createRoot } from 'react-dom/client'
|
|||||||
import { SettingsWindow } from './components/SettingsDialog'
|
import { SettingsWindow } from './components/SettingsDialog'
|
||||||
import './workbuddy/typography/tokens.css'
|
import './workbuddy/typography/tokens.css'
|
||||||
import './styles/tokens.css'
|
import './styles/tokens.css'
|
||||||
|
import './ui/tokens.css'
|
||||||
|
import './ui/button.css'
|
||||||
|
import './ui/input.css'
|
||||||
|
import './ui/switch.css'
|
||||||
import './styles/app.css'
|
import './styles/app.css'
|
||||||
import './styles/settings-entry.css'
|
import './styles/settings-entry.css'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { Children, type ButtonHTMLAttributes, type ReactNode, type Ref } from 'react'
|
||||||
|
import './button.css'
|
||||||
|
|
||||||
|
export type ButtonVariant = 'primary' | 'secondary' | 'grey' | 'ghost' | 'link' | 'danger'
|
||||||
|
export type ButtonSize = 'sm' | 'md' | 'lg'
|
||||||
|
|
||||||
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
|
variant?: ButtonVariant
|
||||||
|
size?: ButtonSize
|
||||||
|
iconOnly?: boolean
|
||||||
|
loading?: boolean
|
||||||
|
iconLeft?: ReactNode
|
||||||
|
iconRight?: ReactNode
|
||||||
|
ref?: Ref<HTMLButtonElement>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原版按钮的加载图标(16 图标栅格、8 辐条、currentColor);
|
||||||
|
* 尺寸由 button.css 按 size 覆盖,旋转由 .yc-button__loading-icon 驱动。
|
||||||
|
*/
|
||||||
|
function ButtonLoadingIcon(): ReactNode {
|
||||||
|
return (
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" className="yc-button__loading-icon">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
fillRule="evenodd"
|
||||||
|
transform="matrix(1 0 0 1 2.07103 1.5)"
|
||||||
|
d="M6.529 0L6.529 4L5.329 4L5.329 0L6.529 0ZM8.394 5.7697L11.8581 3.7697L11.258 2.7305L7.7939 4.7305L8.394 5.7697ZM3.4641 5.7698L0 3.7698L0.6 2.7305L4.0641 4.7305L3.4641 5.7698ZM7.7939 8.2697L11.258 10.2697L11.8581 9.2305L8.394 7.2305L7.7939 8.2697ZM4.0641 8.2697L0.6 10.2697L0 9.2305L3.4641 7.2305L4.0641 8.2697ZM6.529 9L6.529 13L5.329 13L5.329 9L6.529 9Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一按钮。DOM 结构与原版按钮一致:
|
||||||
|
* iconLeft -> .yc-button__icon--left,children -> .yc-button__content
|
||||||
|
* (iconOnly 时 children 进 .yc-button__icon),loading -> .yc-button__loading。
|
||||||
|
*/
|
||||||
|
export function Button({
|
||||||
|
variant = 'secondary',
|
||||||
|
size = 'md',
|
||||||
|
iconOnly = false,
|
||||||
|
loading = false,
|
||||||
|
iconLeft,
|
||||||
|
iconRight,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
type,
|
||||||
|
disabled,
|
||||||
|
ref,
|
||||||
|
'aria-busy': ariaBusy,
|
||||||
|
...rest
|
||||||
|
}: ButtonProps): React.JSX.Element {
|
||||||
|
const classes = ['yc-button', `yc-button--${variant}`, `yc-button--${size}`]
|
||||||
|
if (iconOnly) classes.push('yc-button--icon-only')
|
||||||
|
if (loading) classes.push('yc-button--loading')
|
||||||
|
if (disabled || loading) classes.push('yc-button--disabled')
|
||||||
|
if (className) classes.push(className)
|
||||||
|
|
||||||
|
const hasContent = Children.count(children) > 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
{...rest}
|
||||||
|
ref={ref}
|
||||||
|
type={type ?? 'button'}
|
||||||
|
className={classes.join(' ')}
|
||||||
|
disabled={disabled || loading}
|
||||||
|
aria-busy={loading ? true : ariaBusy}
|
||||||
|
>
|
||||||
|
{iconLeft ? <span className="yc-button__icon yc-button__icon--left">{iconLeft}</span> : null}
|
||||||
|
{!iconOnly && hasContent ? <span className="yc-button__content">{children}</span> : null}
|
||||||
|
{iconOnly && hasContent ? <span className="yc-button__icon">{children}</span> : null}
|
||||||
|
{iconRight ? <span className="yc-button__icon yc-button__icon--right">{iconRight}</span> : null}
|
||||||
|
{loading ? (
|
||||||
|
<span className="yc-button__loading" aria-hidden="true">
|
||||||
|
<ButtonLoadingIcon />
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { Button, type ButtonProps } from './Button'
|
||||||
|
|
||||||
|
/** 图标按钮没有文本,必须有可读名称:aria-label 或 title 至少给一个。 */
|
||||||
|
type IconButtonLabel =
|
||||||
|
| { 'aria-label': string; title?: string }
|
||||||
|
| { title: string; 'aria-label'?: string }
|
||||||
|
|
||||||
|
export type IconButtonProps = Omit<ButtonProps, 'iconOnly' | 'children'> &
|
||||||
|
IconButtonLabel & {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button 的 iconOnly 语法糖:默认 variant="ghost"、size="md"。
|
||||||
|
*
|
||||||
|
* 缺少 aria-label 与 title 时:开发环境抛出明确错误;生产构建不渲染 DOM,
|
||||||
|
* 避免留下对读屏不可用的空白按钮(类型层已用联合类型要求二者之一)。
|
||||||
|
*/
|
||||||
|
export function IconButton({
|
||||||
|
variant = 'ghost',
|
||||||
|
size = 'md',
|
||||||
|
children,
|
||||||
|
'aria-label': ariaLabel,
|
||||||
|
title,
|
||||||
|
...rest
|
||||||
|
}: IconButtonProps): React.JSX.Element | null {
|
||||||
|
if (!ariaLabel && !title) {
|
||||||
|
const message = 'IconButton 需要 aria-label 或 title:图标按钮缺少可读名称。'
|
||||||
|
if (import.meta.env.DEV) throw new Error(message)
|
||||||
|
console.error(message)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button {...rest} iconOnly variant={variant} size={size} aria-label={ariaLabel} title={title}>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* YCode UI Input(P2-B)。
|
||||||
|
*
|
||||||
|
* 结构与几何来源:`docs/界面基础组件规范-2026-10-18.md` 的 Input 章节,
|
||||||
|
* 等价于设置页恢复样式 source-general-settings-recovered.css 中 `.wb-input-wrapper`
|
||||||
|
* (height 28/32/48、padding-x 8/8/12、radius 6/8/12、filled/disabled/error 态)。
|
||||||
|
* 只消费 ui/tokens.css 的 `--yc-*` L2 token,不写裸值。
|
||||||
|
*/
|
||||||
|
import type { InputHTMLAttributes, ReactNode } from 'react'
|
||||||
|
import './input.css'
|
||||||
|
|
||||||
|
export type InputSize = 'sm' | 'md' | 'lg'
|
||||||
|
|
||||||
|
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
|
||||||
|
size?: InputSize
|
||||||
|
invalid?: boolean
|
||||||
|
filled?: boolean
|
||||||
|
prefix?: ReactNode
|
||||||
|
suffix?: ReactNode
|
||||||
|
wrapperClassName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function classNames(...values: Array<string | false | null | undefined>): string {
|
||||||
|
return values.filter(Boolean).join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Input({
|
||||||
|
size = 'md',
|
||||||
|
invalid = false,
|
||||||
|
filled = false,
|
||||||
|
prefix,
|
||||||
|
suffix,
|
||||||
|
wrapperClassName,
|
||||||
|
className,
|
||||||
|
disabled,
|
||||||
|
...inputProps
|
||||||
|
}: InputProps): React.JSX.Element {
|
||||||
|
const wrapperClass = classNames(
|
||||||
|
'yc-input',
|
||||||
|
`yc-input--${size}`,
|
||||||
|
filled && 'yc-input--filled',
|
||||||
|
invalid && 'yc-input--invalid',
|
||||||
|
disabled && 'yc-input--disabled',
|
||||||
|
wrapperClassName
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={wrapperClass} data-disabled={disabled ? 'true' : undefined}>
|
||||||
|
{prefix ? <span className="yc-input__prefix">{prefix}</span> : null}
|
||||||
|
<input className={classNames('yc-input__inner', className)} disabled={disabled} {...inputProps} />
|
||||||
|
{suffix ? <span className="yc-input__suffix">{suffix}</span> : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* YCode UI Switch(P2-B)。
|
||||||
|
*
|
||||||
|
* 结构与几何来源:`docs/界面基础组件规范-2026-10-18.md` 的 Switch 章节,
|
||||||
|
* 对应 GeneralSettingsPanel 本地 Switch 与恢复样式 source-general-settings-recovered.css
|
||||||
|
* 的 `.wb-switch*` 闭包(track 24×14 / 26×16 / 34×20,thumb 10 / 12 / 16)。
|
||||||
|
* 只消费 ui/tokens.css 的 `--yc-*` L2 token,不写裸值。
|
||||||
|
*/
|
||||||
|
import type { ChangeEvent } from 'react'
|
||||||
|
import './switch.css'
|
||||||
|
|
||||||
|
export type SwitchSize = 'sm' | 'md' | 'lg'
|
||||||
|
|
||||||
|
export interface SwitchProps {
|
||||||
|
checked: boolean
|
||||||
|
onCheckedChange?(checked: boolean): void
|
||||||
|
disabled?: boolean
|
||||||
|
readOnly?: boolean
|
||||||
|
size?: SwitchSize
|
||||||
|
'aria-label': string
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function classNames(...values: Array<string | false | null | undefined>): string {
|
||||||
|
return values.filter(Boolean).join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Switch({
|
||||||
|
checked,
|
||||||
|
onCheckedChange,
|
||||||
|
disabled = false,
|
||||||
|
readOnly = false,
|
||||||
|
size = 'md',
|
||||||
|
className,
|
||||||
|
'aria-label': ariaLabel
|
||||||
|
}: SwitchProps): React.JSX.Element {
|
||||||
|
const handleChange = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
if (readOnly) return
|
||||||
|
onCheckedChange?.(event.target.checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={classNames('yc-switch', `yc-switch--${size}`, className)}
|
||||||
|
data-disabled={disabled ? 'true' : undefined}
|
||||||
|
data-readonly={readOnly ? 'true' : undefined}
|
||||||
|
>
|
||||||
|
<span className="yc-switch__control">
|
||||||
|
<input
|
||||||
|
className="yc-switch__input"
|
||||||
|
type="checkbox"
|
||||||
|
role="switch"
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
aria-readonly={readOnly || undefined}
|
||||||
|
checked={checked}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<span className="yc-switch__track">
|
||||||
|
<span className="yc-switch__thumb" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
/**
|
||||||
|
* YCode Button / IconButton(L2:--yc-button-*)。
|
||||||
|
*
|
||||||
|
* 由原版 .wb-button 的已验证闭包翻译:类名前缀 wb-button -> yc-button,
|
||||||
|
* 子元素沿用原结构(__icon / __content / __loading / __loading-icon)。
|
||||||
|
* 颜色与几何只消费 ui/tokens.css 的 --yc-button-* 与 styles/tokens.css 的
|
||||||
|
* L0/L1 token;不写裸值,自身不带外间距(间距由调用方决定)。
|
||||||
|
*/
|
||||||
|
|
||||||
|
.yc-button {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--yc-button-gap-md);
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--yc-button-radius-md);
|
||||||
|
font-family: var(--yc-font-sans);
|
||||||
|
font-weight: var(--yc-font-weight-500);
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
transition:
|
||||||
|
background-color var(--yc-button-transition-duration) var(--yc-button-transition-easing),
|
||||||
|
color var(--yc-button-transition-duration) var(--yc-button-transition-easing),
|
||||||
|
border-color var(--yc-button-transition-duration) var(--yc-button-transition-easing),
|
||||||
|
transform var(--yc-button-transition-duration) var(--yc-button-transition-easing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- 尺寸 */
|
||||||
|
|
||||||
|
.yc-button--sm {
|
||||||
|
height: var(--yc-button-height-sm);
|
||||||
|
padding: 0 var(--yc-button-padding-sm);
|
||||||
|
gap: var(--yc-button-gap-sm);
|
||||||
|
border-radius: var(--yc-button-radius-sm);
|
||||||
|
font-size: var(--yc-button-font-size-sm);
|
||||||
|
line-height: var(--yc-button-line-height-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--md {
|
||||||
|
height: var(--yc-button-height-md);
|
||||||
|
padding: 0 var(--yc-button-padding-md);
|
||||||
|
gap: var(--yc-button-gap-md);
|
||||||
|
border-radius: var(--yc-button-radius-md);
|
||||||
|
font-size: var(--yc-button-font-size-md);
|
||||||
|
line-height: var(--yc-button-line-height-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--lg {
|
||||||
|
height: var(--yc-button-height-lg);
|
||||||
|
padding: 0 var(--yc-button-padding-lg);
|
||||||
|
gap: var(--yc-button-gap-lg);
|
||||||
|
border-radius: var(--yc-button-radius-lg);
|
||||||
|
font-size: var(--yc-button-font-size-lg);
|
||||||
|
line-height: var(--yc-button-line-height-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--icon-only {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--sm:not(.yc-button--icon-only):not(.yc-button--link) {
|
||||||
|
min-width: var(--yc-button-min-width-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--md:not(.yc-button--icon-only):not(.yc-button--link) {
|
||||||
|
min-width: var(--yc-button-min-width-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--icon-only.yc-button--sm {
|
||||||
|
width: var(--yc-button-height-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--icon-only.yc-button--md {
|
||||||
|
width: var(--yc-button-height-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--icon-only.yc-button--lg {
|
||||||
|
width: var(--yc-button-height-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------ 图标与文本容器 */
|
||||||
|
|
||||||
|
.yc-button__icon,
|
||||||
|
.yc-button__loading-icon {
|
||||||
|
width: var(--yc-button-icon-md);
|
||||||
|
height: var(--yc-button-icon-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--sm :is(.yc-button__icon, .yc-button__loading-icon) {
|
||||||
|
width: var(--yc-button-icon-sm);
|
||||||
|
height: var(--yc-button-icon-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--lg :is(.yc-button__icon, .yc-button__loading-icon) {
|
||||||
|
width: var(--yc-button-icon-lg);
|
||||||
|
height: var(--yc-button-icon-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button__icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button__icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
color: currentColor;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button__content {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- 变体 */
|
||||||
|
|
||||||
|
.yc-button--primary {
|
||||||
|
background-color: var(--yc-button-primary-bg);
|
||||||
|
color: var(--yc-button-primary-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--primary:hover:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-primary-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--primary:active:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-primary-bg-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--primary:disabled,
|
||||||
|
.yc-button--primary.yc-button--disabled {
|
||||||
|
background-color: var(--yc-button-primary-bg-disabled);
|
||||||
|
color: var(--yc-button-primary-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--secondary {
|
||||||
|
background-color: var(--yc-button-secondary-bg);
|
||||||
|
color: var(--yc-button-secondary-fg);
|
||||||
|
border: var(--yc-border-width) solid var(--yc-button-secondary-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--secondary:hover:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-secondary-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--secondary:active:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-secondary-bg-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--secondary:disabled,
|
||||||
|
.yc-button--secondary.yc-button--disabled {
|
||||||
|
color: var(--yc-button-secondary-fg-disabled);
|
||||||
|
border-color: var(--yc-button-secondary-border-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--grey {
|
||||||
|
background-color: var(--yc-button-grey-bg);
|
||||||
|
color: var(--yc-button-grey-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--grey:hover:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-grey-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--grey:active:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-grey-bg-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--grey:disabled,
|
||||||
|
.yc-button--grey.yc-button--disabled {
|
||||||
|
background-color: var(--yc-button-grey-bg-disabled);
|
||||||
|
color: var(--yc-button-grey-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--ghost {
|
||||||
|
background-color: var(--yc-button-ghost-bg);
|
||||||
|
color: var(--yc-button-ghost-fg);
|
||||||
|
font-weight: var(--yc-font-weight-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--ghost:hover:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-ghost-bg-hover);
|
||||||
|
color: var(--yc-button-ghost-fg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--ghost:active:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-ghost-bg-active);
|
||||||
|
color: var(--yc-button-ghost-fg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--ghost:disabled,
|
||||||
|
.yc-button--ghost.yc-button--disabled {
|
||||||
|
background-color: var(--yc-button-ghost-bg);
|
||||||
|
color: var(--yc-button-ghost-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--link {
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: var(--yc-button-link-bg);
|
||||||
|
color: var(--yc-button-link-fg);
|
||||||
|
font-weight: var(--yc-font-weight-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--link:hover:not(:disabled) {
|
||||||
|
color: var(--yc-button-link-fg-hover);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--link:active:not(:disabled) {
|
||||||
|
color: var(--yc-button-link-fg-hover);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--link:disabled,
|
||||||
|
.yc-button--link.yc-button--disabled {
|
||||||
|
color: var(--yc-button-link-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--danger {
|
||||||
|
background-color: var(--yc-button-danger-bg);
|
||||||
|
color: var(--yc-button-danger-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--danger:hover:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-danger-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--danger:active:not(:disabled) {
|
||||||
|
background-color: var(--yc-button-danger-bg-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--danger:disabled,
|
||||||
|
.yc-button--danger.yc-button--disabled {
|
||||||
|
background-color: var(--yc-button-danger-bg-disabled);
|
||||||
|
color: var(--yc-button-danger-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------- loading */
|
||||||
|
|
||||||
|
.yc-button--loading {
|
||||||
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容与图标保留占位(只隐藏),加载指示器绝对居中,几何不跳动 */
|
||||||
|
.yc-button--loading .yc-button__content,
|
||||||
|
.yc-button--loading .yc-button__icon {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button__loading {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button__loading-icon {
|
||||||
|
flex: none;
|
||||||
|
animation: yc-button-spin var(--yc-button-spinner-duration) linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes yc-button-spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载态按钮同时是 disabled,spinner 需取变体本身的可见色而非 disabled 前景色 */
|
||||||
|
.yc-button--primary .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-primary-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--secondary .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-secondary-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--grey .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-grey-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--ghost .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-ghost-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--link .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-link-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-button--danger .yc-button__loading-icon {
|
||||||
|
color: var(--yc-button-danger-bg-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ 键盘焦点 */
|
||||||
|
|
||||||
|
.yc-button:focus-visible {
|
||||||
|
outline: var(--yc-focus-ring-width) solid var(--yc-focus-ring-color);
|
||||||
|
outline-offset: var(--yc-focus-ring-offset);
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* YCode UI Input 样式(P2-B)。
|
||||||
|
*
|
||||||
|
* 仅消费 `--yc-*` token(L2 组件 token + L0/L1 基础 token),不写裸值、强制声明或
|
||||||
|
* 外部外边距。几何与状态对应 source-general-settings-recovered.css
|
||||||
|
* 的 `.wb-input-wrapper*` 闭包。
|
||||||
|
*/
|
||||||
|
|
||||||
|
.yc-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--yc-space-2);
|
||||||
|
width: 100%;
|
||||||
|
color: var(--yc-input-fg);
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: var(--yc-input-line-height);
|
||||||
|
background: var(--yc-input-bg);
|
||||||
|
border: var(--yc-border-width) solid var(--yc-input-border);
|
||||||
|
outline: none;
|
||||||
|
transition: border-color var(--yc-input-transition-duration) var(--yc-button-transition-easing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input__inner {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input__inner::placeholder {
|
||||||
|
color: var(--yc-input-placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input__prefix,
|
||||||
|
.yc-input__suffix {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: none;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--yc-input-icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input__prefix svg,
|
||||||
|
.yc-input__suffix svg {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 尺寸 */
|
||||||
|
.yc-input--sm {
|
||||||
|
height: var(--yc-input-height-sm);
|
||||||
|
padding: 0 var(--yc-input-padding-x-sm);
|
||||||
|
border-radius: var(--yc-input-radius-sm);
|
||||||
|
font-size: var(--yc-input-font-size-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--md {
|
||||||
|
height: var(--yc-input-height-md);
|
||||||
|
padding: 0 var(--yc-input-padding-x-md);
|
||||||
|
border-radius: var(--yc-input-radius-md);
|
||||||
|
font-size: var(--yc-input-font-size-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--lg {
|
||||||
|
height: var(--yc-input-height-lg);
|
||||||
|
padding: 0 var(--yc-input-padding-x-lg);
|
||||||
|
border-radius: var(--yc-input-radius-lg);
|
||||||
|
font-size: var(--yc-input-font-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filled */
|
||||||
|
.yc-input--filled {
|
||||||
|
background: var(--yc-input-bg-filled);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hover / focus(invalid 优先级更高,保持错误态边框) */
|
||||||
|
.yc-input:hover:not(.yc-input--disabled):not(:has(.yc-input__inner:read-only)) {
|
||||||
|
border-color: var(--yc-input-border-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input:focus-within:not(.yc-input--disabled):not(:has(.yc-input__inner:read-only)) {
|
||||||
|
border-color: var(--yc-input-border-focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--invalid {
|
||||||
|
border-color: var(--yc-input-border-invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--invalid:hover:not(.yc-input--disabled),
|
||||||
|
.yc-input--invalid:focus-within:not(.yc-input--disabled) {
|
||||||
|
border-color: var(--yc-input-border-invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disabled */
|
||||||
|
.yc-input--disabled,
|
||||||
|
.yc-input:has(.yc-input__inner:disabled) {
|
||||||
|
color: var(--yc-input-fg-disabled);
|
||||||
|
background: var(--yc-input-bg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--disabled .yc-input__inner,
|
||||||
|
.yc-input:has(.yc-input__inner:disabled) .yc-input__inner {
|
||||||
|
color: var(--yc-input-fg-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-input--disabled .yc-input__prefix,
|
||||||
|
.yc-input--disabled .yc-input__suffix,
|
||||||
|
.yc-input:has(.yc-input__inner:disabled) .yc-input__prefix,
|
||||||
|
.yc-input:has(.yc-input__inner:disabled) .yc-input__suffix {
|
||||||
|
color: var(--yc-input-icon-disabled);
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* YCode UI Switch 样式(P2-B)。
|
||||||
|
*
|
||||||
|
* 仅消费 `--yc-*` token,不写裸值、强制声明或外部外边距。
|
||||||
|
* 几何与状态对应 source-general-settings-recovered.css 的 `.wb-switch*` 闭包;
|
||||||
|
* 文档未提供 focus 环颜色 token,暂用同计算值的 `--yc-input-border-focus`。
|
||||||
|
*/
|
||||||
|
|
||||||
|
.yc-switch {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-disabled='true'] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch__control {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch__input {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: inherit;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch__track {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 var(--yc-space-1);
|
||||||
|
border-radius: var(--yc-button-radius-pill);
|
||||||
|
background: var(--yc-switch-track-bg);
|
||||||
|
border: var(--yc-border-width) solid var(--yc-switch-track-border);
|
||||||
|
transition: background var(--yc-input-transition-duration) var(--yc-button-transition-easing),
|
||||||
|
border-color var(--yc-input-transition-duration) var(--yc-button-transition-easing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch__thumb {
|
||||||
|
border-radius: var(--yc-button-radius-pill);
|
||||||
|
background: var(--yc-switch-thumb-bg);
|
||||||
|
box-shadow: var(--yc-switch-thumb-shadow);
|
||||||
|
transition: transform var(--yc-input-transition-duration) var(--yc-button-transition-easing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 尺寸:track 用 padding 把 thumb 定位到左侧,与恢复样式一致 */
|
||||||
|
.yc-switch--sm .yc-switch__track {
|
||||||
|
width: var(--yc-switch-track-width-sm);
|
||||||
|
height: var(--yc-switch-track-height-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--sm .yc-switch__thumb {
|
||||||
|
width: var(--yc-switch-thumb-size-sm);
|
||||||
|
height: var(--yc-switch-thumb-size-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--md .yc-switch__track {
|
||||||
|
width: var(--yc-switch-track-width-md);
|
||||||
|
height: var(--yc-switch-track-height-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--md .yc-switch__thumb {
|
||||||
|
width: var(--yc-switch-thumb-size-md);
|
||||||
|
height: var(--yc-switch-thumb-size-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--lg .yc-switch__track {
|
||||||
|
width: var(--yc-switch-track-width-lg);
|
||||||
|
height: var(--yc-switch-track-height-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--lg .yc-switch__thumb {
|
||||||
|
width: var(--yc-switch-thumb-size-lg);
|
||||||
|
height: var(--yc-switch-thumb-size-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checked */
|
||||||
|
.yc-switch__input:checked + .yc-switch__track {
|
||||||
|
background: var(--yc-switch-track-bg-checked);
|
||||||
|
border-color: var(--yc-switch-track-bg-checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch__input:checked + .yc-switch__track:hover {
|
||||||
|
background: var(--yc-switch-track-bg-checked-hover);
|
||||||
|
border-color: var(--yc-switch-track-bg-checked-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--sm .yc-switch__input:checked + .yc-switch__track .yc-switch__thumb {
|
||||||
|
transform: translateX(var(--yc-switch-thumb-translate-sm));
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--md .yc-switch__input:checked + .yc-switch__track .yc-switch__thumb {
|
||||||
|
transform: translateX(var(--yc-switch-thumb-translate-md));
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch--lg .yc-switch__input:checked + .yc-switch__track .yc-switch__thumb {
|
||||||
|
transform: translateX(var(--yc-switch-thumb-translate-lg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* focus-visible */
|
||||||
|
.yc-switch__input:focus-visible + .yc-switch__track {
|
||||||
|
outline: var(--yc-focus-ring-width) solid var(--yc-focus-ring-color);
|
||||||
|
outline-offset: var(--yc-focus-ring-offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* readOnly:保持几何,仅移除可点击语义 */
|
||||||
|
.yc-switch[data-readonly='true'] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-readonly='true'] .yc-switch__input {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disabled:保持几何,用 token 降低视觉强度 */
|
||||||
|
.yc-switch[data-disabled='true'] .yc-switch__input:checked + .yc-switch__track {
|
||||||
|
background: var(--yc-switch-track-bg-checked-disabled);
|
||||||
|
border-color: var(--yc-switch-track-bg-checked-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-disabled='true'] .yc-switch__input:checked + .yc-switch__track:hover {
|
||||||
|
background: var(--yc-switch-track-bg-checked-disabled);
|
||||||
|
border-color: var(--yc-switch-track-bg-checked-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-disabled='true'] .yc-switch__input:not(:checked) + .yc-switch__track {
|
||||||
|
background: var(--yc-switch-track-bg-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-disabled='true'] .yc-switch__input:not(:checked) + .yc-switch__track:hover {
|
||||||
|
background: var(--yc-switch-track-bg-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.yc-switch[data-disabled='true'] .yc-switch__thumb {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
/**
|
||||||
|
* YCode UI 组件 token(L2)。
|
||||||
|
*
|
||||||
|
* 只在组件层消费;页面不得重定义。数值来自当前 --wb-* 控件闭包,
|
||||||
|
* 迁移期间必须保持现有视觉,不允许在这里发明新设计。
|
||||||
|
* Import order: workbuddy/typography/tokens.css -> styles/tokens.css -> ui/tokens.css
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Button */
|
||||||
|
--yc-button-height-sm: 24px;
|
||||||
|
--yc-button-height-md: 32px;
|
||||||
|
--yc-button-height-lg: 48px;
|
||||||
|
--yc-button-padding-sm: 8px;
|
||||||
|
--yc-button-padding-md: 12px;
|
||||||
|
--yc-button-padding-lg: 32px;
|
||||||
|
--yc-button-gap-sm: 2px;
|
||||||
|
--yc-button-gap-md: 4px;
|
||||||
|
--yc-button-gap-lg: 8px;
|
||||||
|
--yc-button-radius-sm: 6px;
|
||||||
|
--yc-button-radius-md: 8px;
|
||||||
|
--yc-button-radius-lg: 12px;
|
||||||
|
--yc-button-radius-pill: 9999px;
|
||||||
|
--yc-button-font-size-sm: var(--yc-font-size-3);
|
||||||
|
--yc-button-font-size-md: var(--yc-font-size-5);
|
||||||
|
--yc-button-font-size-lg: var(--yc-font-size-5);
|
||||||
|
--yc-button-line-height-sm: var(--yc-line-height-5);
|
||||||
|
--yc-button-line-height-md: var(--yc-line-height-5-2);
|
||||||
|
--yc-button-line-height-lg: var(--yc-line-height-5-2);
|
||||||
|
--yc-button-icon-sm: var(--yc-size-3);
|
||||||
|
--yc-button-icon-md: var(--yc-size-4);
|
||||||
|
--yc-button-icon-lg: var(--yc-size-4);
|
||||||
|
--yc-button-transition-duration: 0.1s;
|
||||||
|
--yc-button-transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
--yc-button-spinner-duration: 0.8s;
|
||||||
|
--yc-button-min-width-sm: 40px;
|
||||||
|
--yc-button-min-width-md: 68px;
|
||||||
|
|
||||||
|
--yc-button-primary-bg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-primary-bg-hover: rgba(0, 0, 0, 0.75);
|
||||||
|
--yc-button-primary-bg-active: rgba(0, 0, 0, 0.75);
|
||||||
|
--yc-button-primary-bg-disabled: rgba(0, 0, 0, 0.2);
|
||||||
|
--yc-button-primary-fg: #ffffff;
|
||||||
|
--yc-button-primary-fg-disabled: #ffffff;
|
||||||
|
|
||||||
|
--yc-button-secondary-bg: #ffffff;
|
||||||
|
--yc-button-secondary-bg-hover: #f7f7f7;
|
||||||
|
--yc-button-secondary-bg-active: #f7f7f7;
|
||||||
|
--yc-button-secondary-bg-disabled: #f7f7f7;
|
||||||
|
--yc-button-secondary-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-secondary-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-button-secondary-border: #dedede;
|
||||||
|
--yc-button-secondary-border-disabled: #ebebeb;
|
||||||
|
|
||||||
|
--yc-button-grey-bg: #ebebeb;
|
||||||
|
--yc-button-grey-bg-hover: #e6e6e6;
|
||||||
|
--yc-button-grey-bg-active: #e6e6e6;
|
||||||
|
--yc-button-grey-bg-disabled: #ebebeb;
|
||||||
|
--yc-button-grey-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-grey-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
--yc-button-ghost-bg: transparent;
|
||||||
|
--yc-button-ghost-bg-hover: rgba(0, 0, 0, 0.06);
|
||||||
|
--yc-button-ghost-bg-active: rgba(0, 0, 0, 0.06);
|
||||||
|
--yc-button-ghost-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-ghost-fg-hover: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-ghost-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
--yc-button-link-bg: transparent;
|
||||||
|
--yc-button-link-fg: #1470b4;
|
||||||
|
--yc-button-link-fg-hover: #1470b4;
|
||||||
|
--yc-button-link-fg-disabled: #94b7d1;
|
||||||
|
|
||||||
|
--yc-button-danger-bg: #e85c5c;
|
||||||
|
--yc-button-danger-bg-hover: #ec7474;
|
||||||
|
--yc-button-danger-bg-active: #ec7474;
|
||||||
|
--yc-button-danger-bg-disabled: #f5b9b9;
|
||||||
|
--yc-button-danger-fg: #ffffff;
|
||||||
|
--yc-button-danger-fg-disabled: #ffffff;
|
||||||
|
|
||||||
|
/* Focus ring(Button / Switch / 后续控件共用) */
|
||||||
|
--yc-focus-ring-color: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-focus-ring-width: 2px;
|
||||||
|
--yc-focus-ring-offset: 2px;
|
||||||
|
|
||||||
|
/* Input */
|
||||||
|
--yc-input-height-sm: 28px;
|
||||||
|
--yc-input-height-md: 32px;
|
||||||
|
--yc-input-height-lg: 48px;
|
||||||
|
--yc-input-padding-x-sm: 8px;
|
||||||
|
--yc-input-padding-x-md: 8px;
|
||||||
|
--yc-input-padding-x-lg: 12px;
|
||||||
|
--yc-input-radius-sm: 6px;
|
||||||
|
--yc-input-radius-md: 8px;
|
||||||
|
--yc-input-radius-lg: 12px;
|
||||||
|
--yc-input-font-size-sm: var(--yc-font-size-3);
|
||||||
|
--yc-input-font-size-md: var(--yc-font-size-5);
|
||||||
|
--yc-input-font-size-lg: var(--yc-font-size-5);
|
||||||
|
--yc-input-line-height: var(--yc-line-height-5-2);
|
||||||
|
--yc-input-bg: #ffffff;
|
||||||
|
--yc-input-bg-filled: #f2f2f2;
|
||||||
|
--yc-input-bg-disabled: #f7f7f7;
|
||||||
|
--yc-input-border: #e6e6e6;
|
||||||
|
--yc-input-border-hover: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-input-border-focus: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-input-border-invalid: #f64041;
|
||||||
|
--yc-input-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-input-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-input-placeholder: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-input-icon: rgba(0, 0, 0, 0.5);
|
||||||
|
--yc-input-icon-hover: rgba(0, 0, 0, 0.7);
|
||||||
|
--yc-input-icon-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-input-transition-duration: 0.1s;
|
||||||
|
|
||||||
|
/* Switch */
|
||||||
|
--yc-switch-track-width-sm: 24px;
|
||||||
|
--yc-switch-track-width-md: 26px;
|
||||||
|
--yc-switch-track-width-lg: 34px;
|
||||||
|
--yc-switch-track-height-sm: 14px;
|
||||||
|
--yc-switch-track-height-md: 16px;
|
||||||
|
--yc-switch-track-height-lg: 20px;
|
||||||
|
--yc-switch-thumb-size-sm: 10px;
|
||||||
|
--yc-switch-thumb-size-md: 12px;
|
||||||
|
--yc-switch-thumb-size-lg: 16px;
|
||||||
|
--yc-switch-thumb-translate-sm: 8px;
|
||||||
|
--yc-switch-thumb-translate-md: 8px;
|
||||||
|
--yc-switch-thumb-translate-lg: 12px;
|
||||||
|
--yc-switch-track-bg: #e6e6e6;
|
||||||
|
--yc-switch-track-bg-disabled: #e6e6e6;
|
||||||
|
--yc-switch-track-bg-checked: #00c29a;
|
||||||
|
--yc-switch-track-bg-checked-hover: #40d1b3;
|
||||||
|
--yc-switch-track-bg-checked-disabled: #9fe8d9;
|
||||||
|
--yc-switch-track-border: rgba(0, 0, 0, 0.08);
|
||||||
|
--yc-switch-thumb-bg: #ffffff;
|
||||||
|
--yc-switch-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
--yc-switch-focus-outline: 2px;
|
||||||
|
--yc-switch-focus-offset: 2px;
|
||||||
|
|
||||||
|
/* Select */
|
||||||
|
--yc-select-height-sm: 24px;
|
||||||
|
--yc-select-height-md: 32px;
|
||||||
|
--yc-select-height-lg: 48px;
|
||||||
|
--yc-select-padding-x-sm: 6px;
|
||||||
|
--yc-select-padding-x-md: 8px;
|
||||||
|
--yc-select-padding-x-lg: 12px;
|
||||||
|
--yc-select-radius-sm: 6px;
|
||||||
|
--yc-select-radius-md: 8px;
|
||||||
|
--yc-select-radius-lg: 12px;
|
||||||
|
--yc-select-font-size-sm: var(--yc-font-size-3);
|
||||||
|
--yc-select-font-size-md: var(--yc-font-size-5);
|
||||||
|
--yc-select-font-size-lg: var(--yc-font-size-5);
|
||||||
|
--yc-select-line-height: var(--yc-line-height-5-2);
|
||||||
|
--yc-select-icon: var(--yc-size-4);
|
||||||
|
--yc-select-bg: #ffffff;
|
||||||
|
--yc-select-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-select-placeholder: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-select-border: #e6e6e6;
|
||||||
|
--yc-select-border-hover: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-select-border-open: rgba(0, 0, 0, 0.5);
|
||||||
|
--yc-select-bg-disabled: #f7f7f7;
|
||||||
|
--yc-select-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
/* Dialog */
|
||||||
|
--yc-dialog-bg: #ffffff;
|
||||||
|
--yc-dialog-border: #dedede;
|
||||||
|
--yc-dialog-radius: 24px;
|
||||||
|
--yc-dialog-radius-confirm: 12px;
|
||||||
|
--yc-dialog-max-width-s: 480px;
|
||||||
|
--yc-dialog-max-width-m: 640px;
|
||||||
|
--yc-dialog-max-width-l: 960px;
|
||||||
|
--yc-dialog-max-height: calc(100vh - 160px);
|
||||||
|
--yc-dialog-overlay: rgba(0, 0, 0, 0.15);
|
||||||
|
--yc-dialog-shadow: var(--yc-shadow-dialog);
|
||||||
|
|
||||||
|
/* Popover */
|
||||||
|
--yc-popover-bg: #ffffff;
|
||||||
|
--yc-popover-border: #dedede;
|
||||||
|
--yc-popover-radius: 16px;
|
||||||
|
--yc-popover-padding: 8px;
|
||||||
|
--yc-popover-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-popover-shadow: var(--yc-shadow-popover);
|
||||||
|
|
||||||
|
/* Segmented */
|
||||||
|
--yc-segmented-track-padding: 2px;
|
||||||
|
--yc-segmented-track-radius: 8px;
|
||||||
|
--yc-segmented-track-bg: #f2f2f2;
|
||||||
|
--yc-segmented-item-gap: 4px;
|
||||||
|
--yc-segmented-item-radius: 6px;
|
||||||
|
--yc-segmented-item-height: 32px;
|
||||||
|
--yc-segmented-item-padding-x: 12px;
|
||||||
|
--yc-segmented-item-font-size: var(--yc-font-size-5);
|
||||||
|
--yc-segmented-item-line-height: var(--yc-line-height-5-2);
|
||||||
|
--yc-segmented-item-fg: rgba(0, 0, 0, 0.7);
|
||||||
|
--yc-segmented-item-fg-hover: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-segmented-item-fg-active: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-segmented-item-fg-disabled: rgba(0, 0, 0, 0.3);
|
||||||
|
--yc-segmented-item-bg-hover: #e6e6e6;
|
||||||
|
--yc-segmented-thumb-bg: #ffffff;
|
||||||
|
--yc-segmented-thumb-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
--yc-segmented-item-weight: 400;
|
||||||
|
--yc-segmented-item-weight-active: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme='dark'] {
|
||||||
|
--yc-button-primary-bg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-button-primary-bg-hover: rgba(255, 255, 255, 0.75);
|
||||||
|
--yc-button-primary-bg-active: rgba(255, 255, 255, 0.75);
|
||||||
|
--yc-button-primary-bg-disabled: rgba(255, 255, 255, 0.2);
|
||||||
|
--yc-button-primary-fg: rgba(0, 0, 0, 0.9);
|
||||||
|
--yc-button-primary-fg-disabled: rgba(0, 0, 0, 0.9);
|
||||||
|
|
||||||
|
--yc-button-secondary-bg: #262626;
|
||||||
|
--yc-button-secondary-bg-hover: #2e2e2e;
|
||||||
|
--yc-button-secondary-bg-active: #2e2e2e;
|
||||||
|
--yc-button-secondary-bg-disabled: #262626;
|
||||||
|
--yc-button-secondary-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-button-secondary-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-button-secondary-border: #3d3d3d;
|
||||||
|
--yc-button-secondary-border-disabled: #3a3a3a;
|
||||||
|
|
||||||
|
--yc-button-grey-bg: #383838;
|
||||||
|
--yc-button-grey-bg-hover: #404040;
|
||||||
|
--yc-button-grey-bg-active: #404040;
|
||||||
|
--yc-button-grey-bg-disabled: #404040;
|
||||||
|
--yc-button-grey-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-button-grey-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
|
--yc-button-ghost-bg-hover: rgba(255, 255, 255, 0.1);
|
||||||
|
--yc-button-ghost-bg-active: rgba(255, 255, 255, 0.1);
|
||||||
|
--yc-button-ghost-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-button-ghost-fg-hover: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-button-ghost-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
|
--yc-button-link-fg: #46a8f0;
|
||||||
|
--yc-button-link-fg-hover: #5ea9f2;
|
||||||
|
--yc-button-link-fg-disabled: #94b7d1;
|
||||||
|
|
||||||
|
--yc-button-danger-bg: #af191a;
|
||||||
|
--yc-button-danger-bg-hover: #a31717;
|
||||||
|
--yc-button-danger-bg-active: #a31717;
|
||||||
|
--yc-button-danger-bg-disabled: #803838;
|
||||||
|
--yc-button-danger-fg-disabled: rgba(255, 255, 255, 0.7);
|
||||||
|
|
||||||
|
--yc-focus-ring-color: rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
|
--yc-input-bg: #242424;
|
||||||
|
--yc-input-bg-filled: #262626;
|
||||||
|
--yc-input-bg-disabled: #171717;
|
||||||
|
--yc-input-border: #454545;
|
||||||
|
--yc-input-border-hover: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-input-border-focus: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-input-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-input-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-input-placeholder: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-input-icon: rgba(255, 255, 255, 0.5);
|
||||||
|
--yc-input-icon-hover: rgba(255, 255, 255, 0.7);
|
||||||
|
--yc-input-icon-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
|
--yc-switch-track-bg: #3c3c3c;
|
||||||
|
--yc-switch-track-bg-disabled: #3c3c3c;
|
||||||
|
--yc-switch-track-bg-checked: #22cba8;
|
||||||
|
--yc-switch-track-bg-checked-hover: #40d1b3;
|
||||||
|
--yc-switch-track-bg-checked-disabled: rgba(61, 217, 182, 0.35);
|
||||||
|
--yc-switch-track-border: rgba(255, 255, 255, 0.14);
|
||||||
|
--yc-switch-thumb-bg: #ffffff;
|
||||||
|
--yc-switch-thumb-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||||
|
|
||||||
|
--yc-select-bg: #242424;
|
||||||
|
--yc-select-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-select-placeholder: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-select-border: #454545;
|
||||||
|
--yc-select-border-hover: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-select-border-open: rgba(255, 255, 255, 0.5);
|
||||||
|
--yc-select-bg-disabled: #171717;
|
||||||
|
--yc-select-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
|
||||||
|
--yc-dialog-bg: #1f1f1f;
|
||||||
|
--yc-dialog-border: #3d3d3d;
|
||||||
|
--yc-dialog-overlay: rgba(0, 0, 0, 0.4);
|
||||||
|
|
||||||
|
--yc-popover-bg: #242424;
|
||||||
|
--yc-popover-border: #3d3d3d;
|
||||||
|
--yc-popover-fg: rgba(255, 255, 255, 0.9);
|
||||||
|
|
||||||
|
--yc-segmented-track-bg: #242424;
|
||||||
|
--yc-segmented-item-fg: rgba(255, 255, 255, 0.7);
|
||||||
|
--yc-segmented-item-fg-hover: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-segmented-item-fg-active: rgba(255, 255, 255, 0.9);
|
||||||
|
--yc-segmented-item-fg-disabled: rgba(255, 255, 255, 0.3);
|
||||||
|
--yc-segmented-item-bg-hover: rgba(255, 255, 255, 0.08);
|
||||||
|
--yc-segmented-thumb-bg: #1f1f1f;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user