2026-01-22 16:23:11 +00:00
|
|
|
import * as React from 'react';
|
|
|
|
|
import { cn } from '@/lib/utils';
|
|
|
|
|
import { useId } from 'react';
|
|
|
|
|
|
|
|
|
|
export interface FloatingInputProps
|
|
|
|
|
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
|
|
|
label: string;
|
|
|
|
|
error?: string;
|
|
|
|
|
icon?: React.ReactNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FloatingInput = React.forwardRef<HTMLInputElement, FloatingInputProps>(
|
|
|
|
|
({ className, label, error, icon, type, id, ...props }, ref) => {
|
|
|
|
|
const generatedId = useId();
|
|
|
|
|
const inputId = id || generatedId;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="relative group w-full mb-5">
|
|
|
|
|
<div className="relative">
|
|
|
|
|
<input
|
|
|
|
|
type={type}
|
|
|
|
|
id={inputId}
|
|
|
|
|
className={cn(
|
feat(web): UI premium Discord/Spotify-like — tokens, shadows, focus, layout
Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y):
- Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source
for layout/shell (index.css), shadows (design-system.css), durations/easing.
- Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height
(max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500
replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes.
- Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls,
AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item,
TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable.
- ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary.
- Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts.
- Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories.
- .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification.
- apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 16:15:58 +00:00
|
|
|
"block px-4 pb-2.5 pt-5 w-full text-sm text-white bg-kodo-graphite/40 rounded-xl border appearance-none focus:outline-none focus:ring-0 peer transition-all duration-[var(--duration-fast)]",
|
2026-01-22 16:23:11 +00:00
|
|
|
// Borders & Colors
|
|
|
|
|
error
|
|
|
|
|
? "border-kodo-red focus:border-kodo-red"
|
|
|
|
|
: "border-white/10 hover:border-white/20 focus:border-kodo-cyan",
|
|
|
|
|
// Glassmorphism
|
|
|
|
|
"backdrop-blur-sm",
|
|
|
|
|
icon ? "pl-11" : "",
|
|
|
|
|
className
|
|
|
|
|
)}
|
|
|
|
|
placeholder=" "
|
|
|
|
|
ref={ref}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* Icon */}
|
|
|
|
|
{icon && (
|
feat(web): UI premium Discord/Spotify-like — tokens, shadows, focus, layout
Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y):
- Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source
for layout/shell (index.css), shadows (design-system.css), durations/easing.
- Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height
(max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500
replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes.
- Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls,
AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item,
TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable.
- ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary.
- Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts.
- Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories.
- .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification.
- apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 16:15:58 +00:00
|
|
|
<div className="absolute left-3.5 top-1/2 -translate-y-1/2 text-kodo-text-dim peer-focus:text-kodo-cyan transition-colors duration-[var(--duration-fast)] pointer-events-none">
|
2026-01-22 16:23:11 +00:00
|
|
|
{icon}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Floating Label */}
|
|
|
|
|
<label
|
|
|
|
|
htmlFor={inputId}
|
|
|
|
|
className={cn(
|
feat(web): UI premium Discord/Spotify-like — tokens, shadows, focus, layout
Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y):
- Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source
for layout/shell (index.css), shadows (design-system.css), durations/easing.
- Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height
(max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500
replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes.
- Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls,
AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item,
TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable.
- ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary.
- Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts.
- Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories.
- .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification.
- apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 16:15:58 +00:00
|
|
|
"absolute text-sm duration-[var(--duration-fast)] transform -translate-y-3 scale-75 top-4 z-10 origin-[0] peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-3 pointer-events-none transition-transform",
|
2026-01-22 16:23:11 +00:00
|
|
|
icon ? "left-11 peer-focus:left-11 peer-placeholder-shown:left-11" : "left-4 peer-focus:left-4 peer-placeholder-shown:left-4",
|
|
|
|
|
error
|
|
|
|
|
? "text-kodo-red"
|
|
|
|
|
: "text-kodo-text-dim peer-focus:text-kodo-cyan group-hover:text-white/70"
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
{label}
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Error Message */}
|
|
|
|
|
{error && (
|
|
|
|
|
<p className="mt-1 text-xs text-kodo-red animate-slideDown">
|
|
|
|
|
{error}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
FloatingInput.displayName = 'FloatingInput';
|
|
|
|
|
|
|
|
|
|
export { FloatingInput };
|