Compare commits

...
10 Commits
Author SHA1 Message Date
Hamed 3f344fa1a8 update 2026-09-01 10:46:31 +04:00
Hamed 1d5b638f3e update 2026-08-18 15:29:01 +04:00
Hamed aa6cb26b46 update 2026-08-06 08:01:35 +04:00
Hamed fe1f17f740 update 2026-08-05 12:37:33 +04:00
Hamed 494fc9f79b update 2026-08-05 12:21:37 +04:00
Hamed d631174d40 update 2026-08-05 11:43:58 +04:00
Hamed 121287e105 update 2026-08-05 11:28:05 +04:00
Hamed fbacd2ca22 update 2026-08-03 15:19:57 +04:00
Hamed 711ac3668c update 2026-08-03 14:50:00 +04:00
Hamed 5594c3c25b update 2026-08-03 14:48:01 +04:00
87 changed files with 590 additions and 201 deletions
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>
+168 -3
View File
@@ -1,7 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="bb7b50a5-be9c-4cd7-a05b-979f0e91b173" name="Changes" comment="update" /> <list default="true" id="bb7b50a5-be9c-4cd7-a05b-979f0e91b173" name="Changes" comment="update">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -15,6 +20,65 @@
<scroll-view-position x="0" y="0" /> <scroll-view-position x="0" y="0" />
</layout> </layout>
</component> </component>
<component name="NextEditCompletionFeaturesState">
<decayedCancelled>
<entry key="MS100" value="1.9180577791458209" />
<entry key="MS500" value="4.688644388100796" />
<entry key="S2" value="8.26749701184336" />
<entry key="S5" value="10.565752377401568" />
<entry key="S10" value="11.665306157952212" />
<entry key="S30" value="12.525747261610114" />
<entry key="S60" value="12.758981623001501" />
<entry key="M2" value="12.87850025822862" />
<entry key="M5" value="12.951160086704387" />
<entry key="M10" value="12.975539848697636" />
<entry key="M15" value="12.983684286049057" />
<entry key="M30" value="12.99183766624342" />
<entry key="H1" value="12.995917713255967" />
<entry key="H2" value="12.997958576577691" />
<entry key="H4" value="12.99897921826579" />
<entry key="D1" value="12.999829859984649" />
<entry key="W1" value="12.999975694045316" />
</decayedCancelled>
<decayedSelected>
<entry key="MS100" value="0.0" />
<entry key="MS500" value="0.0" />
<entry key="S2" value="0.0" />
<entry key="S5" value="0.0" />
<entry key="S10" value="0.0" />
<entry key="S30" value="0.0" />
<entry key="S60" value="0.0" />
<entry key="M2" value="0.0" />
<entry key="M5" value="0.0" />
<entry key="M10" value="0.0" />
<entry key="M15" value="0.0" />
<entry key="M30" value="0.0" />
<entry key="H1" value="0.0" />
<entry key="H2" value="0.0" />
<entry key="H4" value="0.0" />
<entry key="D1" value="0.0" />
<entry key="W1" value="0.0" />
</decayedSelected>
<decayedShown>
<entry key="MS100" value="1.7420918727122994" />
<entry key="MS500" value="4.512290317154382" />
<entry key="S2" value="8.19204120547899" />
<entry key="S5" value="10.528482205836237" />
<entry key="S10" value="11.645001964515167" />
<entry key="S30" value="12.518545816831239" />
<entry key="S60" value="12.755322274489146" />
<entry key="M2" value="12.876655570534636" />
<entry key="M5" value="12.950418561706101" />
<entry key="M10" value="12.97516847394418" />
<entry key="M15" value="12.98343656653061" />
<entry key="M30" value="12.991713738236065" />
<entry key="H1" value="12.995855732176478" />
<entry key="H2" value="12.997927581767277" />
<entry key="H4" value="12.998963719792695" />
<entry key="D1" value="12.999827276757467" />
<entry key="W1" value="12.999975325009228" />
</decayedShown>
</component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
&quot;customColor&quot;: &quot;&quot;, &quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 2 &quot;associatedIndex&quot;: 2
@@ -33,18 +97,30 @@
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;, &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;, &quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;, &quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;javascript.nodejs.core.library.configured.version&quot;: &quot;26.3.0&quot;,
&quot;javascript.nodejs.core.library.typings.version&quot;: &quot;26.1.2&quot;,
&quot;javascript.preferred.runtime.type.id&quot;: &quot;node&quot;, &quot;javascript.preferred.runtime.type.id&quot;: &quot;node&quot;,
&quot;js.debugger.nextJs.config.created.client&quot;: &quot;true&quot;, &quot;js.debugger.nextJs.config.created.client&quot;: &quot;true&quot;,
&quot;js.debugger.nextJs.config.created.server&quot;: &quot;true&quot;, &quot;js.debugger.nextJs.config.created.server&quot;: &quot;true&quot;,
&quot;kronk.content.tree.expanded.paths&quot;: &quot;&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/Project/GitHubRepo/robot-market-landing&quot;, &quot;last_opened_file_path&quot;: &quot;D:/Project/GitHubRepo/robot-market-landing&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;editor.preferences.fonts.default&quot;, &quot;settings.editor.selected.configurable&quot;: &quot;editor.preferences.fonts.default&quot;,
&quot;ts.external.directory.path&quot;: &quot;C:\\Program Files\\JetBrains\\WebStorm 2026.1.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external&quot;, &quot;ts.external.directory.path&quot;: &quot;C:\\Program Files\\JetBrains\\WebStorm 2026.1.1\\plugins\\javascript-plugin\\jsLanguageServicesImpl\\external&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}</component> }</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\Project\GitHubRepo\robot-market-landing\public\images\icons" />
<recent name="D:\Project\GitHubRepo\robot-market-landing\public\images" />
<recent name="D:\Project\GitHubRepo\robot-market-landing\app" />
</key>
</component>
<component name="RunManager" selected="npm.Next.js: server-side"> <component name="RunManager" selected="npm.Next.js: server-side">
<configuration name="Next.js: debug client-side" type="JavascriptDebugType" uri="http://localhost:3000/"> <configuration name="Next.js: debug client-side" type="JavascriptDebugType" uri="http://localhost:3000/">
<method v="2" /> <method v="2" />
@@ -63,7 +139,7 @@
<component name="SharedIndexes"> <component name="SharedIndexes">
<attachedChunks> <attachedChunks>
<set> <set>
<option value="bundled-js-predefined-d6986cc7102b-31caf2ab9e3c-JavaScript-WS-261.23567.141" /> <option value="bundled-js-predefined-d6986cc7102b-31caf2ab9e3c-JavaScript-WS-261.27258.45" />
</set> </set>
</attachedChunks> </attachedChunks>
</component> </component>
@@ -84,6 +160,20 @@
<workItem from="1785645096071" duration="26000" /> <workItem from="1785645096071" duration="26000" />
<workItem from="1785646314677" duration="16621000" /> <workItem from="1785646314677" duration="16621000" />
<workItem from="1785730130350" duration="12049000" /> <workItem from="1785730130350" duration="12049000" />
<workItem from="1785757166936" duration="5000" />
<workItem from="1785901279535" duration="17323000" />
<workItem from="1785988592310" duration="763000" />
<workItem from="1785993398943" duration="489000" />
<workItem from="1785995385816" duration="1586000" />
<workItem from="1785999660169" duration="117000" />
<workItem from="1785999908774" duration="697000" />
<workItem from="1786434051896" duration="714000" />
<workItem from="1787030163530" duration="2042000" />
<workItem from="1787052515900" duration="43000" />
<workItem from="1787980069071" duration="1369000" />
<workItem from="1787993488084" duration="706000" />
<workItem from="1788148958104" duration="1576000" />
<workItem from="1788244010046" duration="1115000" />
</task> </task>
<task id="LOCAL-00001" summary="update"> <task id="LOCAL-00001" summary="update">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -197,12 +287,87 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1785747909967</updated> <updated>1785747909967</updated>
</task> </task>
<option name="localTasksCounter" value="15" /> <task id="LOCAL-00015" summary="update">
<option name="closed" value="true" />
<created>1785754086526</created>
<option name="number" value="00015" />
<option name="presentableId" value="LOCAL-00015" />
<option name="project" value="LOCAL" />
<updated>1785754086526</updated>
</task>
<task id="LOCAL-00016" summary="update">
<option name="closed" value="true" />
<created>1785754201946</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1785754201946</updated>
</task>
<task id="LOCAL-00017" summary="update">
<option name="closed" value="true" />
<created>1785755999255</created>
<option name="number" value="00017" />
<option name="presentableId" value="LOCAL-00017" />
<option name="project" value="LOCAL" />
<updated>1785755999255</updated>
</task>
<task id="LOCAL-00018" summary="update">
<option name="closed" value="true" />
<created>1785914887554</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1785914887554</updated>
</task>
<task id="LOCAL-00019" summary="update">
<option name="closed" value="true" />
<created>1785915840468</created>
<option name="number" value="00019" />
<option name="presentableId" value="LOCAL-00019" />
<option name="project" value="LOCAL" />
<updated>1785915840468</updated>
</task>
<task id="LOCAL-00020" summary="update">
<option name="closed" value="true" />
<created>1785918100372</created>
<option name="number" value="00020" />
<option name="presentableId" value="LOCAL-00020" />
<option name="project" value="LOCAL" />
<updated>1785918100372</updated>
</task>
<task id="LOCAL-00021" summary="update">
<option name="closed" value="true" />
<created>1785919055708</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1785919055708</updated>
</task>
<task id="LOCAL-00022" summary="update">
<option name="closed" value="true" />
<created>1785988898095</created>
<option name="number" value="00022" />
<option name="presentableId" value="LOCAL-00022" />
<option name="project" value="LOCAL" />
<updated>1785988898096</updated>
</task>
<task id="LOCAL-00023" summary="update">
<option name="closed" value="true" />
<created>1787052543722</created>
<option name="number" value="00023" />
<option name="presentableId" value="LOCAL-00023" />
<option name="project" value="LOCAL" />
<updated>1787052543722</updated>
</task>
<option name="localTasksCounter" value="24" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" /> <option name="version" value="3" />
</component> </component>
<component name="UnknownFeatures">
<option featureType="com.intellij.fileTypeFactory" implementationName="next.config.js" />
</component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="ui : change the position of header in Hero Section" /> <MESSAGE value="ui : change the position of header in Hero Section" />
<MESSAGE value="update" /> <MESSAGE value="update" />
+5
View File
@@ -0,0 +1,5 @@
.PHONY: push
push:
git push origin HEAD
git push gitea HEAD
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

