glass-ui
componentbuttonsource: ok · hit
Button
Displays a button or a component that looks like a button with glassy variants.
npx shadcn add "https://glass-ui.crenspire.com/r/button.json"free
Visual style
glass-blur
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightui-primitives@radix-ui/react-slot
Registry dependencies
button
Files5 · source cached 10/9/2026, 2:02:33 AM
lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
lib/glass-utils.ts
/**
* Glassmorphism customization utilities
* Allows users to customize color, transparency, blur, and outline for glass effects
*/
export interface GlassCustomization {
/**
* Background color for the glass effect (e.g., "rgba(255, 255, 255, 0.1)" or "#ffffff")
* Default: uses CSS variable --glass-bg
*/
color?: string
/**
* Transparency/opacity for the background (0-1)
* If provided, will override the alpha channel in color
*/
transparency?: number
/**
* Blur amount in pixels
* Default: uses CSS variable --blur (20px)
*/
blur?: number | string
/**
* Border/outline color (e.g., "rgba(255, 255, 255, 0.25)" or "#ffffff")
* Default: uses CSS variable --glass-border
*/
outline?: string
/**
* Border/outline width in pixels
* Default: 1px
*/
outlineWidth?: number | string
/**
* Shadow for the glass effect
* Default: uses CSS variable --glass-shadow
*/
shadow?: string
/**
* Inner glow color and intensity (e.g., "rgba(255, 255, 255, 0.2)")
* Creates an inset shadow for a glowing effect inside the element
*/
innerGlow?: string
/**
* Inner glow blur/spread radius in pixels
* Default: 20px
*/
innerGlowBlur?: number | string
}
/**
* Converts glass customization props to CSS style object
*/
export function getGlassStyles(customization?: GlassCustomization): React.CSSProperties {
if (!customization) return {}
const styles: React.CSSProperties = {}
// Handle background color and transparency
if (customization.color || customization.transparency !== undefined) {
let bgColor = customization.color || 'rgba(255, 255, 255, 0.1)'
// If transparency is provided, adjust the alpha channel
if (customization.transparency !== undefined) {
// Extract RGB from color string if it's rgba/rgb
const rgbaMatch = bgColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/)
if (rgbaMatch) {
const [, r, g, b] = rgbaMatch
bgColor = `rgba(${r}, ${g}, ${b}, ${customization.transparency})`
} else if (bgColor.startsWith('#')) {
// Convert hex to rgba
const hex = bgColor.replace('#', '')
const r = parseInt(hex.substring(0, 2), 16)
const g = parseInt(hex.substring(2, 4), 16)
const b = parseInt(hex.substring(4, 6), 16)
bgColor = `rgba(${r}, ${g}, ${b}, ${customization.transparency})`
} else {
// Fallback: append transparency
bgColor = `${bgColor}${customization.transparency}`
}
}
styles.backgroundColor = bgColor
}
// Handle blur
if (customization.blur !== undefined) {
const blurValue = typeof customization.blur === 'number'
? `${customization.blur}px`
: customization.blur
styles.backdropFilter = `blur(${blurValue})`
styles.WebkitBackdropFilter = `blur(${blurValue})` // Safari support
}
// Handle outline/border - always apply border for glassmorphism effect
if (customization.outline !== undefined) {
const width = customization.outlineWidth || '1px'
styles.borderColor = customization.outline
styles.borderWidth = typeof width === 'number' ? `${width}px` : width
styles.borderStyle = 'solid'
} else if (!customization.outline && (customization.color || customization.transparency !== undefined || customization.blur !== undefined)) {
// Apply default border if glass customization is provided but outline is not
styles.borderColor = 'rgba(255, 255, 255, 0.3)'
styles.borderWidth = '1px'
styles.borderStyle = 'solid'
}
// Handle shadow and inner glow - combine both if provided
const shadows: string[] = []
// Add outer shadow
if (customization.shadow !== undefined) {
shadows.push(customization.shadow)
} else if (customization.color || customization.transparency !== undefined || customization.blur !== undefined) {
// Apply default glass shadow for depth
shadows.push('0 8px 32px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.05)')
}
// Add inner glow as inset shadow
if (customization.innerGlow !== undefined) {
const glowBlur = customization.innerGlowBlur !== undefined
? (typeof customization.innerGlowBlur === 'number' ? `${customization.innerGlowBlur}px` : customization.innerGlowBlur)
: '20px'
shadows.push(`inset 0 0 ${glowBlur} ${customization.innerGlow}`)
}
if (shadows.length > 0) {
styles.boxShadow = shadows.join(', ')
}
return styles
}
/**
* Generates CSS custom properties for glass customization
* Useful for components that need to pass styles to child elements
*/
export function getGlassCSSVars(customization?: GlassCustomization): Record<string, string> {
if (!customization) return {}
const vars: Record<string, string> = {}
if (customization.color || customization.transparency !== undefined) {
let bgColor = customization.color || 'rgba(255, 255, 255, 0.1)'
if (customization.transparency !== undefined) {
const rgbaMatch = bgColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/)
if (rgbaMatch) {
const [, r, g, b] = rgbaMatch
bgColor = `rgba(${r}, ${g}, ${b}, ${customization.transparency})`
} else if (bgColor.startsWith('#')) {
const hex = bgColor.replace('#', '')
const r = parseInt(hex.substring(0, 2), 16)
const g = parseInt(hex.substring(2, 4), 16)
const b = parseInt(hex.substring(4, 6), 16)
bgColor = `rgba(${r}, ${g}, ${b}, ${customization.transparency})`
}
}
vars['--glass-bg-custom'] = bgColor
}
if (customization.blur !== undefined) {
const blurValue = typeof customization.blur === 'number'
? `${customization.blur}px`
: customization.blur
vars['--blur-custom'] = blurValue
}
if (customization.outline !== undefined) {
vars['--glass-border-custom'] = customization.outline
}
if (customization.outlineWidth !== undefined) {
const width = typeof customization.outlineWidth === 'number'
? `${customization.outlineWidth}px`
: customization.outlineWidth
vars['--glass-border-width-custom'] = width
}
if (customization.shadow !== undefined) {
vars['--glass-shadow-custom'] = customization.shadow
}
if (customization.innerGlow !== undefined) {
vars['--glass-inner-glow-custom'] = customization.innerGlow
}
if (customization.innerGlowBlur !== undefined) {
const blurValue = typeof customization.innerGlowBlur === 'number'
? `${customization.innerGlowBlur}px`
: customization.innerGlowBlur
vars['--glass-inner-glow-blur-custom'] = blurValue
}
return vars
}
lib/hover-effects.ts
import { cva } from "class-variance-authority"
/**
* Shared hover effect variants for all Glass UI components
*
* Effects:
* - none: No hover effect
* - glow: Purple glow shadow that intensifies on hover
* - shimmer: Moving shimmer effect across the component
* - ripple: Ripple effect that scales outward on hover
* - lift: Subtle lift effect with shadow increase
* - scale: Scale up slightly on hover
*/
export const hoverEffects = cva(
"transition-all duration-300",
{
variants: {
hover: {
none: "",
glow: "shadow-lg shadow-purple-500/50 hover:shadow-xl hover:shadow-purple-500/70",
shimmer: "relative overflow-hidden before:absolute before:inset-0 before:-translate-x-full before:bg-gradient-to-r before:from-transparent before:via-white/20 before:to-transparent hover:before:translate-x-full before:transition-transform before:duration-1000",
ripple: "relative overflow-hidden after:absolute after:inset-0 after:scale-0 after:rounded-full after:bg-white/30 after:transition-transform after:duration-500 hover:after:scale-150",
lift: "hover:-translate-y-1 hover:shadow-lg",
scale: "hover:scale-105",
},
},
defaultVariants: {
hover: "none",
},
}
)
export type HoverEffect = "none" | "glow" | "shimmer" | "ripple" | "lift" | "scale"
app/globals.css
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-glass: var(--glass-shadow);
}
:root {
--radius: 0.625rem;
/* Base colors - Light mode with dark text */
--background: transparent;
--foreground: oklch(0.15 0 0); /* Near black - dark text for light mode */
--card: transparent;
--card-foreground: oklch(0.15 0 0); /* Near black - dark text */
--popover: transparent;
--popover-foreground: oklch(0.15 0 0); /* Near black - dark text */
/* Primary colors - Light mode */
--primary: oklch(0.5 0.2 250); /* Blue */
--primary-foreground: oklch(0.98 0 0); /* White text on primary */
/* Secondary colors - Light mode */
--secondary: oklch(0.96 0 0); /* Very light gray */
--secondary-foreground: oklch(0.15 0 0); /* Dark text */
/* Muted colors - Light mode */
--muted: oklch(0.85 0 0); /* Dark gray - darker shade to avoid glass effect override */
--muted-foreground: oklch(0.1 0 0); /* Medium gray text */
/* Accent colors - Light mode */
--accent: oklch(0.96 0 0); /* Very light gray */
--accent-foreground: oklch(0.15 0 0); /* Dark text */
/* Destructive colors - WCAG AA compliant (4.5:1 contrast) */
--destructive: oklch(0.55 0.22 25); /* Red - 4.5:1 with white */
--destructive-foreground: oklch(0.98 0 0); /* White text on red */
/* Border and input - WCAG AA compliant (3:1 for UI components) */
--border: oklch(0.88 0 0); /* Light gray - 3:1 contrast */
--input: oklch(0.88 0 0); /* Light gray - 3:1 contrast */
--ring: oklch(0.5 0.2 250); /* Blue ring - 3:1 contrast */
/* Chart colors - WCAG AA compliant */
--chart-1: oklch(0.6 0.2 250); /* Blue */
--chart-2: oklch(0.55 0.15 150); /* Green */
--chart-3: oklch(0.5 0.2 50); /* Yellow */
--chart-4: oklch(0.65 0.2 300); /* Purple */
--chart-5: oklch(0.6 0.2 20); /* Orange */
/* Sidebar colors - Light mode */
--sidebar: oklch(0.98 0 0); /* Near white */
--sidebar-foreground: oklch(0.15 0 0); /* Dark text */
--sidebar-primary: oklch(0.5 0.2 250); /* Blue */
--sidebar-primary-foreground: oklch(0.98 0 0); /* White text on primary */
--sidebar-accent: oklch(0.96 0 0); /* Very light gray */
--sidebar-accent-foreground: oklch(0.15 0 0); /* Dark text */
--sidebar-border: oklch(0.88 0 0); /* Light gray - 3:1 contrast */
--sidebar-ring: oklch(0.5 0.2 250); /* Blue ring - 3:1 contrast */
/* Apple-standard glassmorphism - Very subtle and refined */
/* Low opacity for Apple's standard glass effect */
--glass-bg: linear-gradient(135deg,
rgba(255, 255, 255, 0.15) 0%,
rgba(255, 255, 255, 0.12) 25%,
rgba(240, 248, 255, 0.13) 50%,
rgba(255, 255, 255, 0.11) 75%,
rgba(230, 240, 255, 0.12) 100%
);
/* Very subtle white border - Apple standard */
--glass-border: rgba(255, 255, 255, 0.12);
/* Minimal shadows with subtle inner glow - Apple standard */
--glass-shadow:
0 4px 16px rgba(0, 0, 0, 0.08),
0 1px 4px rgba(0, 0, 0, 0.04),
0 0 0 0.5px rgba(255, 255, 255, 0.08) inset,
0 0 12px rgba(255, 255, 255, 0.1) inset;
--glass-shadow-lg:
0 8px 32px rgba(0, 0, 0, 0.1),
0 2px 8px rgba(0, 0, 0, 0.06),
0 0 0 0.5px rgba(255, 255, 255, 0.1) inset,
0 0 20px rgba(255, 255, 255, 0.12) inset;
--glass-shadow-sm:
0 2px 8px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.03),
0 0 0 0.5px rgba(255, 255, 255, 0.06) inset,
0 0 8px rgba(255, 255, 255, 0.08) inset;
--gradient: linear-gradient(135deg, #a855f7 0%, #3b82f6 100%);
/* Apple-standard blur values - moderate blur */
--blur: 10px;
--blur-sm: 10px;
--blur-lg: 10px;
/* Frosted glass variant - Enhanced opacity and stronger blur */
--glass-frosted-bg: linear-gradient(135deg,
rgba(255, 255, 255, 0.25) 0%,
rgba(255, 255, 255, 0.22) 25%,
rgba(240, 248, 255, 0.23) 50%,
rgba(255, 255, 255, 0.21) 75%,
rgba(230, 240, 255, 0.22) 100%
);
--glass-frosted-border: rgba(255, 255, 255, 0.3);
--glass-frosted-shadow:
0 8px 32px rgba(0, 0, 0, 0.12),
0 2px 8px rgba(0, 0, 0, 0.08),
0 0 0 0.5px rgba(255, 255, 255, 0.15) inset,
0 0 20px rgba(255, 255, 255, 0.18) inset;
--blur-frosted: 25px;
/* Fluted glass variant - Vertical ridges pattern */
--glass-fluted-pattern: repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.08) 0px,
rgba(255, 255, 255, 0.15) 4px,
rgba(255, 255, 255, 0.08) 8px,
rgba(255, 255, 255, 0.02) 10px,
rgba(255, 255, 255, 0.08) 12px
);
/* Crystal glass variant - Clear glass with highlights and glow */
--glass-crystal-bg: rgba(255, 255, 255, 0.3);
--glass-crystal-border: rgba(255, 255, 255, 0.3);
--glass-crystal-shadow:
0 0 20px rgba(0, 0, 0, 0.2),
0 0 30px rgba(255, 255, 255, 0.1);
--glass-crystal-shadow-hover:
0 0 25px rgba(0, 0, 0, 0.3),
0 0 35px rgba(255, 255, 255, 0.15);
--blur-crystal: 2px;
}
.dark {
/* Apple-standard glassmorphism for dark mode - Very subtle and refined */
/* Very low opacity for Apple's standard glass effect in dark mode */
--glass-bg: linear-gradient(135deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0.06) 25%,
rgba(240, 248, 255, 0.07) 50%,
rgba(255, 255, 255, 0.05) 75%,
rgba(230, 240, 255, 0.06) 100%
);
/* Very subtle white border - Apple standard */
--glass-border: rgba(255, 255, 255, 0.15);
/* Minimal shadows with subtle inner glow - Apple standard for dark mode */
--glass-shadow:
0 4px 16px rgba(0, 0, 0, 0.3),
0 1px 4px rgba(0, 0, 0, 0.15),
0 0 0 0.5px rgba(255, 255, 255, 0.12) inset,
0 0 12px rgba(255, 255, 255, 0.15) inset;
--glass-shadow-lg:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
0 0 0 0.5px rgba(255, 255, 255, 0.15) inset,
0 0 20px rgba(255, 255, 255, 0.18) inset;
--glass-shadow-sm:
0 2px 8px rgba(0, 0, 0, 0.25),
0 1px 2px rgba(0, 0, 0, 0.12),
0 0 0 0.5px rgba(255, 255, 255, 0.1) inset,
0 0 8px rgba(255, 255, 255, 0.12) inset;
/* Frosted glass variant - Enhanced opacity and stronger blur for dark mode */
--glass-frosted-bg: linear-gradient(135deg,
rgba(255, 255, 255, 0.15) 0%,
rgba(255, 255, 255, 0.12) 25%,
rgba(240, 248, 255, 0.13) 50%,
rgba(255, 255, 255, 0.11) 75%,
rgba(230, 240, 255, 0.12) 100%
);
--glass-frosted-border: rgba(255, 255, 255, 0.25);
--glass-frosted-shadow:
0 8px 32px rgba(0, 0, 0, 0.5),
0 2px 8px rgba(0, 0, 0, 0.3),
0 0 0 0.5px rgba(255, 255, 255, 0.2) inset,
0 0 20px rgba(255, 255, 255, 0.22) inset;
/* Fluted glass variant - Vertical ridges pattern for dark mode */
--glass-fluted-pattern: repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.05) 0px,
rgba(255, 255, 255, 0.12) 4px,
rgba(255, 255, 255, 0.05) 8px,
rgba(255, 255, 255, 0.01) 10px,
rgba(255, 255, 255, 0.05) 12px
);
/* Crystal glass variant - Clear glass with highlights and glow for dark mode */
--glass-crystal-bg: rgba(255, 255, 255, 0.1);
--glass-crystal-border: rgba(255, 255, 255, 0.3);
--glass-crystal-shadow:
0 0 20px rgba(0, 0, 0, 0.4),
0 0 30px rgba(255, 255, 255, 0.15);
--glass-crystal-shadow-hover:
0 0 25px rgba(0, 0, 0, 0.5),
0 0 35px rgba(255, 255, 255, 0.2);
/* Base colors - Apple-style white text */
--background: transparent;
--foreground: oklch(1 0 0); /* White - Apple-style */
--card: transparent;
--card-foreground: oklch(1 0 0); /* White - Apple-style */
--popover: transparent;
--popover-foreground: oklch(1 0 0); /* White - Apple-style */
/* Primary colors - Apple-style white text */
--primary: oklch(0.7 0.15 250); /* Light blue */
--primary-foreground: oklch(1 0 0); /* White - Apple-style */
/* Secondary colors - Apple-style white text */
--secondary: oklch(0.25 0 0); /* Dark gray */
--secondary-foreground: oklch(1 0 0); /* White - Apple-style */
/* Muted colors - Apple-style white text */
--muted: oklch(0.18 0 0); /* Darker gray - darker shade to avoid glass effect override */
--muted-foreground: oklch(1 0 0); /* White - Apple-style */
/* Accent colors - Apple-style white text */
--accent: oklch(0.25 0 0); /* Dark gray */
--accent-foreground: oklch(1 0 0); /* White - Apple-style */
/* Destructive colors - WCAG AA compliant (4.5:1 contrast) */
--destructive: oklch(0.65 0.22 25); /* Light red - 4.5:1 with dark background */
--destructive-foreground: oklch(0.12 0 0); /* Near black text on red */
/* Border and input - WCAG AA compliant (3:1 for UI components) */
--border: oklch(0.3 0 0); /* Medium gray - 3:1 contrast */
--input: oklch(0.25 0 0); /* Dark gray - 3:1 contrast */
--ring: oklch(0.6 0.2 250); /* Light blue ring - 3:1 contrast */
/* Chart colors - WCAG AA compliant */
--chart-1: oklch(0.65 0.2 250); /* Light blue */
--chart-2: oklch(0.7 0.15 150); /* Light green */
--chart-3: oklch(0.75 0.2 50); /* Light yellow */
--chart-4: oklch(0.7 0.2 300); /* Light purple */
--chart-5: oklch(0.68 0.2 20); /* Light orange */
/* Sidebar colors - Apple-style white text */
--sidebar: oklch(0.18 0 0); /* Dark gray */
--sidebar-foreground: oklch(1 0 0); /* White - Apple-style */
--sidebar-primary: oklch(0.7 0.15 250); /* Light blue */
--sidebar-primary-foreground: oklch(1 0 0); /* White - Apple-style */
--sidebar-accent: oklch(0.25 0 0); /* Dark gray */
--sidebar-accent-foreground: oklch(1 0 0); /* White - Apple-style */
--sidebar-border: oklch(0.3 0 0); /* Medium gray - 3:1 contrast */
--sidebar-ring: oklch(0.6 0.2 250); /* Light blue ring - 3:1 contrast */
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply text-foreground;
background-color: transparent;
}
}
@layer utilities {
/* Apple-standard glass utility - Very subtle and refined */
/* This creates Apple's standard glassmorphism with moderate blur */
.glass-bg {
/* Low opacity gradient background - Apple standard */
background-image: var(--glass-bg);
background-color: transparent;
/* Moderate backdrop blur - Apple standard (20px) */
backdrop-filter: blur(var(--blur)) saturate(180%);
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%);
/* Very subtle white border - Apple standard */
border: 0.5px solid var(--glass-border);
/* Minimal shadow with subtle inner glow - Apple standard */
box-shadow: var(--glass-shadow);
}
/* Frosted glass utility - Enhanced blur and higher opacity */
.glass-frosted {
background-image: var(--glass-frosted-bg) !important;
background-color: transparent !important;
/* Stronger backdrop blur for frosted effect */
backdrop-filter: blur(var(--blur-frosted)) saturate(200%) !important;
-webkit-backdrop-filter: blur(var(--blur-frosted)) saturate(200%) !important;
/* More pronounced border */
border: 0.5px solid var(--glass-frosted-border) !important;
/* Enhanced shadow for depth */
box-shadow: var(--glass-frosted-shadow) !important;
}
/* Fluted glass utility - Vertical ridges with glass effect */
.glass-fluted {
/* Base glass background combined with fluted pattern */
background-image: var(--glass-fluted-pattern), var(--glass-bg) !important;
background-color: transparent !important;
/* Moderate backdrop blur like standard glass */
backdrop-filter: blur(var(--blur)) saturate(180%) !important;
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%) !important;
/* Standard glass border */
border: 0.5px solid var(--glass-border) !important;
/* Standard glass shadow */
box-shadow: var(--glass-shadow) !important;
}
/* Crystal glass utility - Clear glass with highlights and glow */
.glass-crystal {
position: relative;
background-color: var(--glass-crystal-bg) !important;
/* Minimal backdrop blur for clarity */
backdrop-filter: blur(var(--blur-crystal)) !important;
-webkit-backdrop-filter: blur(var(--blur-crystal)) !important;
border: 1px solid var(--glass-crystal-border) !important;
box-shadow: var(--glass-crystal-shadow) !important;
transition: all 0.3s ease !important;
/* Top highlight gradient */
background-image: linear-gradient(to bottom right, rgba(255, 255, 255, 0.15), transparent 50%) !important;
background-size: 200% 200% !important;
}
.glass-crystal::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.4), transparent);
opacity: 0.7;
pointer-events: none;
height: 30%;
}
.glass-crystal::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: radial-gradient(circle at 50% 120%, rgba(255, 255, 255, 0.2), transparent 70%);
opacity: 0.8;
pointer-events: none;
}
.glass-crystal:hover {
box-shadow: var(--glass-crystal-shadow-hover) !important;
background-position: 100% 100% !important;
}
/* Ensure react-day-picker doesn't override glass effect */
.glass-bg[class*="rdp"] {
background-color: transparent !important;
}
.glass-bg .rdp {
background-color: transparent !important;
}
.glass-bg .rdp-month {
background-color: transparent !important;
}
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
/* Sonner Toast Notifications - Glass Effect Overrides */
[data-sonner-toast] {
background: var(--glass-bg) !important;
backdrop-filter: blur(var(--blur)) !important;
-webkit-backdrop-filter: blur(var(--blur)) !important;
border: 1px solid var(--glass-border) !important;
box-shadow: var(--glass-shadow-lg) !important;
color: var(--foreground) !important;
}
[data-sonner-toast][data-type="success"] {
border-color: rgba(34, 197, 94, 0.3) !important;
}
[data-sonner-toast][data-type="error"] {
border-color: rgba(239, 68, 68, 0.3) !important;
}
[data-sonner-toast][data-type="warning"] {
border-color: rgba(234, 179, 8, 0.3) !important;
}
[data-sonner-toast][data-type="info"] {
border-color: rgba(59, 130, 246, 0.3) !important;
}
/* Toast description text */
[data-sonner-toast] [data-description] {
color: var(--muted-foreground) !important;
}
/* Toast action buttons - Glass styled */
[data-sonner-toast] [data-button] {
background: var(--glass-bg) !important;
backdrop-filter: blur(var(--blur-sm)) !important;
-webkit-backdrop-filter: blur(var(--blur-sm)) !important;
border: 1px solid var(--glass-border) !important;
color: var(--foreground) !important;
transition: opacity 0.2s ease !important;
}
[data-sonner-toast] [data-button]:hover {
opacity: 0.9 !important;
}
/* Toast cancel button */
[data-sonner-toast] [data-cancel] {
background: var(--glass-bg) !important;
backdrop-filter: blur(var(--blur-sm)) !important;
-webkit-backdrop-filter: blur(var(--blur-sm)) !important;
border: 1px solid var(--glass-border) !important;
color: var(--muted-foreground) !important;
}
[data-sonner-toast] [data-cancel]:hover {
opacity: 0.9 !important;
}
/* Toast close button */
[data-sonner-toast] [data-close-button] {
background: var(--glass-bg) !important;
backdrop-filter: blur(var(--blur-sm)) !important;
-webkit-backdrop-filter: blur(var(--blur-sm)) !important;
border: 1px solid var(--glass-border) !important;
color: var(--foreground) !important;
}
[data-sonner-toast] [data-close-button]:hover {
opacity: 0.9 !important;
}components/ui/glass/button.tsx
"use client"
import * as React from "react"
import { Button as BaseButton } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import type { GlassCustomization } from "@/lib/glass-utils"
import { hoverEffects, type HoverEffect } from "@/lib/hover-effects"
export interface ButtonProps
extends Omit<React.ComponentProps<typeof BaseButton>, "glass"> {
effect?: HoverEffect
glass?: GlassCustomization
}
/**
* Glass UI Button - A beautifully designed button component with glassy effects
* Built on top of the base Button component with enhanced visual effects
*
* @example
* ```tsx
* <Button
* glass={{
* color: "rgba(59, 130, 246, 0.2)",
* blur: 25,
* outline: "rgba(59, 130, 246, 0.4)"
* }}
* >
* Click me
* </Button>
* ```
*/
export const Button = React.forwardRef<
HTMLButtonElement,
ButtonProps
>(({ className, effect = "glow", variant = "glass", glass, ...props }, ref) => {
return (
<BaseButton
ref={ref}
variant={variant}
glass={glass}
className={cn(
"relative overflow-hidden",
hoverEffects({ hover: effect }),
className
)}
{...props}
/>
)
})
Button.displayName = "Button"