mirror of
https://github.com/R0m1k3/Menu.git
synced 2026-10-14 10:50:10 +02:00
feat: implement MenuButton component and home page layout with global glassmorphism styles
This commit is contained in:
1 parent
5ff4784596
commit
ca99378348
6 files changed
+198
-302
No files matched your search
+20
-34
@@ -3,8 +3,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { ArrowUpRight, Globe } from 'lucide-react';
|
||||
import { GlassCard } from './GlassCard';
|
||||
import { Globe } from 'lucide-react';
|
||||
import styles from './MenuButton.module.css';
|
||||
|
||||
interface MenuButtonProps {
|
||||
@@ -12,22 +11,14 @@ interface MenuButtonProps {
|
||||
url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract base domain from URL for favicon fetch.
|
||||
*/
|
||||
function getDomain(url: string): string {
|
||||
try {
|
||||
const { hostname } = new URL(url);
|
||||
return hostname;
|
||||
return new URL(url).hostname;
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MenuButton component displaying a favicon and app name.
|
||||
* Favicons are fetched from Google's favicon CDN.
|
||||
*/
|
||||
export const MenuButton: React.FC<MenuButtonProps> = ({ name, url }) => {
|
||||
const domain = getDomain(url);
|
||||
const faviconUrl = `https://www.google.com/s2/favicons?domain=${domain}&sz=64`;
|
||||
@@ -35,29 +26,24 @@ export const MenuButton: React.FC<MenuButtonProps> = ({ name, url }) => {
|
||||
|
||||
return (
|
||||
<Link href={url} target="_blank" rel="noopener noreferrer" className={styles.menuButton}>
|
||||
<GlassCard hoverable className={styles.menuButton}>
|
||||
<ArrowUpRight size={16} className={styles.arrowIcon} />
|
||||
|
||||
<div className={styles.faviconWrapper}>
|
||||
{!faviconError ? (
|
||||
<Image
|
||||
src={faviconUrl}
|
||||
alt={`${name} icon`}
|
||||
width={40}
|
||||
height={40}
|
||||
className={styles.favicon}
|
||||
onError={() => setFaviconError(true)}
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.faviconFallback}>
|
||||
<Globe size={28} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span className={styles.label}>{name}</span>
|
||||
</GlassCard>
|
||||
<div className={styles.faviconWrapper}>
|
||||
{!faviconError ? (
|
||||
<Image
|
||||
src={faviconUrl}
|
||||
alt={`${name} favicon`}
|
||||
width={48}
|
||||
height={48}
|
||||
className={styles.favicon}
|
||||
onError={() => setFaviconError(true)}
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.faviconFallback}>
|
||||
<Globe size={32} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<span className={styles.label}>{name}</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user