feat(release): prepare 1.1.0 candidate

This commit is contained in:
Yun Chan 2026-08-29 18:33:45 +09:00
parent 5a34f66981
commit 5205dcdfa9
736 changed files with 115667 additions and 12203 deletions

View file

@ -4,23 +4,23 @@ import { Led } from './Led'
interface BadgeProps {
children: ReactNode
led?: boolean
ledColor?: 'amber' | 'green' | 'red'
ledColor?: 'blue' | 'green' | 'red'
className?: string
}
export function Badge({ children, led = false, ledColor = 'amber', className = '' }: BadgeProps) {
export function Badge({ children, led = false, ledColor = 'blue', className = '' }: BadgeProps) {
return (
<span
className={`
inline-flex items-center gap-2 px-3 py-1
font-mono text-nano uppercase tracking-widest
text-neutral-400 bg-surface-700/50 border border-white/[0.06]
rounded-sm select-none
text-xs font-medium
text-neutral-300 bg-surface-800/90 border border-white/10
rounded-full shadow-sm select-none
${className}
`}
>
{led && <Led color={ledColor} size="sm" />}
{children}
<span>{children}</span>
</span>
)
}

View file

@ -8,13 +8,13 @@ interface DataPointProps {
export function DataPoint({ label, value, unit, className = '' }: DataPointProps) {
return (
<div className={`flex flex-col ${className}`}>
<span className="font-mono text-nano uppercase tracking-widest text-neutral-500 mb-1">
<span className="text-xs font-normal text-neutral-400 mb-1">
{label}
</span>
<span className="font-display text-2xl md:text-3xl font-bold text-neutral-100 tracking-tight">
<span className="text-2xl sm:text-3xl font-medium text-neutral-50 tracking-tight flex items-baseline">
{value}
{unit && (
<span className="text-sm font-mono text-neutral-500 ml-1">{unit}</span>
<span className="text-xs font-normal text-brand-blue ml-1.5">{unit}</span>
)}
</span>
</div>

View file

@ -5,8 +5,9 @@ interface GlowButtonProps {
href?: string
download?: string
variant?: 'primary' | 'secondary'
size?: 'md' | 'lg'
size?: 'sm' | 'md' | 'lg'
className?: string
onClick?: () => void
}
export function GlowButton({
@ -16,33 +17,34 @@ export function GlowButton({
variant = 'primary',
size = 'md',
className = '',
onClick,
}: GlowButtonProps) {
const base = 'glow-btn inline-flex items-center justify-center font-mono text-sm font-medium tracking-wide uppercase rounded-panel select-none'
const base = 'glow-btn inline-flex items-center justify-center font-medium tracking-normal select-none rounded-xl transition-all duration-200 leading-normal'
const variants = {
primary: 'bg-brand-amber text-white hover:bg-brand-amber-light',
secondary: 'bg-surface-500 text-neutral-200 border border-white/[0.08] hover:border-brand-amber/30',
primary: 'bg-brand-blue text-white hover:bg-brand-blue-light shadow-glow-sm hover:shadow-glow-md active:scale-[0.98]',
secondary: 'bg-surface-700/80 text-neutral-100 border border-white/10 hover:border-brand-blue/40 hover:bg-surface-600 hover:text-white active:scale-[0.98]',
}
const sizes = {
md: 'px-6 py-3 text-xs',
lg: 'px-8 py-4 text-sm',
sm: 'px-4.5 py-2 text-xs',
md: 'px-6 py-2.5 sm:py-3 text-xs sm:text-sm font-medium',
lg: 'px-8 sm:px-10 py-3.5 sm:py-4 text-sm sm:text-base font-medium',
}
const cls = `${base} ${variants[variant]} ${sizes[size]} ${className}`
if (href) {
return (
<a href={href} download={download} className={cls}>
<span className="relative z-10">{children}</span>
<a href={href} download={download} onClick={onClick} className={cls}>
<span className="relative z-10 flex items-center gap-2.5">{children}</span>
</a>
)
}
return (
<button className={cls}>
<span className="relative z-10">{children}</span>
<button type="button" onClick={onClick} className={cls}>
<span className="relative z-10 flex items-center gap-2.5">{children}</span>
</button>
)
}

View file

@ -5,16 +5,15 @@ interface InstrumentCardProps {
className?: string
hover?: boolean
}
export function InstrumentCard({ children, className = '', hover = true }: InstrumentCardProps) {
return (
<div
className={`
relative noise-texture
bg-surface-600 border border-white/[0.06]
rounded-card shadow-chassis
p-5 md:p-6
${hover ? 'transition-all duration-250 hover:border-brand-amber/20 hover:shadow-glow-sm' : ''}
bg-surface-800/80 border border-white/10
rounded-2xl shadow-glass-card
p-6 md:p-7 backdrop-blur-xl
${hover ? 'transition-all duration-300 hover:border-brand-blue/35 hover:bg-surface-700/85 hover:shadow-glow-sm' : ''}
${className}
`}
>

View file

@ -21,32 +21,34 @@ export function LanguageSwitcher() {
return (
<div ref={ref} className="relative">
<button
type="button"
onClick={() => setOpen(!open)}
className="flex items-center gap-1.5 px-2.5 py-1.5 font-mono text-nano uppercase tracking-widest text-neutral-400 hover:text-white border border-white/[0.06] rounded-panel transition-colors"
className="flex items-center gap-2 px-3 py-1.5 text-xs font-medium text-neutral-300 hover:text-white bg-surface-800/80 hover:bg-surface-700 border border-white/10 hover:border-brand-blue/40 rounded-lg transition-all shadow-sm"
aria-label="Change language"
>
<GlobeIcon />
{current?.label ?? 'EN'}
<span>{current?.label ?? 'EN'}</span>
<ChevronIcon open={open} />
</button>
{open && (
<div className="absolute right-0 top-full mt-2 w-40 py-1 bg-surface-700 border border-white/[0.08] rounded-card shadow-lg z-50 max-h-80 overflow-y-auto">
<div className="absolute right-0 top-full mt-2 w-44 py-1.5 bg-surface-800/95 backdrop-blur-2xl border border-white/10 rounded-xl shadow-2xl z-50 max-h-80 overflow-y-auto">
{LOCALES.map((l) => (
<button
key={l.code}
type="button"
onClick={() => {
setLocale(l.code)
setOpen(false)
}}
className={`w-full text-left px-3 py-2 font-mono text-xs flex items-center justify-between transition-colors ${
className={`w-full text-left px-3.5 py-2 text-xs flex items-center justify-between transition-colors ${
l.code === locale
? 'text-brand-amber bg-brand-amber/[0.08]'
: 'text-neutral-400 hover:text-white hover:bg-surface-600'
? 'text-brand-blue bg-brand-blue/10 font-medium'
: 'text-neutral-300 hover:text-white hover:bg-surface-700/80 font-normal'
}`}
>
<span>{l.nativeName}</span>
<span className="text-nano text-neutral-600 uppercase">{l.label}</span>
<span className="text-[11px] text-neutral-400 font-normal">{l.label}</span>
</button>
))}
</div>
@ -57,7 +59,7 @@ export function LanguageSwitcher() {
function GlobeIcon() {
return (
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<svg className="w-3.5 h-3.5 text-brand-blue" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M2 12h20" />
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
@ -68,7 +70,7 @@ function GlobeIcon() {
function ChevronIcon({ open }: { open: boolean }) {
return (
<svg
className={`w-3 h-3 transition-transform ${open ? 'rotate-180' : ''}`}
className={`w-3 h-3 text-neutral-400 transition-transform ${open ? 'rotate-180' : ''}`}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"

View file

@ -1,14 +1,14 @@
interface LedProps {
color?: 'amber' | 'green' | 'red'
color?: 'blue' | 'green' | 'red'
pulse?: boolean
size?: 'sm' | 'md'
className?: string
}
const colorMap = {
amber: {
bg: 'bg-brand-amber',
shadow: 'shadow-[0_0_6px_rgba(242,91,41,0.8)]',
blue: {
bg: 'bg-brand-blue',
shadow: 'shadow-[0_0_6px_rgba(59,130,246,0.8)]',
},
green: {
bg: 'bg-emerald-400',
@ -25,7 +25,7 @@ const sizeMap = {
md: 'w-2 h-2',
} as const
export function Led({ color = 'amber', pulse = false, size = 'sm', className = '' }: LedProps) {
export function Led({ color = 'blue', pulse = false, size = 'sm', className = '' }: LedProps) {
const c = colorMap[color]
const s = sizeMap[size]
return (

View file

@ -8,21 +8,22 @@ interface SectionHeaderProps {
export function SectionHeader({ index, title, subtitle, className = '' }: SectionHeaderProps) {
return (
<div className={`mb-12 md:mb-16 ${className}`}>
<div className="flex items-center gap-4 mb-4">
<span className="font-mono text-nano uppercase tracking-widest text-brand-amber">
<div className="flex items-center gap-3 mb-3.5">
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-medium text-brand-blue bg-brand-blue/10 border border-brand-blue/25 shadow-sm">
<span className="w-1.5 h-1.5 rounded-full bg-brand-blue" />
{index}
</span>
<div className="h-px flex-1 bg-white/[0.06]" />
<div className="h-px flex-1 bg-gradient-to-r from-brand-blue/20 via-white/[0.08] to-transparent" />
</div>
<h2
className="font-display text-display font-bold text-neutral-50 tracking-tight break-keep"
className="text-2xl sm:text-3xl md:text-4xl font-medium text-neutral-50 tracking-tight leading-[1.22] break-keep"
style={{ wordBreak: 'keep-all', overflowWrap: 'break-word' }}
>
{title}
</h2>
{subtitle && (
<p
className="mt-3 max-w-xl text-base text-neutral-400 leading-relaxed break-keep"
className="mt-3 max-w-2xl text-sm sm:text-base text-neutral-300 leading-relaxed font-normal break-keep"
style={{ wordBreak: 'keep-all', overflowWrap: 'break-word' }}
>
{subtitle}

View file

@ -38,7 +38,7 @@ export function WaveBars({ className = '' }: WaveBarsProps) {
<div
key={i}
ref={(el) => { barsRef.current[i] = el }}
className="w-[3px] rounded-full bg-brand-amber/60"
className="w-[3px] rounded-full bg-brand-blue/60"
style={{ height: 4, transition: 'height 60ms ease-out' }}
/>
))}