mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Standardise page wrapper width and top padding and refresh catalog and theme styling
This commit is contained in:
@@ -11,7 +11,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Login</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
POST to <code className="kbd kbd-sm">/api/auth/login</code> with
|
||||
username & password
|
||||
</p>
|
||||
@@ -20,7 +20,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Register</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
POST to <code className="kbd kbd-sm">/api/auth/register</code> with full
|
||||
user details
|
||||
</p>
|
||||
@@ -29,7 +29,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Session</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
JWT access & refresh tokens stored in an HTTP-only cookie
|
||||
</p>
|
||||
</div>
|
||||
@@ -37,7 +37,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Protected Routes</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
This dashboard requires authentication via{' '}
|
||||
<code className="kbd kbd-sm">requireAuth()</code>
|
||||
</p>
|
||||
@@ -46,7 +46,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Token Refresh</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
POST to <code className="kbd kbd-sm">/api/auth/refresh</code> with the
|
||||
refresh token in an <code className="kbd kbd-sm">X-Refresh-Token</code>{' '}
|
||||
header
|
||||
@@ -56,7 +56,7 @@ const AuthFlowDemoCard = () => (
|
||||
<li className="list-row">
|
||||
<div>
|
||||
<p className="font-semibold">Account Management</p>
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
PATCH <code className="kbd kbd-sm">/api/auth/username</code>,{' '}
|
||||
<code className="kbd kbd-sm">/email</code>,{' '}
|
||||
<code className="kbd kbd-sm">/password</code>,{' '}
|
||||
|
||||
@@ -14,7 +14,7 @@ const SectionCard = ({ icon, title, description, open, onToggle, children }: Sec
|
||||
<div className="card-body">
|
||||
<div className="flex w-full items-center justify-between gap-5">
|
||||
<div className="flex items-start gap-3">
|
||||
<span className="text-base-content/60 mt-1">{icon}</span>
|
||||
<span className="text-base-content/70 mt-1">{icon}</span>
|
||||
<div>
|
||||
<h2 className="card-title text-lg">{title}</h2>
|
||||
<p className="text-sm text-base-content/70">{description}</p>
|
||||
|
||||
@@ -15,7 +15,7 @@ const SessionInfoCard = ({ username, userAccountId }: SessionInfoCardProps) => (
|
||||
</p>
|
||||
|
||||
<div className="bg-base-200 rounded-box p-4 mt-2">
|
||||
<p className="text-xs font-semibold uppercase tracking-widest text-base-content/50 mb-3">
|
||||
<p className="text-xs font-semibold uppercase tracking-widest text-base-content/70 mb-3">
|
||||
Session Info
|
||||
</p>
|
||||
<div className="stats stats-vertical w-full">
|
||||
|
||||
@@ -208,11 +208,11 @@ const AccountPage = ({ loaderData, actionData }: Route.ComponentProps) => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="mx-auto max-w-2xl px-6 py-10 space-y-6">
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10 pb-10 space-y-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<Settings className="size-7" aria-hidden="true" />
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">Account Settings</h1>
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight">Account Settings</h1>
|
||||
<p className="text-base-content/70">
|
||||
Manage the account details for{' '}
|
||||
<span className="font-mono">{username}</span>
|
||||
@@ -257,7 +257,7 @@ const AccountPage = ({ loaderData, actionData }: Route.ComponentProps) => {
|
||||
|
||||
<Link
|
||||
to="/dashboard"
|
||||
className="link link-hover text-sm text-base-content/60 inline-block"
|
||||
className="link link-hover text-sm text-base-content/70 inline-block"
|
||||
>
|
||||
← Back to dashboard
|
||||
</Link>
|
||||
|
||||
@@ -20,7 +20,7 @@ const Dashboard = ({ loaderData }: Route.ComponentProps) => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="mx-auto max-w-4xl px-6 py-10 space-y-6">
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10 pb-10 space-y-6">
|
||||
<SessionInfoCard username={username} userAccountId={userAccountId} />
|
||||
<AuthFlowDemoCard />
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ const ConfirmSuccess = ({ confirmedDate }: ConfirmSuccessProps) => (
|
||||
<h1 className="card-title text-2xl">Email Confirmed!</h1>
|
||||
<p className="text-base-content/70">Your email address has been successfully verified.</p>
|
||||
<div className="bg-base-200 rounded-box w-full p-3 text-sm text-left">
|
||||
<span className="text-base-content/50 text-xs uppercase tracking-widest font-semibold">
|
||||
<span className="text-base-content/70 text-xs uppercase tracking-widest font-semibold">
|
||||
Confirmed at
|
||||
</span>
|
||||
<p className="font-mono mt-1">{new Date(confirmedDate).toLocaleString()}</p>
|
||||
|
||||
@@ -8,7 +8,7 @@ const LoginCallout = () => (
|
||||
<Link to="/login" className="btn btn-outline btn-sm w-full">
|
||||
Sign in
|
||||
</Link>
|
||||
<Link to="/" className="link link-hover text-sm text-base-content/60">
|
||||
<Link to="/" className="link link-hover text-sm text-base-content/70">
|
||||
Back to home
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ const RegisterCallout = () => (
|
||||
</Link>
|
||||
<Link
|
||||
to="/"
|
||||
className="link link-hover text-sm text-base-content/60 inline-flex items-center gap-1"
|
||||
className="link link-hover text-sm text-base-content/70 inline-flex items-center gap-1"
|
||||
>
|
||||
<HomeSimpleDoor className="size-4" aria-hidden="true" />
|
||||
Back to home
|
||||
|
||||
@@ -23,12 +23,12 @@ const BeerListCard = ({ beers }: BeerListCardProps) => (
|
||||
>
|
||||
<div className="flex flex-col gap-0.5 min-w-0">
|
||||
<span className="font-bold text-sm">{beer.name}</span>
|
||||
<span className="text-xs text-base-content/60">{beer.description}</span>
|
||||
<span className="text-xs text-base-content/70">{beer.description}</span>
|
||||
</div>
|
||||
<span className="badge badge-ghost bg-base-300 text-xs font-semibold whitespace-nowrap">
|
||||
{beer.style}
|
||||
</span>
|
||||
<span className="text-xs text-base-content/60 tabular-nums whitespace-nowrap">
|
||||
<span className="text-xs text-base-content/70 tabular-nums whitespace-nowrap">
|
||||
{beer.abv.toFixed(1)}% ABV
|
||||
</span>
|
||||
<StarRating value={beer.rating} size="xs" />
|
||||
|
||||
@@ -17,7 +17,7 @@ const BeerStyleBreakdownCard = ({ beers }: BeerStyleBreakdownCardProps) => {
|
||||
<div key={style} className="flex flex-col gap-1">
|
||||
<div className="flex items-baseline justify-between gap-2">
|
||||
<span className="text-sm font-semibold">{style}</span>
|
||||
<span className="text-xs text-base-content/60 tabular-nums">{count}</span>
|
||||
<span className="text-xs text-base-content/70 tabular-nums">{count}</span>
|
||||
</div>
|
||||
<progress
|
||||
className="progress progress-primary h-1.5"
|
||||
|
||||
@@ -8,7 +8,7 @@ interface BreweryDetailsCardProps {
|
||||
|
||||
const DetailRow = ({ label, value }: { label: string; value: string | number }) => (
|
||||
<div className="flex items-center justify-between gap-2 text-sm">
|
||||
<span className="text-base-content/60">{label}</span>
|
||||
<span className="text-base-content/70">{label}</span>
|
||||
<span className="font-semibold">{value}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -26,16 +26,16 @@ const BreweryHeaderCard = ({
|
||||
<div className="card-body gap-4 p-7">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="text-xs font-bold uppercase tracking-widest text-base-content/50">
|
||||
<span className="text-xs font-bold uppercase tracking-widest text-base-content/70">
|
||||
Brewery
|
||||
</span>
|
||||
<span className="badge bg-[var(--color-highlight)] text-[var(--color-highlight-content)]">
|
||||
Est. {foundedYear}
|
||||
</span>
|
||||
</div>
|
||||
<h1 className="text-4xl leading-tight m-0">{brewery.breweryName}</h1>
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight m-0">{brewery.breweryName}</h1>
|
||||
{brewery.location && (
|
||||
<p className="text-sm text-base-content/60 flex items-center gap-1 m-0">
|
||||
<p className="text-sm text-base-content/70 flex items-center gap-1 m-0">
|
||||
<MapPin className="size-4" aria-hidden="true" />
|
||||
{formatBreweryAddress(brewery.location)}
|
||||
</p>
|
||||
@@ -57,7 +57,7 @@ const BreweryHeaderCard = ({
|
||||
<div className="flex items-baseline gap-1.5">
|
||||
<StarRating value={avgRating} size="sm" />
|
||||
<span className="font-bold">{avgRating.toFixed(1)}</span>
|
||||
<span className="text-sm text-base-content/60">({ratingsCount} ratings)</span>
|
||||
<span className="text-sm text-base-content/70">({ratingsCount} ratings)</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-base-content/70 leading-relaxed text-pretty m-0">
|
||||
|
||||
@@ -8,7 +8,7 @@ interface CommunityStatsCardProps {
|
||||
|
||||
const StatRow = ({ label, value }: { label: string; value: number }) => (
|
||||
<div className="flex items-center justify-between gap-2 text-sm">
|
||||
<span className="text-base-content/60">{label}</span>
|
||||
<span className="text-base-content/70">{label}</span>
|
||||
<span className="font-semibold tabular-nums">{value}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ const YourRatingCard = ({ value, onChange }: YourRatingCardProps) => (
|
||||
<div className="card-body flex-row flex-wrap items-center justify-between gap-4 p-6">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<h3 className="text-xl m-0">Your rating</h3>
|
||||
<p className="text-sm text-base-content/60 m-0">
|
||||
<p className="text-sm text-base-content/70 m-0">
|
||||
{value
|
||||
? `You rated this ${value} of 5. Tap the same star to clear.`
|
||||
: 'Tap a star to rate this brewery.'}
|
||||
|
||||
@@ -31,14 +31,14 @@ const CommentItem = ({ comment, onToggleLike }: CommentItemProps) => {
|
||||
<span className="font-bold text-sm">{comment.user}</span>
|
||||
)}
|
||||
<StarRating value={comment.rating} size="xs" />
|
||||
<span className="text-xs text-base-content/60">{comment.time}</span>
|
||||
<span className="text-xs text-base-content/70">{comment.time}</span>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed m-0">{comment.text}</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onToggleLike(comment.id)}
|
||||
className={`self-start inline-flex items-center gap-1 text-xs font-semibold ${
|
||||
comment.liked ? 'text-primary' : 'text-base-content/60'
|
||||
comment.liked ? 'text-primary' : 'text-base-content/70'
|
||||
}`}
|
||||
>
|
||||
{comment.liked ? (
|
||||
|
||||
@@ -24,7 +24,7 @@ const BreweryCard = ({ brewery }: BreweryCardProps) => (
|
||||
</p>
|
||||
)}
|
||||
{brewery.location && (
|
||||
<p className="text-sm text-base-content/50 mt-2">
|
||||
<p className="text-sm text-base-content/70 mt-2">
|
||||
{formatBreweryAddress(brewery.location)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -19,14 +19,14 @@ const FeaturedBreweryCard = ({ brewery, onShowOnMap }: FeaturedBreweryCardProps)
|
||||
<div className="card-body gap-3.5 p-8 md:grid md:grid-cols-[1.35fr_1fr] md:gap-10 md:items-start">
|
||||
<div className="flex flex-col gap-3.5">
|
||||
{brewery.location && (
|
||||
<div className="text-sm font-semibold text-base-content/60">
|
||||
<div className="text-sm font-semibold text-base-content/70">
|
||||
{brewery.location.cityName}, {brewery.location.stateProvinceCode}
|
||||
</div>
|
||||
)}
|
||||
<h3 className="font-serif text-4xl leading-tight m-0">{brewery.breweryName}</h3>
|
||||
<p className="text-lg leading-snug text-pretty m-0">{brewery.description}</p>
|
||||
{brewery.location && (
|
||||
<p className="text-sm text-base-content/60 m-0">
|
||||
<p className="text-sm text-base-content/70 m-0">
|
||||
{formatBreweryAddress(brewery.location)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -17,7 +17,7 @@ const RecentBreweries = ({ breweries }: RecentBreweriesProps) => {
|
||||
<div className="card-body gap-1.5">
|
||||
<h3 className="card-title font-serif text-xl">{brewery.breweryName}</h3>
|
||||
{brewery.location && (
|
||||
<div className="text-sm text-base-content/60">
|
||||
<div className="text-sm text-base-content/70">
|
||||
{brewery.location.cityName},{' '}
|
||||
{brewery.location.stateProvinceCode}
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ const NearbyBreweriesHeader = ({
|
||||
return (
|
||||
<div className="flex items-baseline justify-between gap-4 flex-wrap mb-3.5">
|
||||
<h2 className="font-serif text-2xl m-0">Breweries near you</h2>
|
||||
<span className="text-sm text-base-content/60">
|
||||
<span className="text-sm text-base-content/70">
|
||||
{center
|
||||
? `${withDistance.length} within ${formatDistance(radiusKm * 1000, unit)} of ${centerLabel}`
|
||||
: 'Finding breweries near you…'}
|
||||
|
||||
@@ -23,7 +23,7 @@ const NearbyBreweryList = ({
|
||||
return (
|
||||
<>
|
||||
{withDistance.length === 0 && center && (
|
||||
<p className="text-sm text-base-content/60">
|
||||
<p className="text-sm text-base-content/70">
|
||||
No partner breweries within {formatDistance(radiusKm * 1000, unit)}.
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -37,7 +37,7 @@ const NearbyBreweryListItem = ({
|
||||
</span>
|
||||
</div>
|
||||
{brewery.location && (
|
||||
<div className="text-sm text-base-content/60">
|
||||
<div className="text-sm text-base-content/70">
|
||||
{brewery.location.cityName}, {brewery.location.stateProvinceCode}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -8,7 +8,7 @@ interface SidebarCardProps {
|
||||
const SidebarCard = ({ title, children }: SidebarCardProps) => (
|
||||
<div className="card bg-base-100 shadow">
|
||||
<div className="card-body gap-3 p-6">
|
||||
<p className="text-xs font-bold uppercase tracking-widest text-base-content/50 m-0">
|
||||
<p className="text-xs font-bold uppercase tracking-widest text-base-content/70 m-0">
|
||||
{title}
|
||||
</p>
|
||||
{children}
|
||||
|
||||
@@ -44,8 +44,8 @@ const Breweries = ({ loaderData }: Route.ComponentProps) => {
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200 text-base-content pb-16">
|
||||
<div className="max-w-7xl mx-auto px-5 pt-10">
|
||||
<h1 className="font-serif text-5xl leading-tight mb-2">Breweries</h1>
|
||||
<p className="text-lg text-base-content/60 max-w-xl m-0">
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight mb-2">Breweries</h1>
|
||||
<p className="text-lg text-base-content/70 max-w-xl m-0">
|
||||
Discover our partner breweries — start with this week's feature, then see
|
||||
what's pouring near you.
|
||||
</p>
|
||||
|
||||
@@ -80,15 +80,15 @@ const BreweryDetail = ({ loaderData }: Route.ComponentProps) => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="max-w-4xl mx-auto px-6 pt-8 pb-16">
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10 pb-16">
|
||||
<Link
|
||||
to="/breweries"
|
||||
className="link link-hover text-sm text-base-content/60 mb-4 inline-block"
|
||||
className="link link-hover text-sm text-base-content/70 mb-4 inline-block"
|
||||
>
|
||||
← Back to breweries
|
||||
</Link>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_19rem] gap-5 items-start">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[1fr_23rem] gap-5 items-start">
|
||||
<div className="flex flex-col gap-5">
|
||||
<BreweryHeaderCard
|
||||
brewery={brewery}
|
||||
|
||||
@@ -72,14 +72,14 @@ const Breweries = ({ loaderData }: Route.ComponentProps) => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="container mx-auto p-14">
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10">
|
||||
<Link
|
||||
to="/breweries"
|
||||
className="link link-hover text-sm text-base-content/60 mb-4 inline-block"
|
||||
className="link link-hover text-sm text-base-content/70 mb-4 inline-block"
|
||||
>
|
||||
← Back to Breweries
|
||||
</Link>
|
||||
<h1 className="text-4xl font-bold mb-4">Full brewery directory</h1>
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight mb-4">Full brewery directory</h1>
|
||||
<p className="text-base-content/70 mb-6">
|
||||
All of our partner breweries, newest first.
|
||||
</p>
|
||||
@@ -93,7 +93,7 @@ const Breweries = ({ loaderData }: Route.ComponentProps) => {
|
||||
</ClientOnly>
|
||||
|
||||
{allBreweries.length === 0 ? (
|
||||
<p className="text-center text-base-content/60 mt-12">
|
||||
<p className="text-center text-base-content/70 mt-12">
|
||||
No breweries found yet.
|
||||
</p>
|
||||
) : (
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Clock, Lock, Tools } from 'iconoir-react';
|
||||
import type { ComponentType } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
type Reason = 'soon' | 'maintenance' | 'auth';
|
||||
|
||||
type Action = { to: string; label: string; className: string };
|
||||
|
||||
type Content = {
|
||||
Icon: ComponentType<{ className?: string }>;
|
||||
title: string;
|
||||
description: string;
|
||||
actions: Action[];
|
||||
};
|
||||
|
||||
const CONTENT: Record<Reason, Content> = {
|
||||
soon: {
|
||||
Icon: Clock,
|
||||
title: 'This feature is not available yet',
|
||||
description: 'This feature is still in development.',
|
||||
actions: [
|
||||
{ to: '/breweries', label: 'Browse breweries', className: 'btn-primary' },
|
||||
{ to: '/', label: 'Back to home', className: 'btn-ghost' },
|
||||
],
|
||||
},
|
||||
maintenance: {
|
||||
Icon: Tools,
|
||||
title: 'This feature is temporarily unavailable',
|
||||
description: 'This feature is offline for maintenance. Try again in a few minutes.',
|
||||
actions: [],
|
||||
},
|
||||
auth: {
|
||||
Icon: Lock,
|
||||
title: 'Sign in to use this feature',
|
||||
description: 'This feature requires a valid session. Log in or create an account to continue.',
|
||||
actions: [
|
||||
{ to: '/login', label: 'Login', className: 'btn-primary' },
|
||||
{ to: '/register', label: 'Register', className: 'btn-outline' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
type FeatureNotAvailableProps = {
|
||||
reason?: Reason;
|
||||
};
|
||||
|
||||
const FeatureNotAvailable = ({ reason = 'soon' }: FeatureNotAvailableProps) => {
|
||||
const { Icon, title, description, actions } = CONTENT[reason];
|
||||
|
||||
return (
|
||||
<section className="flex flex-col items-center gap-3 rounded-box border border-base-300 bg-base-100 px-6 py-12 text-center">
|
||||
<div className="flex size-14 items-center justify-center rounded-full bg-base-200 text-base-content/70">
|
||||
<Icon className="size-6" />
|
||||
</div>
|
||||
<div className="flex max-w-md flex-col gap-2">
|
||||
<h2 className="font-serif text-2xl font-bold leading-tight">{title}</h2>
|
||||
<p className="text-base-content/70 text-pretty">{description}</p>
|
||||
</div>
|
||||
{actions.length > 0 && (
|
||||
<div className="flex flex-wrap justify-center gap-3 pt-2">
|
||||
{actions.map(({ to, label, className }) => (
|
||||
<Link key={to} to={to} className={`btn btn-sm ${className}`}>
|
||||
{label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeatureNotAvailable;
|
||||
@@ -1,3 +1,4 @@
|
||||
import FeatureNotAvailable from '../components/FeatureNotAvailable';
|
||||
import type { Route } from './+types/beer-styles';
|
||||
|
||||
export const meta = ({}: Route.MetaArgs) => {
|
||||
@@ -7,9 +8,12 @@ export const meta = ({}: Route.MetaArgs) => {
|
||||
const BeerStyles = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="text-4xl font-bold mb-4">Beer Styles</h1>
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10">
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight mb-4">Beer Styles</h1>
|
||||
<p className="text-base-content/70">Learn about different beer styles.</p>
|
||||
<div className="mt-8">
|
||||
<FeatureNotAvailable />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import FeatureNotAvailable from '../components/FeatureNotAvailable';
|
||||
import type { Route } from './+types/beers';
|
||||
|
||||
export const meta = ({}: Route.MetaArgs) => {
|
||||
@@ -7,9 +8,12 @@ export const meta = ({}: Route.MetaArgs) => {
|
||||
const Beers = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200">
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="text-4xl font-bold mb-4">Beers</h1>
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10">
|
||||
<h1 className="font-serif text-5xl font-bold leading-tight mb-4">Beers</h1>
|
||||
<p className="text-base-content/70">Explore our collection of beers.</p>
|
||||
<div className="mt-8">
|
||||
<FeatureNotAvailable />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,10 +21,9 @@ export const meta = ({}: Route.MetaArgs) => [
|
||||
|
||||
export const loader = async ({ request }: Route.LoaderArgs) => {
|
||||
const auth = await getOptionalAuth(request);
|
||||
|
||||
// The rest of the landing page stands on its own, so a brewery service
|
||||
// outage degrades to the empty state instead of an error page.
|
||||
let recentBreweries: Brewery[] = [];
|
||||
|
||||
const randomOffset = Math.random() * 1.0
|
||||
try {
|
||||
recentBreweries = await getBreweries(PARTNER_BREWERY_COUNT, 0);
|
||||
} catch {
|
||||
|
||||
@@ -31,7 +31,7 @@ const TextTokenSample = ({
|
||||
}) => {
|
||||
return (
|
||||
<div className="rounded-box p-3" style={{ backgroundColor: `var(${background})` }}>
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
||||
<p className="text-xs font-semibold uppercase tracking-wide text-base-content/70">
|
||||
{label}
|
||||
</p>
|
||||
<p className="mt-1 text-sm font-medium" style={{ color: `var(${text})` }}>
|
||||
@@ -54,7 +54,7 @@ const ThemePanel = ({ label, value, vibe }: { label: string; value: string; vibe
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/70">
|
||||
Core
|
||||
</p>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
@@ -69,7 +69,7 @@ const ThemePanel = ({ label, value, vibe }: { label: string; value: string; vibe
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/70">
|
||||
Status
|
||||
</p>
|
||||
<div className="grid gap-2 grid-cols-2 sm:grid-cols-4">
|
||||
@@ -81,7 +81,7 @@ const ThemePanel = ({ label, value, vibe }: { label: string; value: string; vibe
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/50">
|
||||
<p className="mb-1.5 text-xs font-semibold uppercase tracking-wide text-base-content/70">
|
||||
Content
|
||||
</p>
|
||||
<div className="grid gap-2 sm:grid-cols-3">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const EmptyState = ({ message }: { message: string }) => (
|
||||
<div className="card bg-base-100 shadow">
|
||||
<div className="card-body items-center py-12">
|
||||
<p className="text-sm text-base-content/60 text-center m-0">{message}</p>
|
||||
<p className="text-sm text-base-content/70 text-center m-0">{message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ const ProfileSidebarCard = ({
|
||||
<div className="card-body gap-4 p-6">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold m-0 leading-tight">{displayName}</h1>
|
||||
<p className="text-sm text-base-content/60 m-0 mt-0.5">@{username}</p>
|
||||
<p className="text-sm text-base-content/70 m-0 mt-0.5">@{username}</p>
|
||||
</div>
|
||||
|
||||
{isOwnProfile ? (
|
||||
@@ -52,7 +52,7 @@ const ProfileSidebarCard = ({
|
||||
|
||||
<p className="text-sm leading-normal m-0">{bio}</p>
|
||||
|
||||
<div className="flex flex-col gap-1.5 text-sm text-base-content/60">
|
||||
<div className="flex flex-col gap-1.5 text-sm text-base-content/70">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<MapPin className="size-4 shrink-0" aria-hidden="true" />
|
||||
{location}
|
||||
@@ -68,7 +68,7 @@ const ProfileSidebarCard = ({
|
||||
<div className="flex flex-col gap-2">
|
||||
{stats.map((stat) => (
|
||||
<div key={stat.label} className="flex items-center justify-between gap-2">
|
||||
<span className="text-sm text-base-content/60">{stat.label}</span>
|
||||
<span className="text-sm text-base-content/70">{stat.label}</span>
|
||||
<span className="font-serif text-lg font-bold tabular-nums">
|
||||
{stat.value}
|
||||
</span>
|
||||
|
||||
@@ -24,7 +24,7 @@ const ProfileTabs = ({ activeTab, onChange, panels }: ProfileTabsProps) => {
|
||||
{TABS.map((tab) => (
|
||||
<Tab
|
||||
key={tab.id}
|
||||
className="-mb-px border-b-2 border-transparent py-3 text-sm font-semibold text-base-content/60 transition-colors hover:text-base-content focus:outline-none data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-primary data-[selected]:border-primary data-[selected]:text-primary"
|
||||
className="-mb-px border-b-2 border-transparent py-3 text-sm font-semibold text-base-content/70 transition-colors hover:text-base-content focus:outline-none data-[focus]:outline-2 data-[focus]:outline-offset-2 data-[focus]:outline-primary data-[selected]:border-primary data-[selected]:text-primary"
|
||||
>
|
||||
{tab.label}
|
||||
</Tab>
|
||||
|
||||
@@ -36,11 +36,11 @@ const ActivityTab = ({ activity }: ActivityTabProps) => {
|
||||
</div>
|
||||
)}
|
||||
{item.comment && (
|
||||
<p className="text-sm text-base-content/60 italic mt-1.5 mb-0">
|
||||
<p className="text-sm text-base-content/70 italic mt-1.5 mb-0">
|
||||
“{item.comment}”
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-base-content/60 mt-1.5 mb-0">
|
||||
<p className="text-xs text-base-content/70 mt-1.5 mb-0">
|
||||
{item.time}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +42,7 @@ const FollowingTab = ({ following, onToggleFollow }: FollowingTabProps) => {
|
||||
) : (
|
||||
<p className="font-semibold text-sm m-0 truncate">{f.name}</p>
|
||||
)}
|
||||
<p className="text-xs text-base-content/60 m-0 truncate">{f.meta}</p>
|
||||
<p className="text-xs text-base-content/70 m-0 truncate">{f.meta}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -18,7 +18,7 @@ const LikedTab = ({ liked }: LikedTabProps) => {
|
||||
<div className="h-[120px] bg-base-300" />
|
||||
<div className="card-body p-4 gap-1">
|
||||
<p className="font-serif font-bold m-0">{item.name}</p>
|
||||
<p className="text-sm text-base-content/60 m-0">{item.meta}</p>
|
||||
<p className="text-sm text-base-content/70 m-0">{item.meta}</p>
|
||||
<div className="mt-1">
|
||||
<StarRating value={item.rating} size="xs" />
|
||||
</div>
|
||||
|
||||
@@ -75,7 +75,7 @@ const ProfileContent = ({ profile, isOwnProfile }: ProfileContentProps) => {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-base-200 pb-16">
|
||||
<div className="max-w-[1080px] mx-auto px-6 pt-8">
|
||||
<div className="mx-auto max-w-7xl px-5 pt-10">
|
||||
<div className="rounded-box h-[190px] bg-base-300" />
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[300px_1fr] gap-8 items-start -mt-12">
|
||||
|
||||
Reference in New Issue
Block a user