+7
View File
@@ -8,12 +8,19 @@ const vazirmatn = Vazirmatn({
display: 'swap', display: 'swap',
}); });
export const metadata = { export const metadata = {
title: 'روبات مارکت | دستگاه‌های وندینگ هوشمند', title: 'روبات مارکت | دستگاه‌های وندینگ هوشمند',
description: description:
'روبات مارکت؛ دستگاه‌های فروش خودکار هوشمند با مدیریت آنلاین، تحویل نرم و طراحی مدرن.', 'روبات مارکت؛ دستگاه‌های فروش خودکار هوشمند با مدیریت آنلاین، تحویل نرم و طراحی مدرن.',
}; };
export const viewport = {
themeColor: '#00a693',
};
export default function RootLayout({children}) { export default function RootLayout({children}) {
return ( return (
+2 -2
View File
@@ -1,6 +1,5 @@
import Header from '@/components/Header'; import Header from '@/components/Header';
import HeroSection from '@/components/HeroSection'; import HeroSection from '@/components/HeroSection';
import HorizontalShowcase from '@/components/HorizontalShowcase';
import TrustedBySection from '@/components/TrustedBySection'; import TrustedBySection from '@/components/TrustedBySection';
import FeaturesSection from '@/components/FeaturesSection'; import FeaturesSection from '@/components/FeaturesSection';
import AboutSection from '@/components/AboutSection'; import AboutSection from '@/components/AboutSection';
@@ -12,6 +11,7 @@ import TicketForm from '@/components/TicketForm';
import Footer from '@/components/Footer'; import Footer from '@/components/Footer';
import CartDrawer from '@/components/CartDrawer'; import CartDrawer from '@/components/CartDrawer';
import ChatWidget from '@/components/ChatWidget'; import ChatWidget from '@/components/ChatWidget';
import ShowcaseSection from "@/components/ShowcaseSection";
export default function HomePage() { export default function HomePage() {
@@ -25,7 +25,7 @@ export default function HomePage() {
<HeroSection/> <HeroSection/>
<HorizontalShowcase/> <ShowcaseSection/>
<TrustedBySection/> <TrustedBySection/>
+42 -42
View File
@@ -2,56 +2,56 @@
// رندر آیتم‌های شناور (چیپس/نوشابه) دور دستگاه با حرکت تصادفی و ملایم GSAP. // رندر آیتم‌های شناور (چیپس/نوشابه) دور دستگاه با حرکت تصادفی و ملایم GSAP.
import { useEffect, useRef } from 'react'; import {useEffect, useRef} from 'react';
import { gsap } from 'gsap'; import {gsap} from 'gsap';
/** /**
* Renders the centralized `floatingSnacks` config as absolutely-positioned * Renders the centralized `floatingSnacks` config as absolutely-positioned
* images and gives each one a gentle, randomized floating drift via GSAP. * images and gives each one a gentle, randomized floating drift via GSAP.
* Positions/sizes/images all come from data/content.js — edit there only. * Positions/sizes/images all come from data/content.js — edit there only.
*/ */
export default function FloatingItems({ items }) { export default function FloatingItems({items}) {
const containerRef = useRef(null); const containerRef = useRef(null);
useEffect(() => { useEffect(() => {
const nodes = containerRef.current?.querySelectorAll('[data-float-item]'); const nodes = containerRef.current?.querySelectorAll('[data-float-item]');
if (!nodes) return; if (!nodes) return;
const tweens = Array.from(nodes).map((node, i) => { const tweens = Array.from(nodes).map((node, i) => {
const drift = 14 + Math.random() * 14; const drift = 14 + Math.random() * 14;
const rotate = 4 + Math.random() * 6; const rotate = 4 + Math.random() * 6;
return gsap.to(node, { return gsap.to(node, {
y: `+=${drift}`, y: `+=${drift}`,
rotate: i % 2 === 0 ? rotate : -rotate, rotate: i % 2 === 0 ? rotate : -rotate,
duration: 3.5 + Math.random() * 2.5, duration: 3.5 + Math.random() * 2.5,
ease: 'sine.inOut', ease: 'sine.inOut',
yoyo: true, yoyo: true,
repeat: -1, repeat: -1,
delay: Math.random() * 1.5, delay: Math.random() * 1.5,
}); });
}); });
return () => tweens.forEach((t) => t.kill()); return () => tweens.forEach((t) => t.kill());
}, [items]); }, [items]);
return ( return (
<div ref={containerRef} className="absolute inset-0 pointer-events-none"> <div ref={containerRef} className="absolute inset-0 pointer-events-none hidden md:block">
{items.map((item) => ( {items.map((item) => (
<img <img
key={item.id} key={item.id}
data-float-item data-float-item
src={item.image} src={item.image}
alt="" alt=""
aria-hidden="true" aria-hidden="true"
className="absolute drop-shadow-[0_8px_20px_rgba(0,0,0,0.35)]" className="absolute drop-shadow-[0_8px_20px_rgba(0,0,0,0.35)]"
style={{ style={{
top: item.top, top: item.top,
left: item.left, left: item.left,
width: item.size, width: item.size,
height: 'auto', height: 'auto',
}} }}
/> />
))} ))}
</div> </div>
); );
} }
+1 -1
View File
@@ -44,7 +44,7 @@ export default function Header() {
> >
<div className="mx-auto max-w-7xl px-5 md:px-8 h-20 flex items-center justify-between gap-4"> <div className="mx-auto max-w-7xl px-5 md:px-8 h-20 flex items-center justify-between gap-4">
<a href="#hero" className="flex items-center gap-2 shrink-0"> <a href="#hero" className="flex items-center gap-2 shrink-0">
<Image src="/images/logo.png" alt="روبات مارکت" width={150} height={42} priority/> <Image src="/images/icons/logo.png" alt="روبات مارکت" width={150} height={42} priority/>
</a> </a>
<nav className="hidden xl:flex items-center gap-5 2xl:gap-7"> <nav className="hidden xl:flex items-center gap-5 2xl:gap-7">
+36 -16
View File
@@ -1,9 +1,5 @@
'use client'; 'use client';
// سکشن ویترین محصولات: با اسکرول عمودی به اسکرول افقی پین‌شده تبدیل می‌شود (GSAP ScrollTrigger)
// و یک ویدیوی پس‌زمینه دارد که با پیشرفت اسکرول جلو/عقب می‌رود. طبق درخواست کاربر، این سکشن
// و هیرو از چرخه‌ی رنگ‌بندی متناوب بقیه سکشن‌ها مستثنا هستند.
import {useEffect, useRef, useState} from 'react'; import {useEffect, useRef, useState} from 'react';
import {gsap} from 'gsap'; import {gsap} from 'gsap';
import {ScrollTrigger} from 'gsap/ScrollTrigger'; import {ScrollTrigger} from 'gsap/ScrollTrigger';
@@ -30,9 +26,28 @@ export default function HorizontalShowcase() {
const ctx = gsap.context(() => { const ctx = gsap.context(() => {
const track = trackRef.current; const track = trackRef.current;
const section = sectionRef.current; const section = sectionRef.current;
if (!track || !section) return; if (!track || !section) return;
const scrollDistance = () => track.scrollWidth - window.innerWidth; const scrollDistance = () => (
Math.max(track.scrollWidth - window.innerWidth, 0)
);
let animationFrameId = null;
let latestProgress = 0;
const syncVideo = (progress) => {
latestProgress = progress;
if (animationFrameId !== null) return;
animationFrameId = window.requestAnimationFrame(() => {
const video = videoRef.current;
if (video && Number.isFinite(video.duration) && video.duration > 0) {
video.currentTime = latestProgress * video.duration;
}
animationFrameId = null;
});
};
const horizontalTween = gsap.to(track, { const horizontalTween = gsap.to(track, {
x: () => -scrollDistance(), x: () => -scrollDistance(),
@@ -44,16 +59,12 @@ export default function HorizontalShowcase() {
scrub: 1, scrub: 1,
pin: true, pin: true,
invalidateOnRefresh: true, invalidateOnRefresh: true,
onUpdate: (self) => { onUpdate: (self) => syncVideo(self.progress),
const video = videoRef.current;
if (video && video.duration) {
video.currentTime = self.progress * video.duration;
}
},
}, },
}); });
return () => { return () => {
if (animationFrameId !== null) window.cancelAnimationFrame(animationFrameId);
horizontalTween.scrollTrigger?.kill(); horizontalTween.scrollTrigger?.kill();
horizontalTween.kill(); horizontalTween.kill();
}; };
@@ -64,6 +75,7 @@ export default function HorizontalShowcase() {
const handleModalAddToCart = () => { const handleModalAddToCart = () => {
if (!quickViewMachine) return; if (!quickViewMachine) return;
dispatch( dispatch(
addToCart({ addToCart({
id: quickViewMachine.id, id: quickViewMachine.id,
@@ -73,6 +85,7 @@ export default function HorizontalShowcase() {
image: quickViewMachine.image, image: quickViewMachine.image,
}) })
); );
message.success(t.cart.addToast(quickViewMachine.name)); message.success(t.cart.addToast(quickViewMachine.name));
setQuickViewMachine(null); setQuickViewMachine(null);
}; };
@@ -115,12 +128,19 @@ export default function HorizontalShowcase() {
> >
{quickViewMachine && ( {quickViewMachine && (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<img src={quickViewMachine.image} alt={quickViewMachine.name} <img
className="w-full h-64 object-contain"/> src={quickViewMachine.image}
alt={quickViewMachine.name}
className="w-full h-64 object-contain"
/>
<p className="text-secondary leading-7">{quickViewMachine.description}</p> <p className="text-secondary leading-7">{quickViewMachine.description}</p>
<p className="text-xl font-bold text-primary">{quickViewMachine.priceLabel}</p> <p className="text-xl font-bold text-primary">{quickViewMachine.priceLabel}</p>
<Button type="primary" size="large" icon={<ShoppingCartOutlined/>} <Button
onClick={handleModalAddToCart}> type="primary"
size="large"
icon={<ShoppingCartOutlined/>}
onClick={handleModalAddToCart}
>
{t.machineActions.addToCart} {t.machineActions.addToCart}
</Button> </Button>
</div> </div>
@@ -128,4 +148,4 @@ export default function HorizontalShowcase() {
</Modal> </Modal>
</section> </section>
); );
} }
+1 -2
View File
@@ -95,8 +95,7 @@ export default function MapSection() {
<div className="grid lg:grid-cols-[1.3fr,1fr] gap-6"> <div className="grid lg:grid-cols-[1.3fr,1fr] gap-6">
<div className="rounded-2xl overflow-hidden border border-subtle h-[360px] lg:h-auto min-h-[360px]"> <div className="rounded-2xl overflow-hidden border border-subtle h-[360px] lg:h-auto min-h-[360px]">
{/*<MapThumb coords={pins[0].coords} mapStyle={mapStyle} alt={pins[0].label} />*/} <MapThumb coords={pins[0].coords} mapStyle={mapStyle} alt={pins[0].label}/>
<Image src="/images/map.png" alt="روبات مارکت" width={600} height={600} className={"object-contain"} />
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
+107
View File
@@ -0,0 +1,107 @@
'use client';
import {useState} from 'react';
import {Modal, Button, message} from 'antd';
import {ShoppingCartOutlined, EyeOutlined} from '@ant-design/icons';
import {useDispatch} from 'react-redux';
import {useLanguage} from '@/app/context/LanguageContext';
import {addToCart} from '@/store/cartSlice';
export default function MobileShowcase() {
const dispatch = useDispatch();
const {t, dir} = useLanguage();
const [quickViewMachine, setQuickViewMachine] = useState(null);
const handleAddToCart = (machine) => {
dispatch(
addToCart({
id: machine.id,
name: machine.name,
priceNumeric: machine.priceNumeric,
priceLabel: machine.priceLabel,
image: machine.image,
})
);
message.success(t.cart.addToast(machine.name));
};
const handleModalAddToCart = () => {
if (!quickViewMachine) return;
handleAddToCart(quickViewMachine);
setQuickViewMachine(null);
};
return (
<section id="showcase" className="relative w-full py-8 px-4" dir={dir}>
<div className="flex flex-col gap-4">
{t.machines.map((machine) => (
<div
key={machine.id}
className="flex gap-4 items-center bg-surface border border-subtle rounded-2xl p-4"
>
<img
src={machine.image}
alt={machine.name}
className="w-24 h-24 object-contain shrink-0"
onClick={() => setQuickViewMachine(machine)}
/>
<div className="flex flex-col gap-1.5 min-w-0 flex-1">
<span className="text-brand-400 text-xs font-semibold tracking-wide">
{machine.shortLabel}
</span>
<h3 className="text-lg font-bold text-primary truncate">
{machine.name}
</h3>
<p className="text-sm text-secondary line-clamp-2">
{machine.description}
</p>
<p className="text-base font-bold text-primary mt-1">
{machine.priceLabel}
</p>
<div className="flex justify-start items-center mt-3">
<Button
type="primary"
size="middle"
icon={<ShoppingCartOutlined/>}
onClick={() => handleAddToCart(machine)}
>
{t.machineActions.addToCart}
</Button>
</div>
</div>
</div>
))}
</div>
<Modal
open={!!quickViewMachine}
onCancel={() => setQuickViewMachine(null)}
footer={null}
centered
title={quickViewMachine?.name}
>
{quickViewMachine && (
<div className="flex flex-col gap-4">
<img
src={quickViewMachine.image}
alt={quickViewMachine.name}
className="w-full h-64 object-contain"
/>
<p className="text-secondary leading-7">{quickViewMachine.description}</p>
<p className="text-xl font-bold text-primary">{quickViewMachine.priceLabel}</p>
<Button
type="primary"
size="large"
icon={<ShoppingCartOutlined/>}
onClick={handleModalAddToCart}
>
{t.machineActions.addToCart}
</Button>
</div>
)}
</Modal>
</section>
);
}
+28
View File
@@ -0,0 +1,28 @@
'use client';
import {useEffect, useState} from 'react';
import HorizontalShowcase from './HorizontalShowcase';
import MobileShowcase from './MobileShowcase';
const MOBILE_BREAKPOINT = 768;
export default function ShowcaseSection() {
const [isMobile, setIsMobile] = useState(null);
useEffect(() => {
const mediaQuery = window.matchMedia(
`(max-width: ${MOBILE_BREAKPOINT - 1}px)`
);
const handleChange = (event) => setIsMobile(event.matches);
setIsMobile(mediaQuery.matches);
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, []);
if (isMobile === null) return null;
return isMobile ? <MobileShowcase/> : <HorizontalShowcase/>;
}
+99 -107
View File
@@ -1,123 +1,115 @@
'use client'; 'use client';
// کارت نمایش هر دستگاه داخل ویترین: شامل جلوه اسپات‌لایت (هاور روی عکس دستگاه رنگ جایگزین را نشان می‌دهد)،
// آیتم‌های شناور، گیف+توضیحات، و دکمه‌های افزودن به سبد / مشاهده سریع / علاقه‌مندی.
import { useRef, useState } from 'react'; import {useRef} from 'react';
import { Button, Tooltip, message } from 'antd'; import {Button, message} from 'antd';
import { ShoppingCartOutlined, EyeOutlined, HeartOutlined, HeartFilled } from '@ant-design/icons'; import {ShoppingCartOutlined, EyeOutlined} from '@ant-design/icons';
import { useDispatch } from 'react-redux'; import {useDispatch} from 'react-redux';
import { addToCart } from '@/store/cartSlice'; import {addToCart} from '@/store/cartSlice';
import { useLanguage } from '@/app/context/LanguageContext'; import {useLanguage} from '@/app/context/LanguageContext';
import FloatingItems from './FloatingItems'; import FloatingItems from './FloatingItems';
import { floatingSnacks } from '@/data/content'; import {floatingSnacks} from '@/data/content';
export default function VendingCard({ machine, onQuickView }) { export default function VendingCard({machine, onQuickView}) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { t, dir } = useLanguage(); const {t, dir} = useLanguage();
const [wishlisted, setWishlisted] = useState(false); const stageRef = useRef(null);
const stageRef = useRef(null); const lensRef = useRef(null);
const lensRef = useRef(null); const revealRef = useRef(null);
const revealRef = useRef(null);
const handleMouseMove = (e) => { const handleMouseMove = (e) => {
const stage = stageRef.current; const stage = stageRef.current;
if (!stage) return; if (!stage) return;
const rect = stage.getBoundingClientRect(); const rect = stage.getBoundingClientRect();
const x = e.clientX - rect.left; const x = e.clientX - rect.left;
const y = e.clientY - rect.top; const y = e.clientY - rect.top;
if (lensRef.current) { if (lensRef.current) {
lensRef.current.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`; lensRef.current.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`;
} }
if (revealRef.current) { if (revealRef.current) {
revealRef.current.style.clipPath = `circle(95px at ${x}px ${y}px)`; revealRef.current.style.clipPath = `circle(95px at ${x}px ${y}px)`;
} }
}; };
const handleMouseLeave = () => { const handleMouseLeave = () => {
if (revealRef.current) revealRef.current.style.clipPath = 'circle(0px at 50% 50%)'; if (revealRef.current) revealRef.current.style.clipPath = 'circle(0px at 50% 50%)';
}; };
const handleAddToCart = () => { const handleAddToCart = () => {
dispatch( dispatch(
addToCart({ addToCart({
id: machine.id, id: machine.id,
name: machine.name, name: machine.name,
priceNumeric: machine.priceNumeric, priceNumeric: machine.priceNumeric,
priceLabel: machine.priceLabel, priceLabel: machine.priceLabel,
image: machine.image, image: machine.image,
}) })
); );
message.success(t.cart.addToast(machine.name)); message.success(t.cart.addToast(machine.name));
}; };
return ( return (
<div className="horizontal-panel flex items-center justify-center px-6 md:px-16" dir={dir}> <div className="horizontal-panel flex items-center justify-center px-6 md:px-16" dir={dir}>
<div className="relative z-10 max-w-6xl w-full grid md:grid-cols-2 gap-10 items-center"> <div className="relative z-10 max-w-6xl w-full grid md:grid-cols-2 gap-0 md:gap-10 items-center">
<div <div
ref={stageRef} ref={stageRef}
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
className="spotlight-stage relative h-[420px] md:h-[560px] flex items-center justify-center" className="spotlight-stage relative h-48 md:h-[500px] flex items-center justify-center"
> >
<FloatingItems items={floatingSnacks} /> <FloatingItems items={floatingSnacks}/>
<img src={machine.image} alt={machine.name} className="base-layer z-10" /> <img src={machine.image} alt={machine.name} className="base-layer z-10"/>
<img <img
ref={revealRef} ref={revealRef}
src={machine.imageAlt} src={machine.imageAlt}
alt={`${machine.name} - ${t.machineActions.altVariant}`} alt={`${machine.name} - ${t.machineActions.altVariant}`}
className="reveal-layer z-20" className="reveal-layer z-20"
/> />
<div ref={lensRef} className="spotlight-lens" /> <div ref={lensRef} className="spotlight-lens"/>
<span className="absolute top-3 z-30 text-[11px] px-3 py-1 rounded-full bg-brand/15 border border-subtle text-brand-400 start-3"> <span
className="absolute hidden md:block top-3 z-30 text-[11px] px-3 py-1 rounded-full bg-brand/15 border border-subtle text-brand-400 start-3">
{t.machineActions.hoverHint} {t.machineActions.hoverHint}
</span> </span>
</div>
<div className="flex flex-col justify-center items-center gap-5 ">
<span className="text-brand-400 text-sm font-semibold tracking-wide">{machine.shortLabel}</span>
<h3 className="text-2xl md:text-4xl font-extrabold text-primary">{machine.name}</h3>
<div
className="grid grid-cols-[auto,1fr] gap-4 items-start bg-surface border border-subtle rounded-2xl p-4">
<img
src={machine.gif}
alt={t.machineActions.gifAlt(machine.name)}
className="w-28 h-14 md:w-32 md:h-24 object-cover rounded-lg border border-subtle"
/>
<p className="text-sm md:text-base text-secondary md:leading-7">{machine.description}</p>
</div>
<ul className="flex flex-wrap gap-2">
{machine.highlights.map((h) => (
<li key={h}
className="text-xs md:text-sm text-brand-400 bg-brand/10 border border-subtle rounded-full px-3 py-1">
{h}
</li>
))}
</ul>
<p className="text-xl md:text-2xl font-bold text-primary mt-2">{machine.priceLabel}</p>
<div className="flex flex-wrap items-center gap-2 mt-2 ">
<Button type="primary" size="large" icon={<ShoppingCartOutlined/>} onClick={handleAddToCart}>
{t.machineActions.addToCart}
</Button>
<Button size="large" icon={<EyeOutlined/>} onClick={() => onQuickView?.(machine)}>
{t.machineActions.quickView}
</Button>
</div>
</div>
</div>
</div> </div>
);
<div className="flex flex-col gap-5">
<span className="text-brand-400 text-sm font-semibold tracking-wide">{machine.shortLabel}</span>
<h3 className="text-2xl md:text-4xl font-extrabold text-primary">{machine.name}</h3>
<div className="grid grid-cols-[auto,1fr] gap-4 items-start bg-surface border border-subtle rounded-2xl p-4">
<img
src={machine.gif}
alt={t.machineActions.gifAlt(machine.name)}
className="w-28 h-20 md:w-32 md:h-24 object-cover rounded-lg border border-subtle"
/>
<p className="text-sm md:text-base text-secondary leading-7">{machine.description}</p>
</div>
<ul className="flex flex-wrap gap-2">
{machine.highlights.map((h) => (
<li key={h} className="text-xs md:text-sm text-brand-400 bg-brand/10 border border-subtle rounded-full px-3 py-1">
{h}
</li>
))}
</ul>
<p className="text-xl md:text-2xl font-bold text-primary mt-2">{machine.priceLabel}</p>
<div className="flex flex-wrap items-center gap-3 mt-2">
<Button type="primary" size="large" icon={<ShoppingCartOutlined />} onClick={handleAddToCart}>
{t.machineActions.addToCart}
</Button>
<Button size="large" icon={<EyeOutlined />} onClick={() => onQuickView?.(machine)}>
{t.machineActions.quickView}
</Button>
<Tooltip title={wishlisted ? t.machineActions.wishlistRemove : t.machineActions.wishlistAdd}>
<Button
size="large"
shape="circle"
icon={wishlisted ? <HeartFilled className="text-brand-400" /> : <HeartOutlined />}
onClick={() => setWishlisted((v) => !v)}
/>
</Tooltip>
</div>
</div>
</div>
</div>
);
} }
+24 -24
View File
@@ -13,8 +13,8 @@ const machinesFa = [
priceNumeric: 3860000000, priceNumeric: 3860000000,
description: 'یخچالدار، ۳۵ کانال اختصاصی، سیستم خنک‌کننده قدرتمند، تحویل نرم، مدیریت آنلاین ۲۴ ساعته.', description: 'یخچالدار، ۳۵ کانال اختصاصی، سیستم خنک‌کننده قدرتمند، تحویل نرم، مدیریت آنلاین ۲۴ ساعته.',
highlights: ['یخچالدار', '۳۵ کانال اختصاصی', 'تحویل نرم', 'مدیریت آنلاین ۲۴ ساعته'], highlights: ['یخچالدار', '۳۵ کانال اختصاصی', 'تحویل نرم', 'مدیریت آنلاین ۲۴ ساعته'],
image: '/images/machine-35-base.png', image: '/images/machine-35-base.webp',
imageAlt: '/images/machine-35-white.png', imageAlt: '/images/machine-35-white.webp',
gif: '/gifs/machine-35.gif', gif: '/gifs/machine-35.gif',
}, },
{ {
@@ -25,8 +25,8 @@ const machinesFa = [
priceNumeric: 4480000000, priceNumeric: 4480000000,
description: 'یخچالدار، ۴۸ کانال اختصاصی، قابلیت‌های پیشرفته مدیریت آنلاین و تحویل کالا.', description: 'یخچالدار، ۴۸ کانال اختصاصی، قابلیت‌های پیشرفته مدیریت آنلاین و تحویل کالا.',
highlights: ['یخچالدار', '۴۸ کانال اختصاصی', 'مدیریت آنلاین پیشرفته', 'تحویل هوشمند کالا'], highlights: ['یخچالدار', '۴۸ کانال اختصاصی', 'مدیریت آنلاین پیشرفته', 'تحویل هوشمند کالا'],
image: '/images/machine-48-base.png', image: '/images/machine-48-base.webp',
imageAlt: '/images/machine-48-white.png', imageAlt: '/images/machine-48-white.webp',
gif: '/gifs/machine-48.gif', gif: '/gifs/machine-48.gif',
}, },
{ {
@@ -37,8 +37,8 @@ const machinesFa = [
priceNumeric: 4980000000, priceNumeric: 4980000000,
description: 'یخچالدار، ۶۰ کانال اختصاصی برای کسب‌وکارهای پرتردد.', description: 'یخچالدار، ۶۰ کانال اختصاصی برای کسب‌وکارهای پرتردد.',
highlights: ['یخچالدار', '۶۰ کانال اختصاصی', 'مناسب اماکن پرتردد', 'ظرفیت بالا'], highlights: ['یخچالدار', '۶۰ کانال اختصاصی', 'مناسب اماکن پرتردد', 'ظرفیت بالا'],
image: '/images/machine-60-base.png', image: '/images/machine-60-base.webp',
imageAlt: '/images/machine-60-white.png', imageAlt: '/images/machine-60-white.webp',
gif: '/gifs/machine-60.gif', gif: '/gifs/machine-60.gif',
}, },
]; ];
@@ -52,8 +52,8 @@ const machinesEn = [
priceNumeric: 3860000000, priceNumeric: 3860000000,
description: 'Refrigerated, 35 dedicated channels, powerful cooling system, soft delivery, 24/7 online management.', description: 'Refrigerated, 35 dedicated channels, powerful cooling system, soft delivery, 24/7 online management.',
highlights: ['Refrigerated', '35 dedicated channels', 'Soft delivery', '24/7 online management'], highlights: ['Refrigerated', '35 dedicated channels', 'Soft delivery', '24/7 online management'],
image: '/images/machine-35-base.png', image: '/images/machine-35-base.webp',
imageAlt: '/images/machine-35-white.png', imageAlt: '/images/machine-35-white.webp',
gif: '/gifs/machine-35.gif', gif: '/gifs/machine-35.gif',
}, },
{ {
@@ -64,8 +64,8 @@ const machinesEn = [
priceNumeric: 4480000000, priceNumeric: 4480000000,
description: 'Refrigerated, 48 dedicated channels, advanced online management and delivery capabilities.', description: 'Refrigerated, 48 dedicated channels, advanced online management and delivery capabilities.',
highlights: ['Refrigerated', '48 dedicated channels', 'Advanced online management', 'Smart delivery'], highlights: ['Refrigerated', '48 dedicated channels', 'Advanced online management', 'Smart delivery'],
image: '/images/machine-48-base.png', image: '/images/machine-48-base.webp',
imageAlt: '/images/machine-48-white.png', imageAlt: '/images/machine-48-white.webp',
gif: '/gifs/machine-48.gif', gif: '/gifs/machine-48.gif',
}, },
{ {
@@ -76,8 +76,8 @@ const machinesEn = [
priceNumeric: 4980000000, priceNumeric: 4980000000,
description: 'Refrigerated, 60 dedicated channels for high-traffic businesses.', description: 'Refrigerated, 60 dedicated channels for high-traffic businesses.',
highlights: ['Refrigerated', '60 dedicated channels', 'Ideal for high-traffic venues', 'High capacity'], highlights: ['Refrigerated', '60 dedicated channels', 'Ideal for high-traffic venues', 'High capacity'],
image: '/images/machine-60-base.png', image: '/images/machine-60-base.webp',
imageAlt: '/images/machine-60-white.png', imageAlt: '/images/machine-60-white.webp',
gif: '/gifs/machine-60.gif', gif: '/gifs/machine-60.gif',
}, },
]; ];
@@ -112,21 +112,21 @@ export const content = {
kicker: 'روبات مارکت', kicker: 'روبات مارکت',
titleLines: ['فروش خودکار،', 'هوشمند و بی‌وقفه'], titleLines: ['فروش خودکار،', 'هوشمند و بی‌وقفه'],
sub: 'تجربه‌ای نوین از خرید آسان و سریع با دستگاه‌های وندینگ روبات مارکت.', sub: 'تجربه‌ای نوین از خرید آسان و سریع با دستگاه‌های وندینگ روبات مارکت.',
image: '/images/machine-slide-0.png', image: '/images/machine-slide-0.webp',
}, },
{ {
id: 'slide-2', id: 'slide-2',
kicker: 'یخچالدار', kicker: 'یخچالدار',
titleLines: ['خنک‌کننده قدرتمند،', 'کیفیت تضمینی'], titleLines: ['خنک‌کننده قدرتمند،', 'کیفیت تضمینی'],
sub: 'نگهداری اصولی تنقلات و نوشیدنی سرد، ۲۴ ساعته و بدون نیاز به نیروی انسانی.', sub: 'نگهداری اصولی تنقلات و نوشیدنی سرد، ۲۴ ساعته و بدون نیاز به نیروی انسانی.',
image: '/images/machine-slide-1.png', image: '/images/machine-slide-1.webp',
}, },
{ {
id: 'slide-3', id: 'slide-3',
kicker: 'مدیریت آنلاین', kicker: 'مدیریت آنلاین',
titleLines: ['کنترل کامل کسب‌وکار', 'از راه دور'], titleLines: ['کنترل کامل کسب‌وکار', 'از راه دور'],
sub: 'مدیریت موجودی، فروش و گزارش‌گیری آنلاین، هر ساعت از شبانه‌روز.', sub: 'مدیریت موجودی، فروش و گزارش‌گیری آنلاین، هر ساعت از شبانه‌روز.',
image: '/images/machine-slide-2.png', image: '/images/machine-slide-2.webp',
}, },
], ],
}, },
@@ -402,21 +402,21 @@ export const content = {
kicker: 'Robot Market', kicker: 'Robot Market',
titleLines: ['Automated selling,', 'smart & non-stop'], titleLines: ['Automated selling,', 'smart & non-stop'],
sub: 'A new experience of fast, easy shopping with Robot Market vending machines.', sub: 'A new experience of fast, easy shopping with Robot Market vending machines.',
image: '/images/machine-slide-0.png', image: '/images/machine-slide-0.webp',
}, },
{ {
id: 'slide-2', id: 'slide-2',
kicker: 'Refrigerated', kicker: 'Refrigerated',
titleLines: ['Powerful cooling,', 'guaranteed quality'], titleLines: ['Powerful cooling,', 'guaranteed quality'],
sub: 'Proper storage for snacks and cold drinks, 24/7, with no staff required.', sub: 'Proper storage for snacks and cold drinks, 24/7, with no staff required.',
image: '/images/machine-slide-1.png', image: '/images/machine-slide-1.webp',
}, },
{ {
id: 'slide-3', id: 'slide-3',
kicker: 'Online Management', kicker: 'Online Management',
titleLines: ['Full control of your', 'business, remotely'], titleLines: ['Full control of your', 'business, remotely'],
sub: 'Manage inventory, sales, and reports online, any hour of the day.', sub: 'Manage inventory, sales, and reports online, any hour of the day.',
image: '/images/machine-slide-2.png', image: '/images/machine-slide-2.webp',
}, },
], ],
}, },
@@ -667,12 +667,12 @@ export const content = {
// Locale-independent asset config (positions/paths only — same in both languages). // Locale-independent asset config (positions/paths only — same in both languages).
export const floatingSnacks = [ export const floatingSnacks = [
{id: 'chips-1', image: '/images/snacks/item-1.png', size: 125, top: '5%', left: '-5%', duration: 5.5, delay: 0}, {id: 'chips-1', image: '/images/snacks/item-1.webp', size: 60, top: '5%', left: '-5%', duration: 5.5, delay: 0},
{id: 'soda-1', image: '/images/snacks/item-2.png', size: 85, top: '68%', left: '2%', duration: 6.2, delay: 0.6}, {id: 'soda-1', image: '/images/snacks/item-2.webp', size: 55, top: '68%', left: '2%', duration: 6.2, delay: 0.6},
{id: 'chips-2', image: '/images/snacks/item-3.png', size: 95, top: '10%', left: '85%', duration: 4.8, delay: 0.3}, {id: 'chips-2', image: '/images/snacks/item-3.webp', size: 65, top: '10%', left: '85%', duration: 4.8, delay: 0.3},
{id: 'soda-2', image: '/images/snacks/item-4.png', size: 105, top: '72%', left: '88%', duration: 5.9, delay: 0.9}, {id: 'soda-2', image: '/images/snacks/item-4.webp', size: 55, top: '72%', left: '88%', duration: 5.9, delay: 0.9},
{id: 'chips-3', image: '/images/snacks/item-5.png', size: 90, top: '42%', left: '90%', duration: 6.6, delay: 1.2}, {id: 'chips-3', image: '/images/snacks/item-5.webp', size: 50, top: '42%', left: '90%', duration: 6.6, delay: 1.2},
{id: 'soda-3', image: '/images/snacks/item-6.png', size: 95, top: '46%', left: '-4%', duration: 5.1, delay: 1.5}, {id: 'soda-3', image: '/images/snacks/item-6.webp', size: 55, top: '46%', left: '-4%', duration: 5.1, delay: 1.5},
]; ];
export const showcaseVideoSrc = '/video/showcase-placeholder.mp4'; export const showcaseVideoSrc = '/video/showcase-placeholder.mp4';
+1
View File
@@ -0,0 +1 @@
[{"eventName":"NEXT_CLI_SESSION_STOPPED","payload":{"nextVersion":"14.2.5","nodeVersion":"v26.3.0","cliCommand":"dev","durationMilliseconds":263824,"turboFlag":false,"pagesDir":false,"appDir":true}}]
+3
View File
@@ -0,0 +1,3 @@
{
"pages": {}
}
+16
View File
@@ -0,0 +1,16 @@
{
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [
"static/development/_buildManifest.js",
"static/development/_ssgManifest.js"
],
"rootMainFiles": [],
"pages": {
"/_app": []
},
"ampFirstPages": []
}
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
{"type": "commonjs"}
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"
+1
View File
@@ -0,0 +1 @@
self.__BUILD_MANIFEST={"polyfillFiles":["static/chunks/polyfills.js"],"devFiles":[],"ampDevFiles":[],"lowPriorityFiles":["static/development/_buildManifest.js","static/development/_ssgManifest.js"],"rootMainFiles":[],"pages":{"/_app":[]},"ampFirstPages":[]}
+6
View File
@@ -0,0 +1,6 @@
{
"version": 3,
"middleware": {},
"functions": {},
"sortedMiddleware": []
}
@@ -0,0 +1 @@
self.__REACT_LOADABLE_MANIFEST="{}"
+1
View File
@@ -0,0 +1 @@
self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}"
+1
View File
@@ -0,0 +1 @@
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}
+1
View File
@@ -0,0 +1 @@
{}
+1
View File
@@ -0,0 +1 @@
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"OV7lo+xPvS/sDjLEddseUuhg7MfbZYxNg/IFGVNi66w=\"\n}"
@@ -0,0 +1,5 @@
{
"node": {},
"edge": {},
"encryptionKey": "OV7lo+xPvS/sDjLEddseUuhg7MfbZYxNg/IFGVNi66w="
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
self.__BUILD_MANIFEST = {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},sortedPages:["\u002F_app"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
+1
View File
@@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
+2
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"type": "module"}
+16 -3
View File
@@ -1,8 +1,21 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';
const nextConfig = { const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
// AntD ships CJS + uses some patterns that benefit from transpilation in the App Router. // AntD ships CJS + uses some patterns that benefit from transpilation in the App Router.
transpilePackages: ['antd', '@ant-design/icons', 'rc-util', 'rc-pagination', 'rc-picker'], transpilePackages: ['antd', '@ant-design/icons', 'rc-util', 'rc-pagination', 'rc-picker'],
output: 'export',
images: {unoptimized: true},
trailingSlash: true,
basePath: basePath || undefined,
assetPrefix: basePath || undefined,
}; };
module.exports = nextConfig; module.exports = nextConfig;
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev -H 0.0.0.0",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint"

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB