feat(ui): add subtle motion and icon polish
This commit is contained in:
parent
79d10730a2
commit
012a5362bb
|
|
@ -19,6 +19,33 @@ interface ToastContextType {
|
|||
|
||||
const ToastContext = createContext<ToastContextType | null>(null);
|
||||
|
||||
function BookIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="h-4 w-4" aria-hidden="true">
|
||||
<path d="M5 5.5A2.5 2.5 0 0 1 7.5 3H19v16H7.5A2.5 2.5 0 0 0 5 21V5.5Z" />
|
||||
<path d="M5 21h14" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function PlusIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="h-4 w-4" aria-hidden="true">
|
||||
<path d="M12 5v14" />
|
||||
<path d="M5 12h14" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function LinkIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="h-4 w-4" aria-hidden="true">
|
||||
<path d="M10 13a5 5 0 0 0 7.07 0l2.12-2.12a5 5 0 0 0-7.07-7.07L10.7 5.23" />
|
||||
<path d="M14 11a5 5 0 0 0-7.07 0L4.8 13.12a5 5 0 0 0 7.07 7.07l1.42-1.42" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function useToastContext() {
|
||||
const context = useContext(ToastContext);
|
||||
if (!context) {
|
||||
|
|
@ -38,10 +65,11 @@ function App() {
|
|||
};
|
||||
|
||||
const linkClass = (path: string) => {
|
||||
const base = `px-4 py-2 rounded-full text-sm font-semibold transition-colors shadow-sm`;
|
||||
const base =
|
||||
'group/nav relative inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold transition-all duration-200 ease-out outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white motion-safe:hover:-translate-y-0.5';
|
||||
return isActive(path)
|
||||
? `${base} bg-blue-100 text-blue-700`
|
||||
: `${base} text-gray-700 hover:bg-gray-100`;
|
||||
? `${base} bg-blue-100 text-blue-700 shadow-sm`
|
||||
: `${base} text-slate-700 hover:bg-slate-100 hover:text-slate-900`;
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -52,21 +80,28 @@ function App() {
|
|||
|
||||
<header className="sticky top-0 z-20 border-b border-slate-200/70 bg-white/85 shadow-sm backdrop-blur-md dark:border-slate-700/60 dark:bg-slate-900/70">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
<div className="flex items-center justify-between h-16 gap-3">
|
||||
<div className="flex items-center">
|
||||
<Link to="/" className="flex-shrink-0">
|
||||
<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Recipe Manager</h1>
|
||||
<Link
|
||||
to="/"
|
||||
className="group inline-flex items-center gap-2 rounded-lg px-2 py-1.5 outline-none transition-colors duration-200 hover:text-blue-700 focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2"
|
||||
>
|
||||
<span className="text-xl" aria-hidden="true">🍽️</span>
|
||||
<h1 className="text-xl sm:text-2xl font-bold text-gray-900 tracking-tight">Recipe Manager</h1>
|
||||
</Link>
|
||||
</div>
|
||||
<nav className="flex space-x-3">
|
||||
<nav aria-label="Primary" className="flex flex-wrap items-center justify-end gap-2 sm:gap-3">
|
||||
<Link to="/" className={linkClass('/')}>
|
||||
Recipes
|
||||
<BookIcon />
|
||||
<span>Recipes</span>
|
||||
</Link>
|
||||
<Link to="/recipe/new" className={linkClass('/recipe/new')}>
|
||||
Add Recipe
|
||||
<PlusIcon />
|
||||
<span>Add Recipe</span>
|
||||
</Link>
|
||||
<Link to="/import/url" className={linkClass('/import/url')}>
|
||||
Import URL
|
||||
<LinkIcon />
|
||||
<span>Import URL</span>
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function emojiForRecipe(recipe: Recipe) {
|
|||
|
||||
function MetaChip({ label, value, emoji }: { label: string; value: string; emoji: string }) {
|
||||
return (
|
||||
<div className="inline-flex items-center gap-1.5 rounded-full border border-slate-200/80 bg-slate-50 px-2.5 py-1 text-xs text-slate-700">
|
||||
<div className="inline-flex items-center gap-1.5 rounded-full border border-slate-200/80 bg-slate-50 px-2.5 py-1 text-xs text-slate-700 transition-all duration-200 group-hover:border-slate-300 group-hover:bg-white">
|
||||
<span aria-hidden="true">{emoji}</span>
|
||||
<span className="font-medium">{value}</span>
|
||||
<span className="text-slate-500">{label}</span>
|
||||
|
|
@ -50,7 +50,7 @@ export function RecipeCard({ recipe, tags = [] }: RecipeCardProps) {
|
|||
return (
|
||||
<Link
|
||||
to={`/recipe/${recipe.id}`}
|
||||
className="group block overflow-hidden border border-slate-200/80 bg-white/95 outline-none transition-all duration-200 hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-lg focus-visible:ring-2 focus-visible:ring-blue-600"
|
||||
className="group block overflow-hidden border border-slate-200/80 bg-white/95 outline-none transition-all duration-200 hover:-translate-y-0.5 hover:border-slate-300 hover:shadow-lg focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2"
|
||||
style={{ boxShadow: shadows.card, borderRadius: radius.lg }}
|
||||
>
|
||||
<div
|
||||
|
|
@ -59,16 +59,16 @@ export function RecipeCard({ recipe, tags = [] }: RecipeCardProps) {
|
|||
background: `linear-gradient(135deg, color-mix(in srgb, ${accent} 30%, white) 0%, color-mix(in srgb, ${accent} 14%, #f8fafc) 55%, #ffffff 100%)`,
|
||||
}}
|
||||
>
|
||||
<div className="absolute left-4 top-4 rounded-full border border-white/70 bg-white/80 px-3 py-1 text-xs font-semibold text-slate-700 backdrop-blur-sm">
|
||||
<div className="absolute left-4 top-4 rounded-full border border-white/70 bg-white/80 px-3 py-1 text-xs font-semibold text-slate-700 backdrop-blur-sm transition-transform duration-200 group-hover:scale-[1.02]">
|
||||
{tags[0]?.name ?? 'Homemade'}
|
||||
</div>
|
||||
<div className="absolute inset-0 flex items-center justify-center text-6xl opacity-90" aria-hidden="true">
|
||||
<div className="absolute inset-0 flex items-center justify-center text-6xl opacity-90 transition-transform duration-300 group-hover:scale-105" aria-hidden="true">
|
||||
{emojiForRecipe(recipe)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex h-[calc(100%-10rem)] min-h-[210px] flex-col p-5">
|
||||
<h3 className="mb-1 line-clamp-2 text-lg font-bold text-gray-900 transition-colors group-hover:text-blue-700">{recipe.title}</h3>
|
||||
<h3 className="mb-1 line-clamp-2 text-lg font-bold text-gray-900 transition-colors duration-200 group-hover:text-blue-700">{recipe.title}</h3>
|
||||
|
||||
{recipe.description ? (
|
||||
<p className="mb-3 line-clamp-2 text-sm text-gray-600">{recipe.description}</p>
|
||||
|
|
@ -87,7 +87,7 @@ export function RecipeCard({ recipe, tags = [] }: RecipeCardProps) {
|
|||
{tags.slice(0, 4).map((tag) => (
|
||||
<span
|
||||
key={tag.id}
|
||||
className="rounded-full px-2.5 py-1 text-xs font-semibold text-white shadow-sm"
|
||||
className="rounded-full px-2.5 py-1 text-xs font-semibold text-white shadow-sm transition-transform duration-200 group-hover:scale-[1.02]"
|
||||
style={{ backgroundColor: tag.color || colors.primary, borderRadius: radius.full }}
|
||||
>
|
||||
{tag.name}
|
||||
|
|
@ -99,7 +99,10 @@ export function RecipeCard({ recipe, tags = [] }: RecipeCardProps) {
|
|||
|
||||
<div className="mt-auto flex items-center justify-between border-t border-slate-100 pt-3 text-xs text-gray-500">
|
||||
<span>{recipe.last_cooked_at ? `Cooked ${formatDate(recipe.last_cooked_at)}` : 'Not cooked yet'}</span>
|
||||
<span className="font-medium text-blue-600 group-hover:underline">View recipe →</span>
|
||||
<span className="inline-flex items-center gap-1 font-medium text-blue-600">
|
||||
View recipe
|
||||
<span className="transition-transform duration-200 group-hover:translate-x-0.5" aria-hidden="true">→</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ button:focus-visible,
|
|||
.btn:focus-visible,
|
||||
input:focus-visible,
|
||||
textarea:focus-visible,
|
||||
select:focus-visible {
|
||||
select:focus-visible,
|
||||
a:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
|
|
@ -176,6 +177,17 @@ textarea::placeholder {
|
|||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.max-w-7xl,
|
||||
.max-w-6xl,
|
||||
|
|
|
|||
|
|
@ -218,8 +218,8 @@ export function ImportUrlPage() {
|
|||
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-base shadow-sm focus:border-transparent focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" disabled={loading} className="rounded-lg bg-blue-600 px-4 py-2.5 font-semibold text-white shadow transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50">
|
||||
{loading ? 'Importing…' : 'Import URL'}
|
||||
<button type="submit" disabled={loading} className="rounded-lg bg-blue-600 px-4 py-2.5 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
|
||||
{loading ? 'Importing…' : '🔗 Import URL'}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
|
@ -267,10 +267,10 @@ export function ImportUrlPage() {
|
|||
</div>
|
||||
|
||||
<div className="mt-2 flex gap-3">
|
||||
<button type="submit" disabled={isSaving} className="rounded-lg bg-green-600 px-4 py-2 font-medium text-white shadow hover:bg-green-700 disabled:cursor-not-allowed disabled:opacity-50">
|
||||
{isSaving ? 'Saving…' : 'Save Recipe'}
|
||||
<button type="submit" disabled={isSaving} className="rounded-lg bg-green-600 px-4 py-2 font-medium text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-green-700 focus-visible:ring-2 focus-visible:ring-green-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
|
||||
{isSaving ? 'Saving…' : '💾 Save Recipe'}
|
||||
</button>
|
||||
<Link to="/recipe/new" className="rounded-lg border border-gray-300 px-4 py-2 font-medium text-gray-700 shadow-sm hover:bg-gray-50">Open full editor</Link>
|
||||
<Link to="/recipe/new" className="rounded-lg border border-gray-300 px-4 py-2 font-medium text-gray-700 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">📝 Open full editor</Link>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -210,23 +210,23 @@ export function RecipeDetailPage() {
|
|||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<button onClick={() => setIsEditing(true)} className="rounded-lg bg-blue-600 px-4 py-2.5 font-semibold text-white shadow transition-colors hover:bg-blue-700">Edit Recipe</button>
|
||||
<Link to={`/recipe/${recipe.id}/cook`} className="rounded-lg bg-green-600 px-4 py-2.5 text-center font-semibold text-white shadow transition-colors hover:bg-green-700">Cook Mode</Link>
|
||||
<button onClick={() => setIsEditing(true)} className="inline-flex items-center justify-center gap-2 rounded-lg bg-blue-600 px-4 py-2.5 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"><span aria-hidden="true">✏️</span> Edit Recipe</button>
|
||||
<Link to={`/recipe/${recipe.id}/cook`} className="inline-flex items-center justify-center gap-2 rounded-lg bg-green-600 px-4 py-2.5 text-center font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-green-700 focus-visible:ring-2 focus-visible:ring-green-500 focus-visible:ring-offset-2"><span aria-hidden="true">🍳</span>Cook Mode</Link>
|
||||
{!deleteConfirm ? (
|
||||
<button onClick={() => setDeleteConfirm(true)} className="rounded-lg bg-red-600 px-4 py-2.5 font-semibold text-white shadow transition-colors hover:bg-red-700">Delete Recipe</button>
|
||||
<button onClick={() => setDeleteConfirm(true)} className="inline-flex items-center justify-center gap-2 rounded-lg bg-red-600 px-4 py-2.5 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-red-700 focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2"><span aria-hidden="true">🗑️</span>Delete Recipe</button>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-2 sm:col-span-2 lg:col-span-2">
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
disabled={isDeleting}
|
||||
className="rounded-lg bg-red-700 px-3 py-2.5 text-sm font-semibold text-white shadow transition-colors hover:bg-red-800 disabled:cursor-not-allowed disabled:bg-gray-400"
|
||||
className="rounded-lg bg-red-700 px-3 py-2.5 text-sm font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-red-800 focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:bg-gray-400"
|
||||
>
|
||||
{isDeleting ? 'Deleting...' : 'Confirm Delete'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setDeleteConfirm(false)}
|
||||
disabled={isDeleting}
|
||||
className="rounded-lg bg-slate-200 px-3 py-2.5 text-sm font-semibold text-slate-700 transition-colors hover:bg-slate-300 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className="rounded-lg bg-slate-200 px-3 py-2.5 text-sm font-semibold text-slate-700 transition-all duration-200 hover:-translate-y-0.5 hover:bg-slate-300 focus-visible:ring-2 focus-visible:ring-slate-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
|
@ -303,7 +303,7 @@ export function RecipeDetailPage() {
|
|||
)}
|
||||
|
||||
<div className="mt-8 text-center">
|
||||
<Link to="/" className="font-medium text-primary hover:text-blue-700">← Back to all recipes</Link>
|
||||
<Link to="/" className="inline-flex items-center gap-1 font-medium text-primary transition-colors hover:text-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 rounded-sm">← Back to all recipes</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -64,16 +64,18 @@ export function RecipeListPage() {
|
|||
<div className="flex flex-wrap gap-3">
|
||||
<Link
|
||||
to="/recipe/new"
|
||||
className="rounded-lg bg-blue-600 px-5 py-2.5 font-semibold text-white shadow transition-colors hover:bg-blue-700"
|
||||
className="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-5 py-2.5 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
<span aria-hidden="true">➕</span>
|
||||
Add Recipe
|
||||
</Link>
|
||||
<a
|
||||
href="#recipes-grid"
|
||||
className="rounded-lg border border-slate-200 bg-white px-5 py-2.5 font-semibold text-slate-700 transition-colors hover:bg-slate-50"
|
||||
className="inline-flex items-center gap-2 rounded-lg border border-slate-200 bg-white px-5 py-2.5 font-semibold text-slate-700 transition-all duration-200 hover:-translate-y-0.5 hover:bg-slate-50 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
<span aria-hidden="true">📚</span>
|
||||
Browse Recipes
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -96,10 +98,11 @@ export function RecipeListPage() {
|
|||
</div>
|
||||
<Link
|
||||
to="/recipe/new"
|
||||
className="rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white shadow transition-colors hover:bg-blue-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500"
|
||||
className="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-blue-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
+ New Recipe
|
||||
<span aria-hidden="true">✨</span>
|
||||
New Recipe
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
|
@ -117,7 +120,7 @@ export function RecipeListPage() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={handleClearSearch}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 rounded-md p-1 text-gray-400 transition-colors hover:text-gray-600 focus-visible:ring-2 focus-visible:ring-blue-500"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
✕
|
||||
|
|
@ -126,7 +129,7 @@ export function RecipeListPage() {
|
|||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="rounded-lg border border-gray-200 bg-gray-100 px-6 py-2 font-semibold text-gray-700 transition-colors hover:bg-gray-200"
|
||||
className="rounded-lg border border-gray-200 bg-gray-100 px-6 py-2 font-semibold text-gray-700 transition-all duration-200 hover:-translate-y-0.5 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
Search
|
||||
|
|
@ -140,8 +143,8 @@ export function RecipeListPage() {
|
|||
onClick={() => setSelectedTagId(null)}
|
||||
className={
|
||||
selectedTagId === null
|
||||
? 'rounded-full bg-blue-600 px-3 py-1.5 text-sm font-semibold text-white shadow outline-none transition-colors'
|
||||
: 'rounded-full bg-gray-100 px-3 py-1.5 text-sm font-medium text-gray-700 outline-none transition-colors hover:bg-gray-200'
|
||||
? 'rounded-full bg-blue-600 px-3 py-1.5 text-sm font-semibold text-white shadow outline-none transition-all duration-150 hover:-translate-y-0.5 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'
|
||||
: 'rounded-full bg-gray-100 px-3 py-1.5 text-sm font-medium text-gray-700 outline-none transition-all duration-150 hover:-translate-y-0.5 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'
|
||||
}
|
||||
style={{ borderRadius: radius.full }}
|
||||
>
|
||||
|
|
@ -153,8 +156,8 @@ export function RecipeListPage() {
|
|||
onClick={() => setSelectedTagId(tag.id)}
|
||||
className={
|
||||
selectedTagId === tag.id
|
||||
? 'rounded-full px-3 py-1.5 text-sm font-semibold text-white shadow outline-none'
|
||||
: 'rounded-full bg-gray-100 px-3 py-1.5 text-sm font-medium text-gray-700 outline-none transition-colors hover:bg-gray-200'
|
||||
? 'rounded-full px-3 py-1.5 text-sm font-semibold text-white shadow outline-none transition-all duration-150 hover:-translate-y-0.5 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'
|
||||
: 'rounded-full bg-gray-100 px-3 py-1.5 text-sm font-medium text-gray-700 outline-none transition-all duration-150 hover:-translate-y-0.5 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2'
|
||||
}
|
||||
style={{ backgroundColor: selectedTagId === tag.id ? tag.color : '', borderRadius: radius.full }}
|
||||
>
|
||||
|
|
@ -171,7 +174,7 @@ export function RecipeListPage() {
|
|||
{selectedTagId !== null && (
|
||||
<span className="rounded bg-blue-50 px-2 py-1 text-blue-700">Tag: {tags.find((t) => t.id === selectedTagId)?.name}</span>
|
||||
)}
|
||||
<button onClick={handleClearFilters} className="font-medium text-blue-600 hover:text-blue-700">
|
||||
<button onClick={handleClearFilters} className="font-medium text-blue-600 transition-colors hover:text-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 rounded-sm">
|
||||
Clear all filters
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -207,9 +210,10 @@ export function RecipeListPage() {
|
|||
{!searchQuery && (
|
||||
<Link
|
||||
to="/recipe/new"
|
||||
className="inline-block rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white shadow transition-colors hover:bg-blue-700"
|
||||
className="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white shadow transition-all duration-200 hover:-translate-y-0.5 hover:bg-blue-700 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
<span aria-hidden="true">🍳</span>
|
||||
Add Your First Recipe
|
||||
</Link>
|
||||
)}
|
||||
|
|
@ -228,7 +232,7 @@ export function RecipeListPage() {
|
|||
<button
|
||||
onClick={loadMore}
|
||||
disabled={loading}
|
||||
className="rounded-lg border bg-gray-100 px-6 py-3 font-medium text-gray-700 transition-colors hover:bg-gray-200 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="rounded-lg border bg-gray-100 px-6 py-3 font-medium text-gray-700 transition-all duration-200 hover:-translate-y-0.5 hover:bg-gray-200 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
style={{ borderRadius: radius.md }}
|
||||
>
|
||||
{loading ? 'Loading...' : 'Load More'}
|
||||
|
|
|
|||
Loading…
Reference in New Issue