mirror of
https://github.com/R0m1k3/Menu.git
synced 2026-10-14 02:39:56 +02:00
feat: initialize project with Next.js, Prisma, and admin dashboard functionality
This commit is contained in:
commit
b73aa8616b
37 files changed
+8711
No files matched your search
@@ -0,0 +1,16 @@
|
||||
.card {
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid var(--glass-border);
|
||||
box-shadow: var(--card-shadow);
|
||||
border-radius: 24px;
|
||||
padding: 2rem;
|
||||
transition: var(--transition-smooth);
|
||||
}
|
||||
|
||||
.hoverable:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.15);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import styles from './GlassCard.module.css';
|
||||
|
||||
interface GlassCardProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
hoverable?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
as?: any;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const GlassCard: React.FC<GlassCardProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
hoverable = false,
|
||||
style,
|
||||
as: Component = 'div',
|
||||
onClick
|
||||
}) => {
|
||||
return (
|
||||
<Component
|
||||
className={`${styles.card} ${hoverable ? styles.hoverable : ''} ${className}`}
|
||||
style={style}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
.menuButton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2.5rem;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
color: var(--foreground);
|
||||
gap: 1.5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.iconWrapper {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
border-radius: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
transition: var(--transition-smooth);
|
||||
}
|
||||
|
||||
.menuButton:hover .iconWrapper {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 0 20px var(--accent);
|
||||
}
|
||||
|
||||
.label {
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import * as Icons from 'lucide-react';
|
||||
import { GlassCard } from './GlassCard';
|
||||
import styles from './MenuButton.module.css';
|
||||
|
||||
interface MenuButtonProps {
|
||||
name: string;
|
||||
url: string;
|
||||
iconName?: keyof typeof Icons;
|
||||
}
|
||||
|
||||
export const MenuButton: React.FC<MenuButtonProps> = ({ name, url, iconName = 'ExternalLink' }) => {
|
||||
const Icon = (Icons[iconName] as React.ElementType) || Icons.ExternalLink;
|
||||
|
||||
return (
|
||||
<Link href={url} target="_blank" rel="noopener noreferrer" style={{ textDecoration: 'none' }}>
|
||||
<GlassCard hoverable className={styles.menuButton}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<Icon size={32} />
|
||||
</div>
|
||||
<span className={styles.label}>{name}</span>
|
||||
</GlassCard>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes';
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { Moon, Sun } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { GlassCard } from './GlassCard';
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
|
||||
// Avoid hydration mismatch
|
||||
React.useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted) {
|
||||
return (
|
||||
<GlassCard className="glass" style={{ padding: '0.6rem', border: 'none' }}>
|
||||
<div style={{ width: '24px', height: '24px' }}></div>
|
||||
</GlassCard>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<GlassCard
|
||||
as="button"
|
||||
className="glass"
|
||||
style={{ padding: '0.6rem', cursor: 'pointer' }}
|
||||
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
||||
>
|
||||
{theme === 'dark' ? <Sun size={24} /> : <Moon size={24} />}
|
||||
</GlassCard>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user