Compare commits

...

3 Commits

Author SHA1 Message Date
hamid zarghami cee1f98972 deactive category
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled
2026-06-23 09:24:09 +03:30
hamid zarghami a0b0266b1a menu bottom color 2026-06-23 09:17:51 +03:30
hamid zarghami c282edd0c6 shadow and don't availablity 2026-06-23 09:07:01 +03:30
10 changed files with 86 additions and 32 deletions
+4 -2
View File
@@ -206,8 +206,10 @@ function FoodPage({}: Props) {
>
{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">
<PlusIcon />
<div className="text-sm2 pt-0.5 font-normal text-foreground">افزودن</div>
{isAvailable && <PlusIcon />}
<div className="text-sm2 pt-0.5 font-normal text-foreground">
{isAvailable ? "افزودن" : "عدم موجودی"}
</div>
</button>
) : (
<>
@@ -6,7 +6,7 @@ import CategorySmallItemRenderer from "@/components/listview/CategorySmallItemRe
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
import clsx from "clsx";
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 */
const COLORED_SVG_RESTAURANT_SLUGS = new Set(["havasone"]);
@@ -20,14 +20,14 @@ const SVG_MASK_STYLE = {
WebkitMaskPosition: "center",
} 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 shouldUseSvgMask = isSvg && tintWithPrimary;
if (shouldUseSvgMask) {
return (
<div
className="shrink-0 bg-primary"
className={clsx("shrink-0 bg-primary", disabled && "opacity-40")}
style={{
width: size,
height: size,
@@ -49,7 +49,7 @@ function CategoryImage({ src, size, alt, tintWithPrimary = true }: { src: string
height={size}
alt={alt}
loading="lazy"
className="shrink-0 object-contain"
className={clsx("shrink-0 object-contain", disabled && "opacity-40")}
onError={(event) => {
event.currentTarget.src = "/assets/images/food-image.png";
}}
@@ -109,11 +109,21 @@ const CategoryScroll = ({ categories, selectedCategory, onSelect, variant = "lar
</Renderer> */}
{categories.map((item) => {
const isSelected = item.id === selectedCategory;
const isDisabled = !item.isActive;
return (
<Renderer key={item.id} className={clsx(isSelected && GLASS_SURFACE_SELECTED)} onClick={handleSelect(item.id)}>
<CategoryImage src={item.avatarUrl || "/assets/images/food-image.png"} size={imageSize} alt="category image" tintWithPrimary={!usesColoredSvg} />
<span className="text-xs text-foreground text-center whitespace-nowrap">{item.title}</span>
<Renderer
key={item.id}
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>
);
})}
@@ -9,10 +9,10 @@ type Props = {
function CategoryItemRenderer({ children, ...rest }: Props) {
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
{...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}
</div>
@@ -9,10 +9,10 @@ type Props = {
function CategorySmallItemRenderer({ children, ...rest }: Props) {
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
{...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}
</div>
+2 -2
View File
@@ -161,9 +161,9 @@ const MenuItem = ({ food }: MenuItemProps) => {
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">
افزودن
{isAvailable ? "افزودن" : "عدم موجودی"}
</div>
</button>
) : (
+2 -8
View File
@@ -12,7 +12,6 @@ import HomeIcon from '../icons/HomeIcon'
import { useTranslation } from 'react-i18next';
import { useCart } from '@/app/[name]/(Main)/cart/hook/useCart';
import { Building } from 'iconsax-react';
import clsx from 'clsx';
import { glassSurfaceNav } from '@/lib/styles/glassSurface';
import { getBottomNavMaskStyle } from './bottomNavShape';
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
@@ -81,7 +80,7 @@ function BottomNavBar({ onPagerClick }: BottomNavBarProps) {
{onPagerClick ? (
<button
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} />
<span className="text-xs2">
@@ -104,12 +103,7 @@ function BottomNavBar({ onPagerClick }: BottomNavBarProps) {
value={t('Menu')} />
<Link
href={`/${name}/about`}
className={clsx(
'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',
)}
className="flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0 text-primary **:stroke-primary"
>
<div className="shrink-0">
<Building
+1 -7
View File
@@ -3,7 +3,6 @@
import Link from 'next/link'
import React from 'react'
import type { LinkProps } from 'next/link'
import { usePathname } from 'next/navigation'
import clsx from 'clsx'
type Props = {
@@ -12,16 +11,11 @@ type Props = {
} & LinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>
function BottomNavLink({ icon, value, href, prefetch, ...restProps }: Props) {
const pathname = usePathname();
const isActive = pathname === href;
const shouldPrefetch = prefetch ?? true;
return (
<Link {...restProps} href={href} prefetch={shouldPrefetch} className={clsx(
'flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0',
isActive
? 'text-primary **:stroke-primary'
: 'text-disabled-text **:stroke-disabled-text',
'flex flex-col justify-arround items-center gap-[5px] pointer-events-auto min-w-0 text-primary **:stroke-primary',
restProps.className ?? '',
)}>
<div className="shrink-0">
@@ -21,7 +21,7 @@ function BottomNavHighlightLink({ icon, value, href, ...restProps }: Props) {
)}>
{icon}
</div>
<span className="text-xs2 text-disabled-text">
<span className="text-xs2 text-primary">
{value}
</span>
</Link>
+1
View File
@@ -3,6 +3,7 @@ import clsx, { type ClassValue } from "clsx";
export const GLASS_SURFACE = "glass-surface";
export const GLASS_SURFACE_FLAT = "glass-surface--flat";
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 function glassSurfaceNav(...extra: ClassValue[]) {
+54 -1
View File
@@ -5,7 +5,7 @@
border: 1px solid rgba(255, 255, 255, 0.8);
-webkit-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,
@@ -17,6 +17,7 @@ html[data-image-bg="true"] .glass-surface {
html[data-theme="dark"] .glass-surface {
background-color: color-mix(in oklch, var(--container) 60%, transparent);
border-color: rgba(255, 255, 255, 0.2);
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
}
.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;
}
/* 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 {
background-color: rgba(255, 255, 255, 0.32);
border: 1px solid rgba(255, 255, 255, 0.8);