Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cee1f98972 | |||
| a0b0266b1a | |||
| c282edd0c6 |
@@ -206,8 +206,10 @@ function FoodPage({}: Props) {
|
|||||||
>
|
>
|
||||||
{quantity <= 0 ? (
|
{quantity <= 0 ? (
|
||||||
<button onClick={handleAddToCart} disabled={!isAvailable} className="inline-flex w-full justify-center items-center gap-2 disabled:pointer-events-none disabled:opacity-40">
|
<button onClick={handleAddToCart} disabled={!isAvailable} className="inline-flex w-full justify-center items-center gap-2 disabled:pointer-events-none disabled:opacity-40">
|
||||||
<PlusIcon />
|
{isAvailable && <PlusIcon />}
|
||||||
<div className="text-sm2 pt-0.5 font-normal text-foreground">افزودن</div>
|
<div className="text-sm2 pt-0.5 font-normal text-foreground">
|
||||||
|
{isAvailable ? "افزودن" : "عدم موجودی"}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import CategorySmallItemRenderer from "@/components/listview/CategorySmallItemRe
|
|||||||
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
|
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { GLASS_SURFACE_SELECTED } from "@/lib/styles/glassSurface";
|
import { GLASS_SURFACE_DISABLED, GLASS_SURFACE_SELECTED } from "@/lib/styles/glassSurface";
|
||||||
|
|
||||||
/** TODO: remove when backend sends avatarRenderMode */
|
/** TODO: remove when backend sends avatarRenderMode */
|
||||||
const COLORED_SVG_RESTAURANT_SLUGS = new Set(["havasone"]);
|
const COLORED_SVG_RESTAURANT_SLUGS = new Set(["havasone"]);
|
||||||
@@ -20,14 +20,14 @@ const SVG_MASK_STYLE = {
|
|||||||
WebkitMaskPosition: "center",
|
WebkitMaskPosition: "center",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
function CategoryImage({ src, size, alt, tintWithPrimary = true }: { src: string; size: number; alt: string; tintWithPrimary?: boolean }) {
|
function CategoryImage({ src, size, alt, tintWithPrimary = true, disabled = false }: { src: string; size: number; alt: string; tintWithPrimary?: boolean; disabled?: boolean }) {
|
||||||
const isSvg = src.endsWith(".svg");
|
const isSvg = src.endsWith(".svg");
|
||||||
const shouldUseSvgMask = isSvg && tintWithPrimary;
|
const shouldUseSvgMask = isSvg && tintWithPrimary;
|
||||||
|
|
||||||
if (shouldUseSvgMask) {
|
if (shouldUseSvgMask) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="shrink-0 bg-primary"
|
className={clsx("shrink-0 bg-primary", disabled && "opacity-40")}
|
||||||
style={{
|
style={{
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
@@ -49,7 +49,7 @@ function CategoryImage({ src, size, alt, tintWithPrimary = true }: { src: string
|
|||||||
height={size}
|
height={size}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
className="shrink-0 object-contain"
|
className={clsx("shrink-0 object-contain", disabled && "opacity-40")}
|
||||||
onError={(event) => {
|
onError={(event) => {
|
||||||
event.currentTarget.src = "/assets/images/food-image.png";
|
event.currentTarget.src = "/assets/images/food-image.png";
|
||||||
}}
|
}}
|
||||||
@@ -109,11 +109,21 @@ const CategoryScroll = ({ categories, selectedCategory, onSelect, variant = "lar
|
|||||||
</Renderer> */}
|
</Renderer> */}
|
||||||
{categories.map((item) => {
|
{categories.map((item) => {
|
||||||
const isSelected = item.id === selectedCategory;
|
const isSelected = item.id === selectedCategory;
|
||||||
|
const isDisabled = !item.isActive;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Renderer key={item.id} className={clsx(isSelected && GLASS_SURFACE_SELECTED)} onClick={handleSelect(item.id)}>
|
<Renderer
|
||||||
<CategoryImage src={item.avatarUrl || "/assets/images/food-image.png"} size={imageSize} alt="category image" tintWithPrimary={!usesColoredSvg} />
|
key={item.id}
|
||||||
<span className="text-xs text-foreground text-center whitespace-nowrap">{item.title}</span>
|
className={clsx(
|
||||||
|
isDisabled && GLASS_SURFACE_DISABLED,
|
||||||
|
isDisabled && "cursor-not-allowed",
|
||||||
|
isSelected && !isDisabled && GLASS_SURFACE_SELECTED,
|
||||||
|
)}
|
||||||
|
onClick={isDisabled ? undefined : handleSelect(item.id)}
|
||||||
|
aria-disabled={isDisabled}
|
||||||
|
>
|
||||||
|
<CategoryImage src={item.avatarUrl || "/assets/images/food-image.png"} size={imageSize} alt="category image" tintWithPrimary={!usesColoredSvg} disabled={isDisabled} />
|
||||||
|
<span className={clsx("text-xs text-center whitespace-nowrap", isDisabled ? "text-disabled-text" : "text-foreground")}>{item.title}</span>
|
||||||
</Renderer>
|
</Renderer>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ type Props = {
|
|||||||
|
|
||||||
function CategoryItemRenderer({ children, ...rest }: Props) {
|
function CategoryItemRenderer({ children, ...rest }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={glassSurface(rest.className, 'cursor-pointer transition-all duration-200 ease-out overflow-hidden rounded-xl')}>
|
<div className={glassSurface(rest.className, 'cursor-pointer transition-all duration-200 ease-out rounded-xl')}>
|
||||||
<div
|
<div
|
||||||
{...rest}
|
{...rest}
|
||||||
className="rounded-normal w-[108px] h-[88px] flex flex-col justify-center items-center gap-2"
|
className="rounded-normal w-[108px] h-[88px] flex flex-col justify-center items-center gap-2 overflow-hidden"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ type Props = {
|
|||||||
|
|
||||||
function CategorySmallItemRenderer({ children, ...rest }: Props) {
|
function CategorySmallItemRenderer({ children, ...rest }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={glassSurface(rest.className, 'cursor-pointer transition-all duration-200 ease-out overflow-hidden rounded-xl')}>
|
<div className={glassSurface(rest.className, 'cursor-pointer transition-all duration-200 ease-out rounded-xl')}>
|
||||||
<div
|
<div
|
||||||
{...rest}
|
{...rest}
|
||||||
className="rounded-normal h-[44px] flex flex-row justify-center items-center p-2.5 gap-2"
|
className="rounded-normal h-[44px] flex flex-row justify-center items-center p-2.5 gap-2 overflow-hidden"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -161,9 +161,9 @@ const MenuItem = ({ food }: MenuItemProps) => {
|
|||||||
disabled={!isAvailable}
|
disabled={!isAvailable}
|
||||||
className="inline-flex w-full justify-center items-center gap-2 disabled:pointer-events-none disabled:opacity-40"
|
className="inline-flex w-full justify-center items-center gap-2 disabled:pointer-events-none disabled:opacity-40"
|
||||||
>
|
>
|
||||||
<PlusIcon />
|
{isAvailable && <PlusIcon />}
|
||||||
<div className="text-sm2 pt-0.5 font-normal text-foreground">
|
<div className="text-sm2 pt-0.5 font-normal text-foreground">
|
||||||
افزودن
|
{isAvailable ? "افزودن" : "عدم موجودی"}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import HomeIcon from '../icons/HomeIcon'
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useCart } from '@/app/[name]/(Main)/cart/hook/useCart';
|
import { useCart } from '@/app/[name]/(Main)/cart/hook/useCart';
|
||||||
import { Building } from 'iconsax-react';
|
import { Building } from 'iconsax-react';
|
||||||
import clsx from 'clsx';
|
|
||||||
import { glassSurfaceNav } from '@/lib/styles/glassSurface';
|
import { glassSurfaceNav } from '@/lib/styles/glassSurface';
|
||||||
import { getBottomNavMaskStyle } from './bottomNavShape';
|
import { getBottomNavMaskStyle } from './bottomNavShape';
|
||||||
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
||||||
@@ -81,7 +80,7 @@ function BottomNavBar({ onPagerClick }: BottomNavBarProps) {
|
|||||||
{onPagerClick ? (
|
{onPagerClick ? (
|
||||||
<button
|
<button
|
||||||
onClick={onPagerClick}
|
onClick={onPagerClick}
|
||||||
className="flex flex-col justify-arround items-center gap-[5px] text-disabled-text pointer-events-auto **:stroke-disabled-text"
|
className="flex flex-col justify-arround items-center gap-[5px] text-primary pointer-events-auto **:stroke-primary"
|
||||||
>
|
>
|
||||||
<PagerIcon width={20} height={20} />
|
<PagerIcon width={20} height={20} />
|
||||||
<span className="text-xs2">
|
<span className="text-xs2">
|
||||||
@@ -104,12 +103,7 @@ function BottomNavBar({ onPagerClick }: BottomNavBarProps) {
|
|||||||
value={t('Menu')} />
|
value={t('Menu')} />
|
||||||
<Link
|
<Link
|
||||||
href={`/${name}/about`}
|
href={`/${name}/about`}
|
||||||
className={clsx(
|
className="flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0 text-primary **:stroke-primary"
|
||||||
'flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0',
|
|
||||||
isAboutRoute
|
|
||||||
? 'text-primary **:stroke-primary'
|
|
||||||
: 'text-disabled-text **:stroke-disabled-text',
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div className="shrink-0">
|
<div className="shrink-0">
|
||||||
<Building
|
<Building
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { LinkProps } from 'next/link'
|
import type { LinkProps } from 'next/link'
|
||||||
import { usePathname } from 'next/navigation'
|
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -12,16 +11,11 @@ type Props = {
|
|||||||
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
|
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
|
||||||
|
|
||||||
function BottomNavLink({ icon, value, href, prefetch, ...restProps }: Props) {
|
function BottomNavLink({ icon, value, href, prefetch, ...restProps }: Props) {
|
||||||
const pathname = usePathname();
|
|
||||||
const isActive = pathname === href;
|
|
||||||
const shouldPrefetch = prefetch ?? true;
|
const shouldPrefetch = prefetch ?? true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link {...restProps} href={href} prefetch={shouldPrefetch} className={clsx(
|
<Link {...restProps} href={href} prefetch={shouldPrefetch} className={clsx(
|
||||||
'flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0',
|
'flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0 text-primary **:stroke-primary',
|
||||||
isActive
|
|
||||||
? 'text-primary **:stroke-primary'
|
|
||||||
: 'text-disabled-text **:stroke-disabled-text',
|
|
||||||
restProps.className ?? '',
|
restProps.className ?? '',
|
||||||
)}>
|
)}>
|
||||||
<div className="shrink-0">
|
<div className="shrink-0">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function BottomNavHighlightLink({ icon, value, href, ...restProps }: Props) {
|
|||||||
)}>
|
)}>
|
||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs2 text-disabled-text">
|
<span className="text-xs2 text-primary">
|
||||||
{value}
|
{value}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import clsx, { type ClassValue } from "clsx";
|
|||||||
export const GLASS_SURFACE = "glass-surface";
|
export const GLASS_SURFACE = "glass-surface";
|
||||||
export const GLASS_SURFACE_FLAT = "glass-surface--flat";
|
export const GLASS_SURFACE_FLAT = "glass-surface--flat";
|
||||||
export const GLASS_SURFACE_SELECTED = "glass-surface--selected";
|
export const GLASS_SURFACE_SELECTED = "glass-surface--selected";
|
||||||
|
export const GLASS_SURFACE_DISABLED = "glass-surface--disabled";
|
||||||
export const GLASS_SURFACE_NAV = "glass-surface-nav";
|
export const GLASS_SURFACE_NAV = "glass-surface-nav";
|
||||||
|
|
||||||
export function glassSurfaceNav(...extra: ClassValue[]) {
|
export function glassSurfaceNav(...extra: ClassValue[]) {
|
||||||
|
|||||||
+54
-1
@@ -5,7 +5,7 @@
|
|||||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
-webkit-backdrop-filter: blur(3px);
|
-webkit-backdrop-filter: blur(3px);
|
||||||
backdrop-filter: blur(3px);
|
backdrop-filter: blur(3px);
|
||||||
box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-pattern-bg="true"] .glass-surface,
|
html[data-pattern-bg="true"] .glass-surface,
|
||||||
@@ -17,6 +17,7 @@ html[data-image-bg="true"] .glass-surface {
|
|||||||
html[data-theme="dark"] .glass-surface {
|
html[data-theme="dark"] .glass-surface {
|
||||||
background-color: color-mix(in oklch, var(--container) 60%, transparent);
|
background-color: color-mix(in oklch, var(--container) 60%, transparent);
|
||||||
border-color: rgba(255, 255, 255, 0.2);
|
border-color: rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.glass-surface--flat {
|
.glass-surface--flat {
|
||||||
@@ -31,6 +32,58 @@ html[data-theme="dark"] .glass-surface--selected {
|
|||||||
background-color: color-mix(in oklch, var(--container) 85%, transparent) !important;
|
background-color: color-mix(in oklch, var(--container) 85%, transparent) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Figma disabled category: white 40%, 2px inner gradient border, blur 12 */
|
||||||
|
.glass-surface--disabled {
|
||||||
|
position: relative;
|
||||||
|
background-color: rgba(255, 255, 255, 0.4) !important;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-surface--disabled::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
padding: 2px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(255, 255, 255, 1) 0%,
|
||||||
|
rgba(255, 253, 253, 0) 50%,
|
||||||
|
rgba(255, 255, 255, 1) 100%
|
||||||
|
);
|
||||||
|
-webkit-mask:
|
||||||
|
linear-gradient(#fff 0 0) content-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
mask:
|
||||||
|
linear-gradient(#fff 0 0) content-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: xor;
|
||||||
|
mask-composite: exclude;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-pattern-bg="true"] .glass-surface--disabled,
|
||||||
|
html[data-image-bg="true"] .glass-surface--disabled {
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] .glass-surface--disabled {
|
||||||
|
background-color: color-mix(in oklch, var(--container) 40%, transparent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] .glass-surface--disabled::before {
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(255, 255, 255, 0.35) 0%,
|
||||||
|
rgba(255, 255, 255, 0) 50%,
|
||||||
|
rgba(255, 255, 255, 0.35) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
.glass-surface-nav {
|
.glass-surface-nav {
|
||||||
background-color: rgba(255, 255, 255, 0.32);
|
background-color: rgba(255, 255, 255, 0.32);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
|||||||
Reference in New Issue
Block a user