commit f19d09c27d7e85094031eeab27036508c89d7a05 Author: Alireza Hassani Date: Wed Aug 26 00:40:31 2026 +0330 Initial commit: Clinic Samen Next.js site. Clone of clinicsamen.com with Meshkee backend integration for blog, workshops, auth, static image slots, and SEO sitemap config. Co-authored-by: Cursor diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abf07ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +.env*.local +.env + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/Ai-data/prompt-connect-backend.txt b/Ai-data/prompt-connect-backend.txt new file mode 100644 index 0000000..36d5657 --- /dev/null +++ b/Ai-data/prompt-connect-backend.txt @@ -0,0 +1,20 @@ +Domain: brb-store.com +Documentation for backend is:https://api.meshkee.com/docs/website + + +Login or user icon should go to customer.{domainName}.com +When logged in, show user name + عزیز +Show a drop down for it with this item >> پروفایل من - خروج and if admin مدیریت وبسایت + + +Create workshops page and details >> connect to workshops +Details page: +- use light box gallery +- zoom image on hover +- has two tabs in bottom, description and comments. Comment is for authenticated user if not show a login link button or box +- and a registration row + +Create blog page and details >> connect to blog + + +update context md for better use in other Ai and systems - update it on every prompt (If required) \ No newline at end of file diff --git a/Ai-data/prompt-images-slot.txt b/Ai-data/prompt-images-slot.txt new file mode 100644 index 0000000..e5cda02 --- /dev/null +++ b/Ai-data/prompt-images-slot.txt @@ -0,0 +1,18 @@ +Wire this page to clinicsamen.com, static-image slots. + +Read http://meshkee.com/docs/website (static-images). Env is already set. + +Fetch slots, match by key: +- slider > duplicatable +- 4 people image > 4 slot +- our-services-icon > 4 slot +- two-banner-bg > 2 slot + + +Use slot.images (all of them if kind=list, first if kind=single). +url → . linkUrl → wrap in . Empty or fail → keep current placeholder. +Use slot.aspectRatio from the API. Do not invent upload APIs. + +If image size or aspect ratio has changed during development, please update it for statics image reader. Add this as rule + +update context md for better use in other Ai and systems - update it on every prompt (If required) \ No newline at end of file diff --git a/Ai-data/prompt-seo.txt b/Ai-data/prompt-seo.txt new file mode 100644 index 0000000..54a55b8 --- /dev/null +++ b/Ai-data/prompt-seo.txt @@ -0,0 +1,18 @@ +### Sitemap + robots.txt +- Do NOT ship public/sitemap.xml or public/robots.txt (nginx proxies both to Meshkee API). +- Live sitemap is an index: /sitemap.xml → /sitemap-main.xml + /sitemap-products.xml. +- Publish GET /meshkee/sitemap-config.json generated at build time from app routes. +- Include public static routes automatically; exclude auth/checkout/cart/admin paths. +- Canonical detail URLs (Meshkee defaults — omit templates unless customized): + - Product: /products/{id}/{nameFaSlug} → GET /tenants/{domain}/products/by-id/{id} + - Category: /products/category/{id}/{nameFaSlug} → GET /tenants/{domain}/categories/by-id/{id} (then list products with categoryId) + - Blog: /blog/{id}/{titleSlug} → GET /tenants/{domain}/blogs/by-id/{id} + - Portfolio: /portfolios/{id}/{titleFaSlug} → GET /tenants/{domain}/portfolios/by-id/{id} +- Slugify: Farsi letters kept, spaces → -, strip other punctuation. Do not use legacy DB slug in public URLs. +- After deploy: business dashboard → Website → Settings → Sync sitemap config (optional for CMS URLs; needed for static pages). + +### On-page SEO (every public page) +- Unique and meta description on every crawlable page +- Exactly one H1; H2/H3 for real sections +- All content images must have meaningful alt (CMS title when available) +- Prefer CMS fields for titles/descriptions; never leave Next defaults diff --git a/Ai-data/prompt.txt b/Ai-data/prompt.txt new file mode 100644 index 0000000..de2211b --- /dev/null +++ b/Ai-data/prompt.txt @@ -0,0 +1,18 @@ +Clone this website clinicsamen.com +Download and use banners,images and fonts from main website, icon and color Pallete from main website +Logo from main website either + +Pick data from current website - all data is valid +Lang:fa +Directions: rtl +Use next js +Color palette like website + +Clone only homepage, about us, contact us and درمانگاران + +we will read workshops and blog from backend later + +Footer Botton row (meshkee link) should be like https://safeteb.com/ + +update context md for better use in other Ai and systems - update it on every prompt (If required) + diff --git a/Ai-data/scraped/about.html b/Ai-data/scraped/about.html new file mode 100644 index 0000000..6b6f4f0 --- /dev/null +++ b/Ai-data/scraped/about.html @@ -0,0 +1,943 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="theme-color" content="#3ed2a7"> + + + <style type="text/css"> + :root { + --wb-primary-color: #DFEAFE; + --wb-secondary-color: #0141C5; + --wb-tertiary-color: #FF0000; + --wb-default-font: iran-sans; + } + + .wb-hidden { + display: none!important; + } + + + * { + font-family: var(--wb-default-font); + } + </style> + + <link rel="stylesheet" type="text/css" href="https://cdn.meshkee.com/web-builder/global/main-color-image.min.css"/> + + <link rel="stylesheet" href="https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans.css"/> + <link rel="stylesheet" href="https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat.css"/> + + <title>درباره ما | کلینیک ثامن قم + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+
+

درباره ما

+ + + +
+
+
+
+ + +
+
+ +
+
+
+
+

کلینیک روانشناسی ثامن

+

1 - روان درمانی، مشاوره تخصصی و روان سنجی (تستها و آزمونهای تشخیصی روانشناسی)
+
+2 - برگزاری کارگاههای آموزشی عمومی و تخصصی، سمینار و همایش در موضوعات "مهارتهای زندگی، مهارتهای خانواده، مهارتهای فردی، تربیت روان درمانگر برای متخصصان و مشاوران، کارگاههای موفقیت، کارگاههای ازدواج و حوزه کودک و نوجوان و ..."
+
+3 - اجرای طرح "ثنامهر" (مشاوره، آموزش، همسان گزینی، مددکاری، حمایت-های مالی و معرفی به مراکز خیریه و ...).
+
+4 - مزاج شناسی تخصصی، اصلاح تغذیه و سبک زندگی
+
+5 - نمایندگی انحصاری بسته جامعه درسا (استعدادسنجی و پرورش هوش کودک و نوجوان) در سطح استان قم
+
+6 - تخصصی ترین مرکز ازدواج در قم
+ 

+

+ + + تماس با ما + + + + + +
+ +
+
+
+ + +
+
+ +
+
+
+
+
+
+ + + +
+
+

مشاوره چت آنلاین

+

CHAT ONLINE

+
+
+
+
+
+
+ + + +
+
+

مشاوره نوشتاری

+

WRITTEN

+
+
+
+
+
+
+ + + +
+
+

مشاوره تلفنی

+

PHONE

+
+
+
+
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + + + + + diff --git a/Ai-data/scraped/contact.html b/Ai-data/scraped/contact.html new file mode 100644 index 0000000..b656fb1 --- /dev/null +++ b/Ai-data/scraped/contact.html @@ -0,0 +1,961 @@ + + + + + + + + + + + + + + + + + تماس با ما | کلینیک ثامن قم + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+
+

تماس با ما

+ + + +
+
+
+
+ + +
+
+ +
+
+
+
+

تماس با کلینیک ثامن

+
+
+
+

آدرس

+

بنیاد - میدان جوان - بلوار آفرینش - خیابان ذوالفقار - نبش کوچه 3

+
+
+

تلفن تماس

+ + 025-32706211 + +
+ + 025-33367803 + +
+
+
+ +
+
+
+
+

برای ما پیام بفرستید

+

با نظراتتون ما رو تو مسير سلامتي کشور عزيزمون کمک کنيد.

+
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + + + + + diff --git a/Ai-data/scraped/home.html b/Ai-data/scraped/home.html new file mode 100644 index 0000000..d87f485 --- /dev/null +++ b/Ai-data/scraped/home.html @@ -0,0 +1,2131 @@ + + + + + + + + + + + + + + + + + کلینیک مشاوره و روانشناسی ثامن قم + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + + +
+
+ +
+
+
+
+
+

مشاوران کلینیک روانشناسی ثامن

+

جهت رزرو نوبت مشاوره تماس بگیرد

+
+
+
+
+
+
+
+ +
+
+ +
+

+ دکتری روانشناسی عمومی +

+
+
+
+
+
+ +
+
+ +
+

+ دکترای روانشناسی سلامت و مدرس دانشگاه +

+
+
+
+
+
+ +
+
+ +
+

+ دکترای روانشناسی دانشگاه تهران +

+
+
+
+
+
+ +
+
+ +
+

+ مدیرعامل و موسس کلینیک ثامن +

+
+
+
+
+
+ + +
+ +
+ +
+
+
+
+
+ چطور میتونم + کمکت کنم؟ +

اگه سوالی داری شمارتو بذار تا بهت زنگ بزنم (:

+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+ + + +
+
+

مشاوره چت آنلاین

+

CHAT ONLINE

+
+
+
+
+
+
+ + + +
+
+

مشاوره نوشتاری

+

WRITTEN

+
+
+
+
+
+
+ + + +
+
+

مشاوره تلفنی

+

PHONE

+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
کلینیک مشاوره و روانشناسی ثامن
+

1 - روان درمانی، مشاوره تخصصی و روان سنجی (تستها و آزمونهای تشخیصی روانشناسی)
+
+2 - برگزاری کارگاههای آموزشی عمومی و تخصصی، سمینار و همایش در موضوعات "مهارتهای زندگی، مهارتهای خانواده، مهارتهای فردی، تربیت روان درمانگر برای متخصصان و مشاوران، کارگاههای موفقیت، کارگاههای ازدواج و حوزه کودک و نوجوان و ..."

+
+ + + درباره ما بیشتر بدانید + + + + + +
+
+
+ کلینیک ثامن +
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+

مقالــــــات مــــــا

+

جدیدترین مقالات در سایت کلینیک مشاوره و روانشناسی ثامن

+
+
+
+ +
+
+
+ + +
+ + +
+ +
+
+
+
+
+

نظرات کاربران

+
+ +
+
+
+
+ + +
+
+ +
+
+
+
+
+

برخی از شیوه های خدمات

+
+
+
+
+
+
+
+ + + +
+
+

ارائه کارگاه آموزشی

+

WORKSHOP

+
+
+
+
+
+
+ + + +
+
+

ارائه مطالب در اینستاگرام

+

INSTAGRAM

+
+
+
+
+
+
+ + + +
+
+

مشاوره آنلاین تصویری

+

VIDEO

+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
چرا کلینیک روانشناسی ثامن ؟
+

 بیشترفعالیت خود را با هدف ارائه خدمات روانشناسی و روانپزشکی توسط متخصصان و روانپزشکان مجرب و حاذق آغاز کرده است.
+این مرکز با داشتن فضایی مناسب، خدماتی تخصصی نظیر روان درمانی فردی، درمان مشکلات زوج و خانواده، مشاوره انلاین، روانپزشکی سالمندان، کودکان و نوجوانان را ارائه می دهد.
+همچنین به درمان بیماری هایی نظیر افسردگی، اختلالات دو قطبی، اختلالات هوشیاری، عواقب مصرف داروهای روانگردان، وسواس فکری و غیره نیز می پردازند…

+
+ + + تماس با مــــــــــــا + + + + + +
+
+
+ چرا +
+
+
+
+
+ + +
+
+ +
+
+
+
+
+

کلینیک روانشناسی ثامن

+

(: آمار سایت ما 

+
+
+
+
+
+
+
+ + + +
+
+
+
+

رضایت مراجعان

+

SATISFACTION

+
+
+
+
+
+
+ + + +
+
+
+
+

تعداد کارگاه برگزار شده

+

WORKSHOP

+
+
+
+
+
+
+ + + +
+
+
+
+

تعـــــــداد مقالـــــات

+

ARTICLES

+
+
+
+
+
+
+ + + +
+
+
+
+

تعداد مراجعین در ماه

+

CLIENTS

+
+
+
+
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + + + + + diff --git a/Ai-data/scraped/iran-sans.css b/Ai-data/scraped/iran-sans.css new file mode 100644 index 0000000..cdfee37 --- /dev/null +++ b/Ai-data/scraped/iran-sans.css @@ -0,0 +1,36 @@ +@font-face { + font-family: "iran-sans"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-regular.ttf'); +} +@font-face { + font-family: "iran-sans-light"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-light.ttf'); +} +@font-face { + font-family: "iran-sans-medium"; + src:url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-medium.ttf'); +} +@font-face { + font-family: "iran-sans-ultralight"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-ultralight.ttf'); +} +@font-face { + font-family: "iran-sans-bold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-bold.ttf'); +} +@font-face { + font-family: "iran-sans-semibold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-semibold.ttf'); +} +@font-face { + font-family: "iran-sans-extrabold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-extrabold.ttf'); +} +@font-face { + font-family: "iran-sans-thin"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-thin.ttf'); +} +@font-face { + font-family: "iran-sans-black"; + src: url('https://cdn.meshkee.com/web-builder/fonts/iran-sans/iran-sans-black.ttf'); +} \ No newline at end of file diff --git a/Ai-data/scraped/main-color.css b/Ai-data/scraped/main-color.css new file mode 100644 index 0000000..552b02a --- /dev/null +++ b/Ai-data/scraped/main-color.css @@ -0,0 +1 @@ +.wb-primary-color {color: var(--wb-primary-color);}.wb-primary-bg-color {background-color: var(--wb-primary-color);}.wb-secondary-color {color: var(--wb-secondary-color);}.wb-secondary-bg-color {background-color: var(--wb-secondary-color);}.wb-tertiary-color {color: var(--wb-tertiary-color);}.wb-tertiary-bg-color {background-color: var(--wb-tertiary-color);} \ No newline at end of file diff --git a/Ai-data/scraped/montserrat.css b/Ai-data/scraped/montserrat.css new file mode 100644 index 0000000..2ba3503 --- /dev/null +++ b/Ai-data/scraped/montserrat.css @@ -0,0 +1,59 @@ +@font-face { + font-family: "montserrat"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-regular.ttf'); +} + +@font-face { + font-family: "montserrat-medium"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-medium.ttf'); +} + +@font-face { + font-family: "montserrat-light"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-light.ttf'); +} + +@font-face { + font-family: "montserrat-extralight"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-extralight.ttf'); +} + +@font-face { + font-family: "montserrat-bold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-bold.ttf'); +} + +@font-face { + font-family: "montserrat-semibold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-semibold.ttf'); +} + +@font-face { + font-family: "montserrat-extrabold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-extrabold.ttf'); +} + +@font-face { + font-family: "montserrat-thin"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-thin.ttf'); +} + +@font-face { + font-family: "montserrat-black"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/montserrat-black.ttf'); +} + +@font-face { + font-family: "montserrat-alternates-regular"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/MontserratAlternates-Regular.ttf'); +} + +@font-face { + font-family: "montserrat-alternates-light"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/MontserratAlternates-Light.ttf'); +} + +@font-face { + font-family: "montserrat-alternates-extrabold"; + src: url('https://cdn.meshkee.com/web-builder/fonts/montserrat/MontserratAlternates-ExtraBold.ttf'); +} \ No newline at end of file diff --git a/Ai-data/scraped/ourdr.html b/Ai-data/scraped/ourdr.html new file mode 100644 index 0000000..f4fec5d --- /dev/null +++ b/Ai-data/scraped/ourdr.html @@ -0,0 +1,1617 @@ + + + + + + + + + + + + + + + + + درمانگران | کلینیک ثامن قم + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+
+

درمانگران

+ + + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر سیدعلیرضا سیفی +
+
+
+
+
+
+
+

+

دکتر سیدعلیرضا سیفی

+ +

- مدیر عامل و موسس کلینیک روانشناسی و مشاوره ثامن تاسیس 1395
+- مدیرعامل و موسس کلینیک تخصصی ازدواج و تحکیم خانواده ثنامهر تاسیس 1401
+- کد پروانه اشتغال سازمان نظام روانشناسی ج.ا.ا     6914
+- عضو انجمن روانشناسی آمریکا APA
+-بازرس و مدیر کمیته آموزش سازمان نظام روانشناسی در قم در سال ۱۴۰۳
+-مسئول کانون مشاوره و مددکاری آستان قدس رضوی در قم
+
+-دکترای روانشناسی سلامت دانشگاه تهران
+-دکترای الهیات و فلسفه (حوزوی)
+-دکترای طب سنتی از ارمنستان (زیر نظر پروفسور خیراندیش)
+-کارشناسی ارشد روانشناسی مثبت گرا (رتبه 1 ورودی و دانشجوی ممتاز با نمره تز 19.50)
+-کارشناسی روانشناسی عمومی
+-مدرس دانشگاه ایرانیان
+-مدرس دانشگاه حضرت معصومه
+-مدرس ازدواج در وزارت بهداشت
+-مدرس دانشگاه هنر و اندیشه اسلامی 
+
+حوزه های فعالیت و تخصص:
+-شخصیت شناسی و مزاج شناسی
+-مشاوره پیش از ازدواج (PMC) و طلاق
+-درمان اختلالات عملکردی جنسی (سکس تراپی)
+-مشاوره خانواده و زوج درمانی
+-مشاوره مذهبی - معنوی
+-مشاوره افسردگی و اضطراب
+-مشاوره مشکلات خواب
+-مشاوره تغذیه براساس مزاج و اختلالات خوردن (چاقی-لاغری)

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر محمدرضا احمدی +
+
+
+
+
+
+
+

+

دکتر محمدرضا احمدی

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 479
+-دکترای روانشناسی تربیتی
+-عضو هیات علمی دانشگاه و حوزه
+
+-حوزه تخصصی
+-روانشناسی رشد و تحول
+-روش تحقیق
+-استاد راهنمای دانشجویان روانشناسی
+-سردبیر چهار مجله تخصصی روانشناسی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ سیده زهرا هدایی نیا +
+
+
+
+
+
+
+

+

دکتر سیده زهرا هدایی نیا

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 1423453
+-دکترای روانشناسی سلامت
+-هیات علمی دانشگاه اراک
+-مدرس دانشگاه
+-دانش آموخته دکتر نیما قربانی و دکتر علیرضا طهماسب
+
+-روانکاو و درمانگر اختلالات بالینی افسردگی، اضطراب وسواس و شخصیت با رویکرد روان پویشی کوتاه مدت (istdp)

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر ابوالفضل رشیدی +
+
+
+
+
+
+
+

+

دکتر ابوالفضل رشیدی

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 4583
+-دکتری روانشناسی و آموزش کودکان استثنایی دانشگاه تهران
+-رتبه 2 دانشگاه تهران
+
+-درمانگر اختلالات کودک و نوجوان (یادگیری اضطراب بیش فعالی و ...)

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ حسین شریفی +
+
+
+
+
+
+
+

+

دکتر حسین شریفی

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 33451
+-هیات علمی دانشگاه
+-دکترای الهیات و معارف
+-کارشناسی ارشد مشاوره
+
+-زوج درمانی
+-ازدواج و طلاق
+-مشاوره فردی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر محبوبه شاهسوار +
+
+
+
+
+
+
+

+

دکتر محبوبه شاهسوار

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی ۱۳۷۱۲
+-دکتری روانشناسی عمومی
+
+-مشاوره پیش از ازدواج
+-زوج درمانگر
+-مشاوره فردی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر بهاره احدی نیا +
+
+
+
+
+
+
+

+

دکتر بهاره احدی نیا

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 33068
+-دانشجوی دکترای مشاوره دانشگاه تهران
+-کارشناسی ارشد روان شناسی بالینی
+
+-مشاوره بالینی کودک و نوجوان
+-استعدادسنجی کودک
+-مدرس کارگاه های کودک و نوجوان

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ دکتر معصومه سادات رهنمایی +
+
+
+
+
+
+
+

+

دکتر معصومه سادات رهنمایی

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 1499083
+-دکترای روانشناسی سلامت دانشگاه تهران
+
+-روانشناسی فردی
+-اختلالات اضطراب
+-وسواس و افسردگی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ رسول نادری +
+
+
+
+
+
+
+

+

رسول نادری

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 1559484
+-کارشناسی ارشد روانشناسی اسلامی گرایش مثبت گرا
+
+-ازدواج خانواده، افسردگی، اضطراب وسواس و اختلالات شخصیت
+-مشاوره مذهبی و آسیب های اجتماعی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ جمشید احمد نژاد +
+
+
+
+
+
+
+

+

جمشید احمد نژاد

+ +

-کارشناسی ارشد علوم تربیتی
+
+-مشاور تحصیلی و انتخاب رشته تخصصی
+-مدرس کارگاه های تحصیلی ، خانواده و ازدواج

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ محمد باقر ساعدی +
+
+
+
+
+
+
+

+

محمد باقر ساعدی

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 44222
+-کارشناسی ارشد روانشناسی شخصیت
+
+-روان درمانگر پویشی ISTDP
+-درمان مشکلات فردی ،اضطراب، افسردگی، مداخله در خیانت

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ زینب معینی پور +
+
+
+
+
+
+
+

+

زینب معینی پور

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 29449
+-کارشناسی ارشد روان شناسی شخصیت
+
+-مشاوره فردی و اختلالات روانشناختی
+-درمانگر اضطراب، خانواده و زوج درمانگر

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ فائزه سادات سبطی +
+
+
+
+
+
+
+

+

فائزه سادات سبطی

+ +

-کارشناسی ارشد روانشناس بالینی 
+-کارشناس الهیات
+
+-مشاوره فردی بانوان افسردگی، اضطراب 
+-رویکرد هیجان مدار ، معنویت درمانی و شناختی رفتاری

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ زهره حیدری +
+
+
+
+
+
+
+

+

زهره حیدری

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 1236186
+- کارشناسی ارشد روانشناسی عمومی
+
+-طرحواره درمانی
+-وسواس و اضطراب
+-تعارضات زناشویی

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ نجما صادق زاده +
+
+
+
+
+
+
+

+

نجما صادق زاده

+ +

-کد پروانه اشتغال سازمان نظام روانشناسی 1376082
+-کارشناسی ارشد روانشناسی خانواده
+
+-زوج درمانی
+-مشاوره خانواده
+-مشاوره پیش از ازدواج

+ + + + + + + +
+ + مشاهده بیشتر + بستـــــــــــــــــــن + +
+
+
+
+ + +
+
+ +
+
+
+ جهت رزرو نوبت مشاوره تماس بگیرید + + 02532706211 + +
+
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + + + + + diff --git a/Ai-data/scraped/safeteb.html b/Ai-data/scraped/safeteb.html new file mode 100644 index 0000000..1de1001 --- /dev/null +++ b/Ai-data/scraped/safeteb.html @@ -0,0 +1 @@ +صفحه اصلی | سیف طب

گوشیتو مربیت کن!

ONLINE PROGRAM

با برنامه آنلاین سیف طب، به رویاهای ورزشیتان پرداخته و عملکردتان را به اوج برسانید.

برنامه ما منحصر به فرد است و به شما امکان می‌دهد با یک رویکرد جامع و مداوم به ورزش خود بپردازید.


فراموش نکنید، موفقیت و پیشرفت شما در دستان شماست. همین حالا روی لینک زیر کلیک کنید و با ما به بهترین خودتان دست یابید.

مشاهده بیشتر
برنامه آنلاین

جدیدترین محصولات

LASTES PRODUCTS

گیاهان دارویی مخصوص ورزشکاران

MEDICINAL PLANTS

گیاهان دارویی، بخشی از طب سنتی و تاریخی هر جامعه هستند. از زمان‌های قدیم، انسان‌ها از خصوصیات شفابخشی این گیاهان برای درمان مشکلات خود استفاده می‌کردند. این گیاهان اغلب مختص مناطق مختلف جهان هستند و شامل گیاهان معطر، گیاهان دارای اثر ضد التهابی،بالا برنده سطح انرژی،ضدباکتری، آرام‌بخش و غیره می‌شوند.


از مزایای استفاده از گیاهان دارویی این است که اکثر آن‌ها تا حد زیادی بدون عوارض جانبی استفاده می‌شوند. با این حال، توصیه می‌شود قبل از مصرف هر گونه گیاه دارویی، نظر یک پزشک یا متخصص تغذیه را جویا شوید.

مشاهده بیشتر
گیاهان دارویی
لوازم ورزشی
لوازم ورزشی

درباره سیف طب

ABOUT US

سیف‌طب با مدیریت محمود سیفی، متخصص ورزش‌درمانی و حرکات اصلاحی از دانشگاه خوارزمی، یک مرکز تخصصی در حوزه حرکات اصلاحی و درمان غیر دارویی دردهای اسکلتی–عضلانی است.
تمرکز اصلی ما بر ورزش‌درمانی و حرکات اصلاحی برای مشکلات شایع مانند کمردرد، زانودرد، دیسک کمر، کف پای صاف و ناهنجاری‌های قامتی می‌باشد.
با بهره‌گیری از علم روز و برنامه‌های اختصاصی، سیف‌طب کمک می‌کند تا بدون نیاز به دارو یا جراحی، درد کاهش یابد و کیفیت زندگی بهبود پیدا کند.
خدمات ما شامل ارزیابی وضعیت بدنی، طراحی برنامه‌های اصلاحی و توانبخشی و ارائه تمرین‌های اختصاصی برای هر فرد است.
یکی از مزیت‌های سیف‌طب، ارائه برنامه‌های ورزش‌درمانی آنلاین و حضوری است تا مراجعین در هر مکان بتوانند به خدمات حرفه‌ای دسترسی داشته باشند.
ما در سیف‌طب باور داریم که حرکت صحیح، بهترین درمان برای دردهای اسکلتی–عضلانی است و می‌تواند جایگزین روش‌های پرخطر و پرهزینه باشد.
تجربه سال‌ها کار تخصصی در زمینه حرکات اصلاحی و ورزش‌درمانی باعث شده سیف‌طب به یکی از مجموعه‌های معتبر در این حوزه تبدیل شود.
هدف ما همراهی با شما در مسیر درمان، بازگشت به زندگی بدون درد و ایجاد سبکی سالم و فعال است.

مشاهده بیشتر
درباره سیف طب

مقاله ها

ARTICLES

ارزیابی اسکلتی عضلانی چیست؟ مراحل، کاربردها و مزایا

ارزیابی اسکلتی عضلانی چیست؟ مراحل، کاربردها و مزایا

ارزیابی اسکلتی عضلانی؛ بررسی دقیق بدن پیش از شروع درمان. درد زانو، کمردرد، گردن‌درد، محدودیت حرکت شانه یا احساس ضعف در یک سمت بدن همیشه فقط از محل درد شروع نمی‌شود.

کمردرد تو با مغزت درمان کن

کمردرد تو با مغزت درمان کن

کمردرد همیشه فقط یک مشکل عضله، دیسک یا مفصل نیست. مخصوصاً وقتی درد مزمن می‌شود، مغز هم وارد ماجرا می‌شود.

جراحی گزینه آخره...

جراحی گزینه آخره...

در دهه‌های اخیر تصور عمومی آن بوده است که برای مشکلات اسکلتی‌–عضلانی مانند پارگی دیسک کمری یا آرتروز تنها استراحت یا دارو و در نهایت جراحی مفید است.

درمان غیرجراحی کمردرد

درمان غیرجراحی کمردرد

ورزش‌درمانی تخصصی برای کمردرد و دیسک کمر — درمان بدون دارو و جراحی. کمردرد یکی از شایعترین مشکلات اسکلتی‌–عضلانی در میان بزرگسالان است.

\ No newline at end of file diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..8e2a032 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,153 @@ +# Clinic Samen — AI / Project Context + +## Source of truth +- Live site being cloned: https://www.clinicsamen.com/ +- Prompt instructions: `Ai-data/prompt.txt` +- Backend / Meshkee Website API: https://api.meshkee.com/docs/website +- Static image slots prompt: `Ai-data/prompt-images-slot.txt` +- Backend connect prompt: `Ai-data/prompt-connect-backend.txt` +- SEO prompt: `Ai-data/prompt-seo.txt` +- Domain: `clinicsamen.com` (`NEXT_PUBLIC_WEBSITE_DOMAIN`) +- Tenant business id: `21` (from `GET /tenants/clinicsamen.com`) + +## Stack +- Next.js 15 (App Router) + React 19 + TypeScript +- Tailwind CSS v4 (utility import) + custom CSS in `src/app/globals.css` +- Language: `fa`, direction: `rtl` +- Fonts (downloaded from Meshkee CDN into `public/fonts/`): + - `iran-sans` (default body / Persian UI) + - `montserrat` (English labels) + +## Color palette (from live site CSS vars / accents) +- Primary soft blue: `#DFEAFE` (`--wb-primary-color`) +- Secondary / brand blue: `#0141C5` (`--wb-secondary-color`) +- Accent blue: `#0946C7` +- Mint accent: `#3ED2A7` +- Footer navy: `#0B1F4D` +- Muted text: `#707070` + +## Pages +| Route | Purpose | +|-------|---------| +| `/` | Homepage | +| `/about` | درباره ما | +| `/contact` | تماس با ما | +| `/ourdr` | درمانگران | +| `/blog` | مقالات (Meshkee blogs API) | +| `/blog/{id}/{titleSlug}` | جزئیات مقاله | +| `/workshops` | کارگاه‌ها (Meshkee workshops API) | +| `/workshops/{slug}` | جزئیات کارگاه | + +## Meshkee API integration +Base: `{NEXT_PUBLIC_MESHKEE_API_BASE}/tenants/{domain}/...` +Helpers: `src/lib/meshkee.ts` → `meshkeeGet`, `tenantPath`, `getTenant`, `getBusinessId` + +### Blog +- List: `GET /blogs?page=&pageSize=` +- Detail: `GET /blogs/by-id/{id}` (canonical URL `/blog/{id}/{titleSlug}`) +- Legacy redirect: `/blog/{slug}` → canonical +- Comments: `GET /comments?entityType=blog&entityId={id}` +- Lib: `src/lib/blog.ts` + +### Workshops +- List: `GET /workshops?page=&pageSize=` +- Detail: `GET /workshops/{slug}` (URL `/workshops/{slug}`) +- Register (auth): `POST /workshops/{workshopId}/register` via `src/app/api/workshops/[workshopId]/register/route.ts` +- Cancel registration (auth): `DELETE /workshops/{workshopId}/register` +- Comments: included on workshop detail when API provides `comments`; otherwise empty +- Lib: `src/lib/workshops.ts` +- **Note:** Tenant currently has no published workshops in API; homepage/list fall back to static samples in `src/data/site.ts`. + +### Auth / customer portal +- Login icon → `https://customer.clinicsamen.com` (`customerPortalUrl` in `src/lib/config.ts`) +- Session: `src/lib/session.tsx` + shared cookies (`src/lib/shared-auth-cookie.ts`) +- Profile API proxy: `GET /api/auth/me` → Meshkee `/auth/me` +- Admin handoff: `POST /api/auth/handoff` → Meshkee `/auth/handoff` → `https://business.clinicsamen.com` +- Logged-in header: user name + «عزیز»; dropdown: پروفایل من، خروج، مدیریت وبسایت (admins only) +- Component: `src/components/AccountMenu.tsx` + +## Static image slots +API: `GET /tenants/{domain}/website/static-images?pageKey=home` +Catalog for dashboard Refresh: `GET /meshkee/static-image-slots` → `STATIC_IMAGE_SLOTS` in `src/lib/static-images.ts` + +| key | kind | itemCount | aspectRatio | recommendedWidth | homepage section | +| --- | --- | --- | --- | --- | --- | +| `slider` | list | null | `1920:740` | 1180 | Hero slider | +| `4-people-image` | list | 4 | `325:356` | 280 | Home therapists row | +| `our-services-icon` | list | 4 | `1:1` | 110 | Services icons | +| `two-banner-bg` | list | 2 | `540:312` | 560 | Dual promo banners | + +Rules: +- Use `slot.images` (all if `kind=list`, first if `kind=single`) +- `url` → ``; `linkUrl` → wrap in link +- Empty / fail → keep local placeholders from `src/data/site.ts` / `public/images/` +- Use `slot.aspectRatio` (via `parseAspectRatio`) +- **If a slot’s on-page size or aspect ratio changes in CSS, update `STATIC_IMAGE_SLOTS` in the same change** + +Helpers: `src/lib/static-images.ts`, `src/components/SlotImage.tsx`, `src/components/SlotLink.tsx` +Home wiring: `src/app/page.tsx` + +## Content & assets +- Site copy, therapists bios, phones, address, socials live in `src/data/site.ts` +- Static workshop/article fallbacks in `src/data/site.ts` (used when API empty) +- Logos, banners, therapist photos, icons in `public/images/` +- Favicon: `/favicon.png` + +## Footer Meshkee credit +- Bottom row matches Safeteb-style Meshkee credit +- Component: `src/components/Footer.tsx` → `.meshkee-credit` +- Styles: `src/app/globals.css` +- Links to `https://meshkee.com` +- Logo: `public/images/footer/MeshkeeLogo-White.png` + +## Important paths +- Layout / shell: `src/app/layout.tsx`, `src/components/Providers.tsx` +- Header + account: `src/components/Header.tsx`, `src/components/AccountMenu.tsx` +- Footer: `src/components/Footer.tsx` +- Home: `src/app/page.tsx`, `src/components/HeroSlider.tsx`, `src/components/HomeSections.tsx` +- Blog: `src/app/blog/`, `src/components/ArticlesCarousel.tsx` +- Workshops: `src/app/workshops/`, `src/components/WorkshopGallery.tsx`, `src/components/WorkshopRegistration.tsx`, `src/components/EntityTabs.tsx` +- Config: `src/lib/config.ts` +- Data: `src/data/site.ts` + +## Contact +- Phones: `025-32706211`, `025-32702623`, `09936221511` +- Address: بنیاد - میدان جوان - بلوار آفرینش - خیابان ذوالفقار - نبش کوچه ۳ +- Socials: Instagram `@Psy.samen`, WhatsApp, Telegram, Eitaa +- Map embed: OpenStreetMap iframe on contact page + +## Env +```bash +NEXT_PUBLIC_WEBSITE_DOMAIN=clinicsamen.com +NEXT_PUBLIC_MESHKEE_API_BASE=https://api.meshkee.com/api/v1 +# Optional overrides: +# NEXT_PUBLIC_CUSTOMER_PORTAL_URL=https://customer.clinicsamen.com +# NEXT_PUBLIC_BUSINESS_ORIGIN=https://business.clinicsamen.com +``` + +## Commands +```bash +npm install +npm run dev +npm run build +``` + +## SEO canonical URLs +- Blog: `/blog/{id}/{titleSlug}` → `GET /blogs/by-id/{id}` +- Workshop: `/workshops/{slug}` → `GET /workshops/{slug}` +- Slugify helper: `src/lib/seo-slug.ts` +- Page metadata helper: `src/lib/seo.ts` → `pageMetadata()` (title, description, canonical, Open Graph) + +## Sitemap + robots +- **Do not** add `public/sitemap.xml` or `public/robots.txt` (nginx proxies to Meshkee API) +- Live sitemap index: `/sitemap.xml` → `/sitemap-main.xml` + CMS URLs +- Static pages config: `GET /meshkee/sitemap-config.json` +- Generated at build: `scripts/generate-sitemap-config.mjs` → `src/lib/sitemap-config.generated.json` +- Run manually: `npm run generate:sitemap-config` +- After deploy: business dashboard → Website → Settings → Sync sitemap config + +### On-page SEO rules +- Unique `` + meta description on every public page (via `pageMetadata` or `generateMetadata`) +- Exactly one `<h1>` per page (homepage: header brand; inner pages: page hero) +- Section headings use `<h2>` / `<h3>` +- CMS images use meaningful `alt` (title when available) diff --git a/README.md b/README.md new file mode 100644 index 0000000..757eaa2 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# کلینیک مشاوره و روانشناسی ثامن + +Next.js clone of [clinicsamen.com](https://www.clinicsamen.com/) (RTL / FA). + +## Pages +- Home `/` +- About `/about` +- Contact `/contact` +- Therapists `/ourdr` + +## Develop +```bash +npm install +npm run dev +``` + +See `CONTEXT.md` for palette, assets, and backend follow-ups. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..bbd17c7 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,14 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [...compat.extends("next/core-web-vitals", "next/typescript")]; + +export default eslintConfig; diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..f52ae79 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,26 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "meshkee-templates.sas.amin.parminstorage.ir", + }, + { + protocol: "https", + hostname: "meshkee-storage.sas.amin.parminstorage.ir", + }, + { + protocol: "https", + hostname: "cdn.meshkee.com", + }, + { + protocol: "https", + hostname: "c804387.parspack.net", + }, + ], + }, +}; + +export default nextConfig; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7137592 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6223 @@ +{ + "name": "clinic-samen", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "clinic-samen", + "version": "0.1.0", + "dependencies": { + "next": "^15.3.3", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.8", + "@types/node": "^22.15.21", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.5", + "eslint": "^9.28.0", + "eslint-config-next": "^15.3.3", + "tailwindcss": "^4.1.8", + "typescript": "^5.8.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.3.tgz", + "integrity": "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@next/env": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.23.tgz", + "integrity": "sha512-Mv3Z9hVbFcPnoLevsZ6rnX1TBtyHb5E17yN7HTPDXSXxeNsGBjUFrdbjRXKKXIOhfth7/cg6Ay7PZ2UFawaWsQ==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.23.tgz", + "integrity": "sha512-0KnCFpiWVIsbwBhByZ0uIcjYM5xqGrFzN2eOPbwru/wuy5Z1dmA+3gP+PRbi4gl1Ny7an66BqAM/NHkX/50rbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.23.tgz", + "integrity": "sha512-SrEwOROH/rhA03F59hHtdhgtfZMWGzr5duDBWgRQt2rS3mJhqMKOcnNx6txOd0/i3E3D3uFKYFvyHsEiwQxzag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.23.tgz", + "integrity": "sha512-f0FpFbG2EhDCuptBGcfrLcYMDuQAhe6m1QA4VVfXFrIBoFXvXt/olGbBkYkloKlXQtmhuzvtdYyuu/6zf07GIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.23.tgz", + "integrity": "sha512-WlNtfepUXKX2u2ZsJZ8c3c8+tJSRZqsYzoMwLOY72A8ucKCCgxgNhiePA3qzFYahVWrwcQd8jOeJmBinc+VFVQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.23.tgz", + "integrity": "sha512-W/6qKk7UG93mg14PmQC+2urt69MIdwTBLNQ6MJyeC4wOCIHCjz+VfgssvS1pK7mgYBtLC1g6VKNoHD9xB0WWGg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.23.tgz", + "integrity": "sha512-vzefI32mi6VMk96RaTAyxApgfGbiFzQBXVsekEjsDv1fr48mlABTWx0sUYhaYCBHWqCalxmz3DxbxFcbFvzNtw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.23.tgz", + "integrity": "sha512-qppK/3dTGOTI+aoWWBZc3DshFIhrzgL8guATlaN9V6M1QJxbkP/rhEZ22tdICsQ/2WWXopMZ2Jokzj2u3uKY3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.23.tgz", + "integrity": "sha512-Wc29KFOdT7XBcII3Vtmw7aoU8Uk3Mes/FNJfhFeSHdYBFJWMcR/DsI8U9BCPUhq/uycsUVuqSKGthW15tLsigA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.23.tgz", + "integrity": "sha512-/C7wRW4fa9s/PKA18zGPPpVmx8ycgVpP8yOxro4gzGTzjPJdscbAP3ODeFvgiIovxD176Z2J/SXO9t8PJKHLeQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.16.1.tgz", + "integrity": "sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", + "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "postcss": "^8.5.16", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", + "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/type-utils": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.67.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", + "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", + "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", + "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", + "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", + "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", + "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", + "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.67.0", + "@typescript-eslint/tsconfig-utils": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", + "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", + "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz", + "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz", + "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.23.tgz", + "integrity": "sha512-z4WcTXNqFHwMG4V8WHb2xrlEPJvwarZa+H/6CR28vxr53icRnQzGXviO11p748BwrMZGl52itdPRzZfzYo0SKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "15.5.23", + "@rushstack/eslint-patch": "^1.10.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^5.0.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz", + "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", + "integrity": "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.5.23", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.23.tgz", + "integrity": "sha512-Gvd2WKgvxIXCGotxcI1im/Uf3rS3J3oZGw0g/uskg6AVBZhyE3aAbujkYWzS3xLmEPEtTLfkaVQUKK0KMTSIkA==", + "license": "MIT", + "dependencies": { + "@next/env": "15.5.23", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.23", + "@next/swc-darwin-x64": "15.5.23", + "@next/swc-linux-arm64-gnu": "15.5.23", + "@next/swc-linux-arm64-musl": "15.5.23", + "@next/swc-linux-x64-gnu": "15.5.23", + "@next/swc-linux-x64-musl": "15.5.23", + "@next/swc-win32-arm64-msvc": "15.5.23", + "@next/swc-win32-x64-msvc": "15.5.23", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..917471e --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "clinic-samen", + "version": "0.1.0", + "private": true, + "scripts": { + "prebuild": "node scripts/generate-sitemap-config.mjs", + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "generate:sitemap-config": "node scripts/generate-sitemap-config.mjs" + }, + "dependencies": { + "next": "^15.3.3", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@tailwindcss/postcss": "^4.1.8", + "@types/node": "^22.15.21", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.5", + "eslint": "^9.28.0", + "eslint-config-next": "^15.3.3", + "tailwindcss": "^4.1.8", + "typescript": "^5.8.3" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..8d9dd6a Binary files /dev/null and b/public/favicon.png differ diff --git a/public/fonts/iran-sans/iran-sans-black.ttf b/public/fonts/iran-sans/iran-sans-black.ttf new file mode 100644 index 0000000..f9990ff Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-black.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-bold.ttf b/public/fonts/iran-sans/iran-sans-bold.ttf new file mode 100644 index 0000000..490ae62 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-bold.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-extrabold.ttf b/public/fonts/iran-sans/iran-sans-extrabold.ttf new file mode 100644 index 0000000..cd28155 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-extrabold.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-light.ttf b/public/fonts/iran-sans/iran-sans-light.ttf new file mode 100644 index 0000000..6748563 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-light.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-medium.ttf b/public/fonts/iran-sans/iran-sans-medium.ttf new file mode 100644 index 0000000..806da5f Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-medium.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-regular.ttf b/public/fonts/iran-sans/iran-sans-regular.ttf new file mode 100644 index 0000000..ad4e6ec Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-regular.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-semibold.ttf b/public/fonts/iran-sans/iran-sans-semibold.ttf new file mode 100644 index 0000000..f5ea4b4 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-semibold.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-thin.ttf b/public/fonts/iran-sans/iran-sans-thin.ttf new file mode 100644 index 0000000..fe26001 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-thin.ttf differ diff --git a/public/fonts/iran-sans/iran-sans-ultralight.ttf b/public/fonts/iran-sans/iran-sans-ultralight.ttf new file mode 100644 index 0000000..36a7708 Binary files /dev/null and b/public/fonts/iran-sans/iran-sans-ultralight.ttf differ diff --git a/public/fonts/montserrat/montserrat-bold.ttf b/public/fonts/montserrat/montserrat-bold.ttf new file mode 100644 index 0000000..9a425b9 Binary files /dev/null and b/public/fonts/montserrat/montserrat-bold.ttf differ diff --git a/public/fonts/montserrat/montserrat-medium.ttf b/public/fonts/montserrat/montserrat-medium.ttf new file mode 100644 index 0000000..db5b1af Binary files /dev/null and b/public/fonts/montserrat/montserrat-medium.ttf differ diff --git a/public/fonts/montserrat/montserrat-regular.ttf b/public/fonts/montserrat/montserrat-regular.ttf new file mode 100644 index 0000000..2a2b2aa Binary files /dev/null and b/public/fonts/montserrat/montserrat-regular.ttf differ diff --git a/public/fonts/montserrat/montserrat-semibold.ttf b/public/fonts/montserrat/montserrat-semibold.ttf new file mode 100644 index 0000000..0ecc667 Binary files /dev/null and b/public/fonts/montserrat/montserrat-semibold.ttf differ diff --git a/public/images/about/about-banner.png b/public/images/about/about-banner.png new file mode 100644 index 0000000..b08e866 Binary files /dev/null and b/public/images/about/about-banner.png differ diff --git a/public/images/banners/bg-pattern.jpg b/public/images/banners/bg-pattern.jpg new file mode 100644 index 0000000..6126d12 Binary files /dev/null and b/public/images/banners/bg-pattern.jpg differ diff --git a/public/images/banners/individual.jpg b/public/images/banners/individual.jpg new file mode 100644 index 0000000..41ac58e Binary files /dev/null and b/public/images/banners/individual.jpg differ diff --git a/public/images/banners/workshops.jpg b/public/images/banners/workshops.jpg new file mode 100644 index 0000000..608391e Binary files /dev/null and b/public/images/banners/workshops.jpg differ diff --git a/public/images/blog/post-1.jpg b/public/images/blog/post-1.jpg new file mode 100644 index 0000000..46e7fa1 Binary files /dev/null and b/public/images/blog/post-1.jpg differ diff --git a/public/images/blog/post-2.jpg b/public/images/blog/post-2.jpg new file mode 100644 index 0000000..8d3f98c Binary files /dev/null and b/public/images/blog/post-2.jpg differ diff --git a/public/images/blog/post-3.jpg b/public/images/blog/post-3.jpg new file mode 100644 index 0000000..f9f91cd Binary files /dev/null and b/public/images/blog/post-3.jpg differ diff --git a/public/images/blog/post-4.jpg b/public/images/blog/post-4.jpg new file mode 100644 index 0000000..4c15e51 Binary files /dev/null and b/public/images/blog/post-4.jpg differ diff --git a/public/images/blog/post-5.jpg b/public/images/blog/post-5.jpg new file mode 100644 index 0000000..a59bb99 Binary files /dev/null and b/public/images/blog/post-5.jpg differ diff --git a/public/images/blog/post-6.jpg b/public/images/blog/post-6.jpg new file mode 100644 index 0000000..b2c2167 Binary files /dev/null and b/public/images/blog/post-6.jpg differ diff --git a/public/images/blog/post-7.jpg b/public/images/blog/post-7.jpg new file mode 100644 index 0000000..3f7709b Binary files /dev/null and b/public/images/blog/post-7.jpg differ diff --git a/public/images/blog/post-8.jpg b/public/images/blog/post-8.jpg new file mode 100644 index 0000000..da5df3f Binary files /dev/null and b/public/images/blog/post-8.jpg differ diff --git a/public/images/footer/MeshkeeLogo-White.png b/public/images/footer/MeshkeeLogo-White.png new file mode 100755 index 0000000..a10ecd3 Binary files /dev/null and b/public/images/footer/MeshkeeLogo-White.png differ diff --git a/public/images/icons/chat-online.png b/public/images/icons/chat-online.png new file mode 100644 index 0000000..5e71d96 Binary files /dev/null and b/public/images/icons/chat-online.png differ diff --git a/public/images/icons/decoration.png b/public/images/icons/decoration.png new file mode 100644 index 0000000..6610519 Binary files /dev/null and b/public/images/icons/decoration.png differ diff --git a/public/images/icons/phone.png b/public/images/icons/phone.png new file mode 100644 index 0000000..197df15 Binary files /dev/null and b/public/images/icons/phone.png differ diff --git a/public/images/icons/why.png b/public/images/icons/why.png new file mode 100644 index 0000000..98cf218 Binary files /dev/null and b/public/images/icons/why.png differ diff --git a/public/images/icons/written.png b/public/images/icons/written.png new file mode 100644 index 0000000..ec924ac Binary files /dev/null and b/public/images/icons/written.png differ diff --git a/public/images/logo/clinic-logo.png b/public/images/logo/clinic-logo.png new file mode 100644 index 0000000..8d9dd6a Binary files /dev/null and b/public/images/logo/clinic-logo.png differ diff --git a/public/images/logo/org-logo.png b/public/images/logo/org-logo.png new file mode 100644 index 0000000..589a4e8 Binary files /dev/null and b/public/images/logo/org-logo.png differ diff --git a/public/images/services/divorce.png b/public/images/services/divorce.png new file mode 100644 index 0000000..65127e3 Binary files /dev/null and b/public/images/services/divorce.png differ diff --git a/public/images/services/education.png b/public/images/services/education.png new file mode 100644 index 0000000..1037da5 Binary files /dev/null and b/public/images/services/education.png differ diff --git a/public/images/services/family.png b/public/images/services/family.png new file mode 100644 index 0000000..439239a Binary files /dev/null and b/public/images/services/family.png differ diff --git a/public/images/services/marriage.png b/public/images/services/marriage.png new file mode 100644 index 0000000..7d08e5a Binary files /dev/null and b/public/images/services/marriage.png differ diff --git a/public/images/slider/slide-1.jpg b/public/images/slider/slide-1.jpg new file mode 100644 index 0000000..c57ec7e Binary files /dev/null and b/public/images/slider/slide-1.jpg differ diff --git a/public/images/slider/slide-2.jpg b/public/images/slider/slide-2.jpg new file mode 100644 index 0000000..4930192 Binary files /dev/null and b/public/images/slider/slide-2.jpg differ diff --git a/public/images/slider/slide-3.jpg b/public/images/slider/slide-3.jpg new file mode 100644 index 0000000..d8e8273 Binary files /dev/null and b/public/images/slider/slide-3.jpg differ diff --git a/public/images/slider/slide-4.jpg b/public/images/slider/slide-4.jpg new file mode 100644 index 0000000..3087920 Binary files /dev/null and b/public/images/slider/slide-4.jpg differ diff --git a/public/images/therapists/ahadinia.jpg b/public/images/therapists/ahadinia.jpg new file mode 100644 index 0000000..02b2503 Binary files /dev/null and b/public/images/therapists/ahadinia.jpg differ diff --git a/public/images/therapists/ahmadi.jpg b/public/images/therapists/ahmadi.jpg new file mode 100644 index 0000000..893aa56 Binary files /dev/null and b/public/images/therapists/ahmadi.jpg differ diff --git a/public/images/therapists/ahmadnezhad.jpg b/public/images/therapists/ahmadnezhad.jpg new file mode 100644 index 0000000..3b26276 Binary files /dev/null and b/public/images/therapists/ahmadnezhad.jpg differ diff --git a/public/images/therapists/heydari.jpg b/public/images/therapists/heydari.jpg new file mode 100644 index 0000000..91fae54 Binary files /dev/null and b/public/images/therapists/heydari.jpg differ diff --git a/public/images/therapists/hodaeinia.jpg b/public/images/therapists/hodaeinia.jpg new file mode 100644 index 0000000..260219f Binary files /dev/null and b/public/images/therapists/hodaeinia.jpg differ diff --git a/public/images/therapists/home-rashidi.jpg b/public/images/therapists/home-rashidi.jpg new file mode 100644 index 0000000..006f73b Binary files /dev/null and b/public/images/therapists/home-rashidi.jpg differ diff --git a/public/images/therapists/home-seifi.webp b/public/images/therapists/home-seifi.webp new file mode 100644 index 0000000..843a81f Binary files /dev/null and b/public/images/therapists/home-seifi.webp differ diff --git a/public/images/therapists/home-shahsavar.jpg b/public/images/therapists/home-shahsavar.jpg new file mode 100644 index 0000000..209fc18 Binary files /dev/null and b/public/images/therapists/home-shahsavar.jpg differ diff --git a/public/images/therapists/moeini.jpg b/public/images/therapists/moeini.jpg new file mode 100644 index 0000000..2237d39 Binary files /dev/null and b/public/images/therapists/moeini.jpg differ diff --git a/public/images/therapists/naderi.jpg b/public/images/therapists/naderi.jpg new file mode 100644 index 0000000..29a0e5f Binary files /dev/null and b/public/images/therapists/naderi.jpg differ diff --git a/public/images/therapists/rahnamaei.jpg b/public/images/therapists/rahnamaei.jpg new file mode 100644 index 0000000..d3a30a0 Binary files /dev/null and b/public/images/therapists/rahnamaei.jpg differ diff --git a/public/images/therapists/rashidi.jpg b/public/images/therapists/rashidi.jpg new file mode 100644 index 0000000..006f73b Binary files /dev/null and b/public/images/therapists/rashidi.jpg differ diff --git a/public/images/therapists/sadeghzadeh.jpg b/public/images/therapists/sadeghzadeh.jpg new file mode 100644 index 0000000..0367106 Binary files /dev/null and b/public/images/therapists/sadeghzadeh.jpg differ diff --git a/public/images/therapists/saedi.jpg b/public/images/therapists/saedi.jpg new file mode 100644 index 0000000..58a804f Binary files /dev/null and b/public/images/therapists/saedi.jpg differ diff --git a/public/images/therapists/sebti.jpg b/public/images/therapists/sebti.jpg new file mode 100644 index 0000000..2286602 Binary files /dev/null and b/public/images/therapists/sebti.jpg differ diff --git a/public/images/therapists/seifi.webp b/public/images/therapists/seifi.webp new file mode 100644 index 0000000..843a81f Binary files /dev/null and b/public/images/therapists/seifi.webp differ diff --git a/public/images/therapists/shahsavar.jpg b/public/images/therapists/shahsavar.jpg new file mode 100644 index 0000000..209fc18 Binary files /dev/null and b/public/images/therapists/shahsavar.jpg differ diff --git a/public/images/therapists/sharifi.jpg b/public/images/therapists/sharifi.jpg new file mode 100644 index 0000000..3f6d65f Binary files /dev/null and b/public/images/therapists/sharifi.jpg differ diff --git a/scripts/generate-sitemap-config.mjs b/scripts/generate-sitemap-config.mjs new file mode 100644 index 0000000..2888343 --- /dev/null +++ b/scripts/generate-sitemap-config.mjs @@ -0,0 +1,99 @@ +/** + * Scans app page routes and writes src/lib/sitemap-config.generated.json + * for GET /meshkee/sitemap-config.json (Meshkee sitemap sync). + */ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const appDir = path.join(root, "src", "app"); +const outFile = path.join(root, "src", "lib", "sitemap-config.generated.json"); + +const EXCLUDE_SEGMENTS = new Set([ + "api", + "meshkee", + "admin", + "auth", + "login", + "checkout", + "cart", + "account", +]); + +const PRIORITY = { + "/": { changefreq: "daily", priority: 1.0 }, + "/ourdr": { changefreq: "weekly", priority: 0.8 }, + "/workshops": { changefreq: "weekly", priority: 0.8 }, + "/blog": { changefreq: "weekly", priority: 0.8 }, + "/about": { changefreq: "monthly", priority: 0.6 }, + "/contact": { changefreq: "monthly", priority: 0.5 }, +}; + +function websiteDomain() { + return ( + process.env.NEXT_PUBLIC_WEBSITE_DOMAIN || + process.env.WEBSITE_DOMAIN || + process.env.NEXT_PUBLIC_MESHKEE_DOMAIN || + "clinicsamen.com" + ); +} + +function walkPages(dir, segments = []) { + /** @type {string[]} */ + const pages = []; + if (!fs.existsSync(dir)) return pages; + + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + if (entry.name.startsWith(".") || entry.name === "node_modules") continue; + const full = path.join(dir, entry.name); + + if (entry.isDirectory()) { + if (EXCLUDE_SEGMENTS.has(entry.name)) continue; + if (/^\[.+\]$/.test(entry.name) || /^\(.+\)$/.test(entry.name)) { + if (/^\(.+\)$/.test(entry.name)) { + pages.push(...walkPages(full, segments)); + } + continue; + } + pages.push(...walkPages(full, [...segments, entry.name])); + continue; + } + + if ( + entry.name === "page.tsx" || + entry.name === "page.ts" || + entry.name === "page.jsx" || + entry.name === "page.js" + ) { + const routePath = segments.length ? `/${segments.join("/")}` : "/"; + pages.push(routePath); + } + } + + return pages; +} + +function main() { + const paths = [...new Set(walkPages(appDir))].sort((a, b) => { + if (a === "/") return -1; + if (b === "/") return 1; + return a.localeCompare(b); + }); + + const staticPages = paths.map((routePath) => { + const meta = PRIORITY[routePath] ?? { priority: 0.5 }; + return { path: routePath, ...meta }; + }); + + const config = { + baseUrl: `https://${websiteDomain()}`, + staticPages, + }; + + fs.mkdirSync(path.dirname(outFile), { recursive: true }); + fs.writeFileSync(outFile, `${JSON.stringify(config, null, 2)}\n`, "utf8"); + console.log(`Wrote ${path.relative(root, outFile)} (${staticPages.length} static pages)`); +} + +main(); diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000..b99d683 --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,57 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; + +import { aboutPoints, site } from "@/data/site"; +import { pageMetadata } from "@/lib/seo"; + +export const metadata: Metadata = pageMetadata({ + title: "درباره ما", + description: `درباره ${site.name}: ${site.description}`, + path: "/about", +}); + +export default function AboutPage() { + return ( + <> + <div className="page-hero"> + <div className="container"> + <h1>درباره ما</h1> + <div className="breadcrumb"> + <Link href="/">خانه</Link> / درباره ما + </div> + </div> + </div> + + <section className="section"> + <div className="container about-layout"> + <div> + <h2 style={{ marginTop: 0, color: "var(--wb-accent)" }}>کلینیک روانشناسی ثامن</h2> + <p style={{ color: "#555", textAlign: "justify" }}>{site.tagline}</p> + <p style={{ color: "#555", textAlign: "justify" }}>{site.description}</p> + <ol className="about-points"> + {aboutPoints.map((point, index) => ( + <li key={point}> + {index + 1} - {point} + </li> + ))} + </ol> + <div style={{ marginTop: "1.5rem" }}> + <Link href="/contact" className="btn btn-primary"> + تماس با ما + </Link> + </div> + </div> + <div className="visual"> + <Image + src="/images/about/about-banner.png" + alt="کلینیک روانشناسی ثامن" + width={640} + height={520} + /> + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/api/auth/handoff/route.ts b/src/app/api/auth/handoff/route.ts new file mode 100644 index 0000000..93365f5 --- /dev/null +++ b/src/app/api/auth/handoff/route.ts @@ -0,0 +1,17 @@ +import { getBearerToken, jsonResponse, meshkeeFetch, unauthorizedResponse } from "@/lib/meshkee-server"; + +export async function POST(request: Request) { + const token = getBearerToken(request); + if (!token) return unauthorizedResponse(); + + const res = await meshkeeFetch("/auth/handoff", { + method: "POST", + token, + }); + + if (!res.ok) { + return jsonResponse({ error: "امکان باز کردن پنل مدیریت نیست." }, res.status); + } + + return jsonResponse(res.data); +} diff --git a/src/app/api/auth/me/route.ts b/src/app/api/auth/me/route.ts new file mode 100644 index 0000000..53435fb --- /dev/null +++ b/src/app/api/auth/me/route.ts @@ -0,0 +1,10 @@ +import { getBearerToken, jsonResponse, meshkeeFetch, unauthorizedResponse } from "@/lib/meshkee-server"; + +export async function GET(request: Request) { + const token = getBearerToken(request); + if (!token) return unauthorizedResponse(); + + const res = await meshkeeFetch("/auth/me", { token }); + if (!res.ok) return jsonResponse({ error: "Unauthorized" }, res.status); + return jsonResponse(res.data); +} diff --git a/src/app/api/workshops/[workshopId]/register/route.ts b/src/app/api/workshops/[workshopId]/register/route.ts new file mode 100644 index 0000000..5e64549 --- /dev/null +++ b/src/app/api/workshops/[workshopId]/register/route.ts @@ -0,0 +1,44 @@ +import { getBearerToken, jsonResponse, meshkeeFetch, unauthorizedResponse } from "@/lib/meshkee-server"; +import { tenantPath } from "@/lib/meshkee"; + +export async function POST( + request: Request, + context: { params: Promise<{ workshopId: string }> }, +) { + const token = getBearerToken(request); + if (!token) return unauthorizedResponse(); + + const { workshopId } = await context.params; + const res = await meshkeeFetch(tenantPath(`/workshops/${encodeURIComponent(workshopId)}/register`), { + method: "POST", + token, + }); + + if (!res.ok) { + const data = res.data as { message?: string } | null; + return jsonResponse({ error: data?.message ?? "ثبت‌نام انجام نشد." }, res.status); + } + + return jsonResponse(res.data, res.status); +} + +export async function DELETE( + request: Request, + context: { params: Promise<{ workshopId: string }> }, +) { + const token = getBearerToken(request); + if (!token) return unauthorizedResponse(); + + const { workshopId } = await context.params; + const res = await meshkeeFetch(tenantPath(`/workshops/${encodeURIComponent(workshopId)}/register`), { + method: "DELETE", + token, + }); + + if (!res.ok) { + const data = res.data as { message?: string } | null; + return jsonResponse({ error: data?.message ?? "لغو ثبت‌نام انجام نشد." }, res.status); + } + + return jsonResponse(res.data); +} diff --git a/src/app/blog/[id]/[slug]/page.tsx b/src/app/blog/[id]/[slug]/page.tsx new file mode 100644 index 0000000..018dc3d --- /dev/null +++ b/src/app/blog/[id]/[slug]/page.tsx @@ -0,0 +1,99 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound, redirect } from "next/navigation"; + +import EntityTabs from "@/components/EntityTabs"; +import PageHero from "@/components/PageHero"; +import { blogHref, blogImage, blogTitleSlug, fetchBlogById, getLocalBlogPost } from "@/lib/blog"; +import { fetchComments } from "@/lib/comments"; +import { formatFaDate } from "@/lib/format"; +import { pageMetadata } from "@/lib/seo"; + +export const revalidate = 60; + +export async function generateMetadata({ + params, +}: { + params: Promise<{ id: string; slug: string }>; +}): Promise<Metadata> { + const { id } = await params; + const apiPost = await fetchBlogById(id); + if (apiPost) { + return pageMetadata({ + title: apiPost.title, + description: apiPost.abstract ?? apiPost.title, + path: blogHref(apiPost), + image: blogImage(apiPost), + }); + } + const local = getLocalBlogPost(id); + if (!local) return { title: "مقاله" }; + return pageMetadata({ + title: local.title, + description: local.abstract ?? local.title, + path: blogHref(local), + image: blogImage(local), + }); +} + +export default async function BlogPostPage({ + params, +}: { + params: Promise<{ id: string; slug: string }>; +}) { + const { id, slug } = await params; + const apiPost = await fetchBlogById(id); + + if (apiPost) { + const canonical = blogTitleSlug(apiPost.title); + if (decodeURIComponent(slug) !== canonical) { + redirect(blogHref(apiPost)); + } + + const comments = await fetchComments("blog", apiPost.id); + return ( + <> + <PageHero title={apiPost.title} image={blogImage(apiPost)} /> + <section className="section"> + <div className="container detail-page"> + <p className="meta-line">{formatFaDate(apiPost.publishedAt || apiPost.createdAt)}</p> + {apiPost.abstract ? <p className="detail-lead">{apiPost.abstract}</p> : null} + {apiPost.mainTextHtml ? ( + <div className="rich-text" dangerouslySetInnerHTML={{ __html: apiPost.mainTextHtml }} /> + ) : null} + <EntityTabs showDescription={false} comments={comments} /> + <Link href="/blog" className="back-link"> + بازگشت به مقالات + </Link> + </div> + </section> + </> + ); + } + + const local = getLocalBlogPost(id); + if (!local) notFound(); + + const canonical = blogTitleSlug(local.title); + if (decodeURIComponent(slug) !== canonical) { + redirect(blogHref(local)); + } + + return ( + <> + <PageHero title={local.title} image={blogImage(local)} /> + <section className="section"> + <div className="container detail-page"> + {local.abstract ? <p className="detail-lead">{local.abstract}</p> : null} + <div className="detail-image"> + <Image src={blogImage(local)} alt={local.title} width={960} height={540} /> + </div> + <Link href="/blog" className="back-link"> + بازگشت به مقالات + </Link> + </div> + </section> + </> + ); +} diff --git a/src/app/blog/[id]/page.tsx b/src/app/blog/[id]/page.tsx new file mode 100644 index 0000000..35b5799 --- /dev/null +++ b/src/app/blog/[id]/page.tsx @@ -0,0 +1,22 @@ +import { notFound, redirect } from "next/navigation"; + +import { blogHref, fetchBlogBySlug, getLocalBlogPost } from "@/lib/blog"; + +export const revalidate = 60; + +/** Legacy `/blog/{slug-or-id}` → canonical `/blog/{id}/{titleSlug}`. */ +export default async function LegacyBlogRedirect({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + + const apiPost = await fetchBlogBySlug(id); + if (apiPost) redirect(blogHref(apiPost)); + + const local = getLocalBlogPost(id); + if (local) redirect(blogHref(local)); + + notFound(); +} diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx new file mode 100644 index 0000000..39e1941 --- /dev/null +++ b/src/app/blog/page.tsx @@ -0,0 +1,78 @@ +import Image from "next/image"; +import Link from "next/link"; + +import PageHero from "@/components/PageHero"; +import { blogHref, blogImage, fetchBlogs, getLocalBlogPosts } from "@/lib/blog"; +import { faDigits, formatFaDate } from "@/lib/format"; +import { pageMetadata } from "@/lib/seo"; + +export const revalidate = 60; + +export const metadata = pageMetadata({ + title: "مقالات", + description: "آخرین مطالب آموزشی کلینیک روانشناسی و مرکز مشاوره ثامن قم", + path: "/blog", +}); + +export default async function BlogPage({ + searchParams, +}: { + searchParams: Promise<{ page?: string }>; +}) { + const { page: pageParam } = await searchParams; + const page = Math.max(1, Number(pageParam) || 1); + const result = await fetchBlogs({ page, pageSize: 12 }); + const usingApi = result.items.length > 0 && !String(result.items[0]?.id).startsWith("local-"); + const posts = usingApi ? result.items : getLocalBlogPosts(); + const pageCount = usingApi + ? Math.max(1, Math.ceil((result.total || result.items.length) / (result.pageSize || 12))) + : 1; + + return ( + <> + <PageHero + title="مقالات" + subtitle="آخرین مطالب آموزشی کلینیک ثامن" + image="/images/blog/post-1.jpg" + /> + <section className="section"> + <div className="container"> + <div className="card-grid"> + {posts.map((post) => ( + <Link key={post.id} href={blogHref(post)} className="media-card media-card--link"> + <div className="thumb"> + <Image src={blogImage(post)} alt={post.title} width={400} height={275} /> + </div> + <div className="body"> + <p className="meta-line">{formatFaDate(post.publishedAt || post.createdAt)}</p> + <h2>{post.title}</h2> + {post.abstract ? <p>{post.abstract}</p> : null} + <div className="meta"> + <span>مشاهده بیشتر</span> + </div> + </div> + </Link> + ))} + </div> + + {pageCount > 1 ? ( + <div className="pagination"> + {Array.from({ length: pageCount }, (_, index) => { + const number = index + 1; + return ( + <Link + key={number} + href={`/blog?page=${number}`} + className={number === page ? "active" : undefined} + > + {faDigits(number)} + </Link> + ); + })} + </div> + ) : null} + </div> + </section> + </> + ); +} diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx new file mode 100644 index 0000000..a022bc5 --- /dev/null +++ b/src/app/contact/page.tsx @@ -0,0 +1,53 @@ +import type { Metadata } from "next"; +import Link from "next/link"; + +import ContactForm from "@/components/ContactForm"; +import { site } from "@/data/site"; +import { pageMetadata } from "@/lib/seo"; + +export const metadata: Metadata = pageMetadata({ + title: "تماس با ما", + description: `تماس با ${site.name} — ${site.address} — تلفن ${site.phone}`, + path: "/contact", +}); + +export default function ContactPage() { + return ( + <> + <div className="page-hero"> + <div className="container"> + <h1>تماس با ما</h1> + <div className="breadcrumb"> + <Link href="/">خانه</Link> / تماس با ما + </div> + </div> + </div> + + <section className="section"> + <div className="container contact-layout"> + <div className="contact-card"> + <h2>تماس با کلینیک ثامن</h2> + <ul className="contact-list"> + <li> + <strong>آدرس:</strong> {site.address} + </li> + {site.phones.map((phone) => ( + <li key={phone}> + <strong>تلفن:</strong>{" "} + <a href={`tel:${phone.replace(/-/g, "")}`}>{phone}</a> + </li> + ))} + <li> + <strong>ساعات کاری:</strong> {site.hours} + </li> + </ul> + <div className="map-frame"> + <iframe title="موقعیت کلینیک ثامن" src={site.mapEmbed} loading="lazy" /> + </div> + </div> + <ContactForm /> + </div> + </section> + </> + ); +} diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000..d69463e --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,1938 @@ +@import "tailwindcss"; + +@font-face { + font-family: "iran-sans"; + src: url("/fonts/iran-sans/iran-sans-regular.ttf") format("truetype"); + font-weight: 400; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "iran-sans"; + src: url("/fonts/iran-sans/iran-sans-light.ttf") format("truetype"); + font-weight: 300; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "iran-sans"; + src: url("/fonts/iran-sans/iran-sans-medium.ttf") format("truetype"); + font-weight: 500; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "iran-sans"; + src: url("/fonts/iran-sans/iran-sans-semibold.ttf") format("truetype"); + font-weight: 600; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "iran-sans"; + src: url("/fonts/iran-sans/iran-sans-bold.ttf") format("truetype"); + font-weight: 700; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "montserrat"; + src: url("/fonts/montserrat/montserrat-regular.ttf") format("truetype"); + font-weight: 400; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "montserrat"; + src: url("/fonts/montserrat/montserrat-semibold.ttf") format("truetype"); + font-weight: 600; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "montserrat"; + src: url("/fonts/montserrat/montserrat-bold.ttf") format("truetype"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +:root { + --wb-primary-color: #dfeafe; + --wb-secondary-color: #0141c5; + --wb-accent: #0946c7; + --wb-mint: #3ed2a7; + --wb-text: #2a2a2a; + --wb-muted: #707070; + --wb-border: #e8eef8; + --wb-footer: #0b1f4d; + --wb-default-font: "iran-sans", Tahoma, sans-serif; + --container: min(1180px, calc(100% - 2rem)); +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + background: #fff; + color: var(--wb-text); + font-family: var(--wb-default-font); + line-height: 1.8; + -webkit-font-smoothing: antialiased; +} + +a { + color: inherit; + text-decoration: none; +} + +img { + max-width: 100%; + display: block; +} + +button { + font: inherit; + cursor: pointer; +} + +.container { + width: var(--container); + margin-inline: auto; +} + +.latin { + font-family: "montserrat", sans-serif; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +/* Top bar */ +.topbar { + background: #fff; + border-bottom: 1px solid #f0f3f8; + padding: 0.55rem 0; + font-size: 0.85rem; + color: var(--wb-muted); +} + +.topbar-inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.topbar-meta { + display: flex; + align-items: center; + gap: 1.25rem; + flex-wrap: wrap; +} + +.topbar-meta a:hover, +.topbar-meta span:hover { + color: var(--wb-accent); +} + +.social-row { + display: flex; + align-items: center; + gap: 0.55rem; +} + +.social-row a { + width: 30px; + height: 30px; + border-radius: 999px; + border: 1px solid #e5eaf3; + display: grid; + place-items: center; + color: var(--wb-accent); + transition: 0.25s ease; +} + +.social-row a:hover { + background: var(--wb-accent); + color: #fff; + border-color: var(--wb-accent); +} + +/* Header */ +.site-header { + background: #fff; + position: sticky; + top: 0; + z-index: 50; + box-shadow: 0 8px 24px rgba(1, 65, 197, 0.06); +} + +.header-brand { + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: 1rem; + padding: 0.85rem 0; +} + +.brand-copy { + text-align: center; +} + +.brand-copy h1, +.brand-title { + margin: 0; + font-size: clamp(1rem, 2.2vw, 1.35rem); + color: #1d1d1d; + font-weight: 700; +} + +.brand-copy p { + margin: 0.25rem 0 0; + color: var(--wb-muted); + font-size: 0.78rem; +} + +.logo-link img, +.org-logo img { + height: auto; + width: auto; + max-height: 68px; + object-fit: contain; +} + +.org-logo { + justify-self: end; +} + +.main-nav { + border-top: 1px solid #f0f3f8; + background: linear-gradient(180deg, #fff 0%, #f8fbff 100%); +} + +.main-nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.15rem 0.35rem; +} + +.main-nav a { + display: block; + padding: 0.85rem 0.9rem; + color: #333; + font-size: 0.92rem; + font-weight: 500; + position: relative; + transition: color 0.2s ease; +} + +.main-nav a:hover, +.main-nav a.active { + color: var(--wb-accent); +} + +.main-nav a::after { + content: ""; + position: absolute; + right: 0.9rem; + left: 0.9rem; + bottom: 0.45rem; + height: 2px; + background: var(--wb-accent); + transform: scaleX(0); + transition: transform 0.25s ease; +} + +.main-nav a:hover::after, +.main-nav a.active::after { + transform: scaleX(1); +} + +.nav-toggle { + display: none; + border: 1px solid #d9e3f5; + background: #fff; + border-radius: 10px; + padding: 0.45rem 0.7rem; + color: var(--wb-accent); +} + +/* Hero */ +.hero { + padding: 1.25rem 0 0.5rem; +} + +.hero > .container { + padding: 0; + margin-inline: auto; +} + +.hero-frame { + position: relative; + width: 100%; + margin: 0; + padding: 0; + border-radius: 18px; + overflow: hidden; + line-height: 0; + background: transparent; + aspect-ratio: 1920 / 740; +} + +.hero-slide { + position: absolute; + inset: 0; + opacity: 0; + transition: opacity 0.6s ease; + z-index: 0; +} + +.hero-slide.active { + opacity: 1; + z-index: 1; +} + +.hero-slide-link { + display: block; + position: absolute; + inset: 0; +} + +.hero-slide img { + display: block !important; + width: 100% !important; + max-width: none !important; + height: 100% !important; + object-fit: cover; + object-position: center; +} + +.hero-controls { + position: absolute; + z-index: 4; + inset: 0; + pointer-events: none; +} + +.hero-controls button { + pointer-events: auto; + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 44px; + height: 44px; + border-radius: 999px; + border: none; + background: rgba(255, 255, 255, 0.95); + color: #333; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.14); + display: inline-flex; + align-items: center; + justify-content: center; + transition: background 0.2s ease, transform 0.2s ease; +} + +.hero-controls button:first-child { + left: 1.25rem; +} + +.hero-controls button:last-child { + right: 1.25rem; +} + +.hero-controls button:hover { + background: #fff; + transform: translateY(-50%) scale(1.05); +} + +.hero-controls button svg { + display: block; +} + +.hero-dots { + position: absolute; + z-index: 4; + left: 50%; + bottom: 1rem; + transform: translateX(-50%); + display: flex; + gap: 0.4rem; +} + +.hero-dots button { + width: 28px; + height: 4px; + border: none; + border-radius: 999px; + background: rgba(255, 255, 255, 0.45); +} + +.hero-dots button.active { + background: var(--wb-accent); +} + +/* Sections */ +.section { + padding: 3.2rem 0; +} + +.section-head { + text-align: center; + margin-bottom: 2rem; +} + +.section-head h2 { + margin: 0; + font-size: clamp(1.25rem, 2.4vw, 1.75rem); + color: #1c1c1c; +} + +.section-head p { + margin: 0.45rem 0 0; + color: var(--wb-muted); +} + +.section-muted { + background: linear-gradient(180deg, #f7faff 0%, #fff 100%); +} + +/* Therapist cards */ +.therapist-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1.25rem; +} + +.therapist-card { + text-align: center; + transition: transform 0.3s ease; + display: block; +} + +.therapist-card:hover { + transform: translateY(-6px); +} + +.therapist-card .photo { + border-radius: 16px; + overflow: hidden; + aspect-ratio: 325 / 356; + background: #eef3fb; + margin-bottom: 0.85rem; +} + +.therapist-card .photo img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.45s ease; +} + +.therapist-card:hover .photo img { + transform: scale(1.04); +} + +.therapist-card h3 { + margin: 0; + font-size: 1rem; + color: #222; +} + +.therapist-card p { + margin: 0.25rem 0 0; + color: var(--wb-muted); + font-size: 0.86rem; +} + +.therapist-page-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; +} + +.therapist-detail { + background: #fff; + border: 1px solid var(--wb-border); + border-radius: 18px; + overflow: hidden; + display: grid; + grid-template-rows: auto 1fr; + transition: box-shadow 0.3s ease, transform 0.3s ease; +} + +.therapist-detail:hover { + box-shadow: 0 18px 40px rgba(1, 65, 197, 0.1); + transform: translateY(-4px); +} + +.therapist-detail .photo { + aspect-ratio: 1 / 1.05; + overflow: hidden; + background: #eef3fb; +} + +.therapist-detail .photo img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.therapist-detail .body { + padding: 1.1rem 1.15rem 1.3rem; +} + +.therapist-detail h3 { + margin: 0 0 0.55rem; + color: var(--wb-accent); + font-size: 1.05rem; +} + +.therapist-detail p { + margin: 0; + color: #555; + font-size: 0.88rem; + text-align: justify; + line-height: 1.9; +} + +/* Workshops / articles */ +.card-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1.15rem; +} + +.media-card { + border: 1px solid var(--wb-border); + border-radius: 16px; + overflow: hidden; + background: #fff; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.media-card:hover { + transform: translateY(-5px); + box-shadow: 0 16px 36px rgba(1, 65, 197, 0.1); +} + +.media-card .thumb { + position: relative; + aspect-ratio: 16 / 11; + overflow: hidden; + background: #eef3fb; +} + +.media-card .thumb img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.4s ease; +} + +.media-card:hover .thumb img { + transform: scale(1.05); +} + +.media-card .body { + padding: 1rem; +} + +.media-card .tag { + display: inline-block; + background: var(--wb-primary-color); + color: var(--wb-accent); + font-size: 0.75rem; + border-radius: 999px; + padding: 0.15rem 0.65rem; + margin-bottom: 0.45rem; +} + +.media-card h3 { + margin: 0; + font-size: 0.95rem; + line-height: 1.7; + min-height: 3.2em; +} + +.media-card p { + margin: 0.45rem 0 0; + color: var(--wb-muted); + font-size: 0.84rem; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.media-card .meta { + margin-top: 0.75rem; + display: flex; + justify-content: space-between; + align-items: center; + color: var(--wb-accent); + font-size: 0.82rem; + font-weight: 600; +} + +.articles-carousel { + position: relative; + --per-view: 4; +} + +.articles-carousel__viewport { + overflow: hidden; + padding-bottom: 0.25rem; + margin-inline: -0.65rem; + width: calc(100% + 1.3rem); +} + +.articles-carousel__track { + display: flex; + align-items: stretch; + transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1); + will-change: transform; +} + +.articles-carousel__item { + flex: 0 0 calc(100% / var(--per-view)); + width: calc(100% / var(--per-view)); + max-width: calc(100% / var(--per-view)); + min-width: 0; + box-sizing: border-box; + padding-inline: 0.65rem; + display: flex; +} + +.articles-carousel__item .media-card { + width: 100%; + display: flex; + flex-direction: column; +} + +.articles-carousel__item .body { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; +} + +.articles-carousel__item h3 { + min-height: 3.4em; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.articles-carousel__item p { + flex: 1; + min-height: 4.2em; + -webkit-line-clamp: 3; +} + +.articles-carousel__item .meta { + margin-top: auto; + padding-top: 0.85rem; +} + +.articles-carousel__controls { + display: flex; + justify-content: center; + gap: 0.75rem; + margin-top: 1.25rem; +} + +.articles-carousel__controls button { + width: 44px; + height: 44px; + border-radius: 999px; + border: 1px solid #d8e2f3; + background: #fff; + color: var(--wb-accent); + box-shadow: 0 6px 16px rgba(1, 65, 197, 0.08); + display: inline-flex; + align-items: center; + justify-content: center; + transition: 0.2s ease; +} + +.articles-carousel__controls button svg { + display: block; +} + +.articles-carousel__controls button:hover { + background: var(--wb-accent); + color: #fff; + border-color: var(--wb-accent); +} + +/* Consult modes */ +.consult-row { + display: grid; + grid-template-columns: 1.2fr 1fr; + gap: 1.5rem; + align-items: stretch; +} + +.consult-modes { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; +} + +.consult-item { + background: #fff; + border: 1px solid var(--wb-border); + border-radius: 16px; + padding: 1.4rem 1rem; + text-align: center; + transition: transform 0.3s ease, border-color 0.3s ease; +} + +.consult-item:hover { + transform: translateY(-4px); + border-color: #b9cdf8; +} + +.consult-item img { + width: 52px; + height: 52px; + margin: 0 auto 0.8rem; + object-fit: contain; +} + +.consult-item h3 { + margin: 0; + font-size: 0.95rem; +} + +.consult-item .latin { + margin: 0.35rem 0 0; + color: #9aa4b5; + font-size: 0.7rem; +} + +.about-cta { + border-radius: 18px; + overflow: hidden; + position: relative; + min-height: 100%; + background: linear-gradient(135deg, #0141c5, #0946c7 55%, #3ed2a7); + color: #fff; + display: grid; + place-items: center; + padding: 2rem; + text-align: center; +} + +.about-cta img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + opacity: 0.28; +} + +.about-cta .content { + position: relative; + z-index: 1; +} + +.about-cta h3 { + margin: 0 0 1rem; + font-size: 1.35rem; +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + border-radius: 10px; + padding: 0.7rem 1.25rem; + font-weight: 600; + transition: 0.25s ease; + border: none; +} + +.btn-primary { + background: var(--wb-accent); + color: #fff; +} + +.btn-primary:hover { + background: #0136a5; +} + +.btn-light { + background: #fff; + color: var(--wb-accent); +} + +.btn-light:hover { + transform: translateY(-2px); +} + +.btn-outline { + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.7); + color: #fff; +} + +/* Services */ +.service-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; +} + +.service-card { + text-align: center; + padding: 1.4rem 1rem; + border-radius: 16px; + background: #fff; + border: 1px solid var(--wb-border); + transition: 0.3s ease; + display: block; +} + +.service-card:hover { + border-color: #b9cdf8; + box-shadow: 0 12px 28px rgba(1, 65, 197, 0.08); + transform: translateY(-4px); +} + +.service-card img { + width: 78px; + height: 78px; + margin: 0 auto 0.85rem; + object-fit: contain; +} + +.service-card .service-icon { + width: 78px; + margin: 0 auto 0.85rem; +} + +.service-card .service-icon img { + width: 100%; + height: 100%; + margin: 0; + object-fit: contain; +} + +.service-card h3 { + margin: 0; + font-size: 0.95rem; +} + +.service-card .latin { + margin: 0.35rem 0 0; + color: #9aa4b5; + font-size: 0.7rem; +} + +.banner-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.15rem; +} + +.promo-banner { + position: relative; + border-radius: 18px; + overflow: hidden; + min-height: 220px; + color: #fff; + aspect-ratio: 540 / 312; +} + +.promo-banner img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; +} + +.promo-banner .shade { + position: absolute; + inset: 0; + background: linear-gradient(90deg, rgba(1, 65, 197, 0.82), rgba(1, 65, 197, 0.35)); +} + +.promo-banner .content { + position: relative; + z-index: 1; + padding: 1.8rem; + max-width: 70%; +} + +.promo-banner h3 { + margin: 0 0 0.75rem; + font-size: 1.25rem; +} + +/* Testimonials + stats */ +.testimonials { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.15rem; +} + +.testimonial { + background: #fff; + border: 1px solid var(--wb-border); + border-radius: 16px; + padding: 1.35rem; + margin: 0; +} + +.testimonial h5 { + margin: 0.65rem 0 0.35rem; + font-size: 0.95rem; + line-height: 1.9; + font-weight: 500; + color: #444; +} + +.testimonial .name { + color: var(--wb-accent); + font-weight: 700; +} + +.testimonial .date { + color: var(--wb-muted); + font-size: 0.82rem; + margin-top: auto; + padding-top: 0.75rem; +} + +.testimonials-carousel { + position: relative; + --per-view: 2; +} + +.testimonials-carousel__viewport { + position: relative; + overflow: hidden; + margin-inline: -0.5rem; + width: calc(100% + 1rem); +} + +.testimonials-carousel__track { + display: flex; + align-items: stretch; + transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1); + will-change: transform; +} + +.testimonials-carousel__item { + flex: 0 0 calc(100% / var(--per-view)); + width: calc(100% / var(--per-view)); + max-width: calc(100% / var(--per-view)); + min-width: 0; + box-sizing: border-box; + padding-inline: 0.5rem; + display: flex; +} + +.testimonials-carousel__item .testimonial { + width: 100%; + display: flex; + flex-direction: column; +} + +.testimonials-carousel__controls { + position: absolute; + inset: 0; + z-index: 3; + pointer-events: none; +} + +.testimonials-carousel__controls button { + pointer-events: auto; + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 44px; + height: 44px; + border-radius: 999px; + border: 1px solid #d8e2f3; + background: rgba(255, 255, 255, 0.96); + color: var(--wb-accent); + box-shadow: 0 6px 16px rgba(1, 65, 197, 0.12); + display: inline-flex; + align-items: center; + justify-content: center; + transition: 0.2s ease; +} + +.testimonials-carousel__controls button:first-child { + left: 0.15rem; +} + +.testimonials-carousel__controls button:last-child { + right: 0.15rem; +} + +.testimonials-carousel__controls button svg { + display: block; +} + +.testimonials-carousel__controls button:hover { + background: var(--wb-accent); + color: #fff; + border-color: var(--wb-accent); + transform: translateY(-50%) scale(1.05); +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; + margin-top: 2rem; +} + +.stat-item { + text-align: center; + padding: 1.2rem 0.75rem; + border-radius: 16px; + background: linear-gradient(180deg, #f4f8ff, #fff); + border: 1px solid var(--wb-border); +} + +.stat-item strong { + display: block; + font-size: 1.8rem; + color: var(--wb-accent); + font-weight: 700; +} + +.stat-item span { + display: block; + margin-top: 0.25rem; + font-size: 0.9rem; +} + +.stat-item .latin { + margin-top: 0.2rem; + color: #9aa4b5; + font-size: 0.68rem; +} + +/* Page hero */ +.page-hero { + background: linear-gradient(180deg, #eef4ff 0%, #fff 100%); + border-bottom: 1px solid var(--wb-border); + padding: 2.4rem 0 1.8rem; + text-align: center; +} + +.page-hero h1 { + margin: 0; + font-size: clamp(1.4rem, 3vw, 2rem); + color: #1d1d1d; +} + +.page-hero .breadcrumb { + margin-top: 0.55rem; + color: var(--wb-muted); + font-size: 0.88rem; +} + +.page-hero .breadcrumb a { + color: var(--wb-accent); +} + +/* About / contact */ +.about-layout { + display: grid; + grid-template-columns: 1.1fr 0.9fr; + gap: 2rem; + align-items: start; +} + +.about-layout .visual { + border-radius: 18px; + overflow: hidden; + background: #eef3fb; +} + +.about-layout .visual img { + width: 100%; + height: 100%; + object-fit: cover; + min-height: 360px; +} + +.about-points { + list-style: none; + margin: 1.25rem 0 0; + padding: 0; + display: grid; + gap: 0.85rem; +} + +.about-points li { + position: relative; + padding-right: 1.35rem; + color: #444; + text-align: justify; +} + +.about-points li::before { + content: ""; + position: absolute; + right: 0; + top: 0.65rem; + width: 8px; + height: 8px; + border-radius: 999px; + background: var(--wb-mint); +} + +.contact-layout { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +.contact-card, +.contact-form { + border: 1px solid var(--wb-border); + border-radius: 18px; + padding: 1.5rem; + background: #fff; +} + +.contact-card h2, +.contact-form h2 { + margin: 0 0 1rem; + font-size: 1.2rem; + color: var(--wb-accent); +} + +.contact-list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 0.8rem; +} + +.contact-list li { + color: #444; +} + +.contact-list a:hover { + color: var(--wb-accent); +} + +.map-frame { + margin-top: 1rem; + border-radius: 14px; + overflow: hidden; + border: 1px solid var(--wb-border); + min-height: 220px; +} + +.map-frame iframe { + width: 100%; + height: 220px; + border: 0; +} + +.form-grid { + display: grid; + gap: 0.85rem; +} + +.form-grid label { + display: grid; + gap: 0.35rem; + font-size: 0.9rem; + color: #444; +} + +.form-grid input, +.form-grid textarea { + width: 100%; + border: 1px solid #d8e2f3; + border-radius: 10px; + padding: 0.75rem 0.9rem; + font: inherit; + background: #fbfcff; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.form-grid input:focus, +.form-grid textarea:focus { + outline: none; + border-color: var(--wb-accent); + box-shadow: 0 0 0 3px rgba(9, 70, 199, 0.12); +} + +.form-grid textarea { + min-height: 140px; + resize: vertical; +} + +/* Footer */ +.site-footer { + background: linear-gradient(180deg, #0b1f4d 0%, #08163a 100%); + color: #d7def0; + margin-top: 2rem; +} + +.footer-main { + padding: 3rem 0 2rem; +} + +.footer-grid { + display: grid; + grid-template-columns: 1.4fr 1fr 1fr 1fr; + gap: 1.5rem; +} + +.site-footer h3 { + margin: 0 0 1rem; + color: #fff; + font-size: 1.05rem; +} + +.site-footer p { + margin: 0; + font-size: 0.9rem; + line-height: 1.9; + text-align: justify; +} + +.footer-list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 0.55rem; +} + +.footer-list a:hover { + color: #fff; +} + +.footer-bottom { + border-top: 1px solid rgba(255, 255, 255, 0.08); + padding: 0.85rem 0 1rem; +} + +.footer-bottom-bar { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 12px; + justify-content: space-between; + padding: 4px 0; +} + +.footer-bottom-site { + color: #9c9c9c; + font-size: 12px; +} + +.meshkee-credit { + align-items: center; + color: #9c9c9c; + display: inline-flex; + gap: 10px; + padding: 6px 10px; + position: relative; + text-decoration: none; + transition: color 0.3s cubic-bezier(0.22, 1, 0.36, 1); +} + +.meshkee-credit:hover { + color: #e0e0e0; + text-decoration: none; +} + +.meshkee-credit__frame { + inset: 0; + pointer-events: none; + position: absolute; +} + +.meshkee-credit__line { + background: #777; + position: absolute; + transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1); +} + +.meshkee-credit__line--l { + height: 100%; + left: 0; + top: 0; + transform: scaleY(0); + transform-origin: top; + transition-delay: 0s; + width: 1px; +} + +.meshkee-credit__line--b { + bottom: 0; + height: 1px; + left: 0; + transform: scaleX(0); + transform-origin: left; + transition-delay: 0.14s; + width: 100%; +} + +.meshkee-credit__line--r { + height: 100%; + right: 0; + top: 0; + transform: scaleY(0); + transform-origin: bottom; + transition-delay: 0.28s; + width: 1px; +} + +.meshkee-credit__line--t { + height: 1px; + left: 0; + top: 0; + transform: scaleX(0); + transform-origin: right; + transition-delay: 0.42s; + width: 100%; +} + +.meshkee-credit:hover .meshkee-credit__line--l, +.meshkee-credit:hover .meshkee-credit__line--r { + transform: scaleY(1); +} + +.meshkee-credit:hover .meshkee-credit__line--t, +.meshkee-credit:hover .meshkee-credit__line--b { + transform: scaleX(1); +} + +.meshkee-credit:not(:hover) .meshkee-credit__line--l { + transition-delay: 0.42s; +} + +.meshkee-credit:not(:hover) .meshkee-credit__line--b { + transition-delay: 0.28s; +} + +.meshkee-credit:not(:hover) .meshkee-credit__line--r { + transition-delay: 0.14s; +} + +.meshkee-credit:not(:hover) .meshkee-credit__line--t { + transition-delay: 0s; +} + +.meshkee-credit__logo { + display: block; + flex-shrink: 0; + height: 42px; + width: auto; + aspect-ratio: 1 / 1; + object-fit: contain; + opacity: 0.7; + position: relative; + transition: opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1); +} + +.meshkee-credit:hover .meshkee-credit__logo { + opacity: 1; +} + +.meshkee-credit__text { + display: flex; + flex-direction: column; + justify-content: center; + line-height: 1.25; + min-height: 42px; + position: relative; +} + +.meshkee-credit__label { + font-size: 11px; +} + +.meshkee-credit__name { + color: #cfcfcf; + font-size: 13px; + font-weight: 600; + transition: color 0.3s cubic-bezier(0.22, 1, 0.36, 1); +} + +.meshkee-credit:hover .meshkee-credit__name { + color: #fff; +} + +@media (max-width: 1100px) { + .therapist-grid, + .card-grid, + .service-grid, + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } + + .therapist-page-grid { + grid-template-columns: repeat(2, 1fr); + } + + .footer-grid { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 860px) { + .header-brand { + grid-template-columns: 1fr auto; + } + + .org-logo { + display: none; + } + + .brand-copy { + text-align: right; + } + + .nav-toggle { + display: inline-flex; + } + + .main-nav { + display: none; + } + + .main-nav.open { + display: block; + } + + .main-nav ul { + flex-direction: column; + align-items: stretch; + padding: 0.5rem 0 1rem; + } + + .consult-row, + .about-layout, + .contact-layout, + .banner-row, + .testimonials { + grid-template-columns: 1fr; + } + + .consult-modes { + grid-template-columns: 1fr; + } +} + +@media (max-width: 575px) { + .therapist-grid, + .card-grid, + .service-grid, + .stats-grid, + .therapist-page-grid, + .footer-grid { + grid-template-columns: 1fr; + } + + .topbar-inner { + flex-direction: column; + align-items: flex-start; + } + + .footer-bottom-bar { + flex-direction: column; + justify-content: center; + text-align: center; + } +} + +/* Topbar account menu */ +.topbar-actions { + display: flex; + align-items: center; + gap: 0.85rem; +} + +.account-menu { + position: relative; + display: inline-flex; + align-items: center; +} + +.account-menu--login { + gap: 0.4rem; + color: var(--wb-accent); + font-size: 0.82rem; + font-weight: 500; +} + +.account-menu--login:hover { + color: #0036a8; +} + +.account-menu__trigger { + display: inline-flex; + align-items: center; + gap: 0.4rem; + border: 1px solid #e5eaf3; + background: #fff; + border-radius: 999px; + padding: 0.35rem 0.75rem; + color: var(--wb-text); + font-size: 0.82rem; +} + +.account-menu__name { + max-width: 9rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.account-menu__chevron { + transition: transform 0.2s ease; +} + +.account-menu__chevron.open { + transform: rotate(180deg); +} + +.account-menu__dropdown { + position: absolute; + top: calc(100% + 0.45rem); + left: 0; + min-width: 11rem; + background: #fff; + border: 1px solid var(--wb-border); + border-radius: 14px; + box-shadow: 0 12px 32px rgba(1, 65, 197, 0.12); + overflow: hidden; + z-index: 60; +} + +.account-menu__logout { + border: 0; + background: transparent; + color: #d64545; +} + +.page-hero__inner { + display: grid; + grid-template-columns: 1fr auto; + gap: 1.5rem; + align-items: center; + text-align: right; +} + +.page-hero__kicker { + margin: 0 0 0.35rem; + color: var(--wb-accent); + font-size: 0.75rem; +} + +.page-hero__inner > div > p:last-child { + margin: 0.65rem 0 0; + color: var(--wb-muted); +} + +.page-hero__image { + border-radius: 16px; + overflow: hidden; + max-width: 320px; +} + +.page-hero__image img { + width: 100%; + height: auto; + object-fit: cover; +} + +.media-card--link { + display: block; + height: 100%; +} + +.section-cta { + margin-top: 1.25rem; + text-align: center; +} + +.pagination { + display: flex; + justify-content: center; + gap: 0.45rem; + margin-top: 1.5rem; +} + +.pagination a { + width: 2.4rem; + height: 2.4rem; + display: grid; + place-items: center; + border-radius: 10px; + border: 1px solid var(--wb-border); + color: var(--wb-text); + font-size: 0.9rem; +} + +.pagination a.active { + background: var(--wb-accent); + border-color: var(--wb-accent); + color: #fff; +} + +.detail-page { + max-width: 920px; +} + +.detail-lead { + margin: 0 0 1rem; + color: #444; + font-size: 1.02rem; + line-height: 2; +} + +.meta-line { + margin: 0 0 0.85rem; + color: var(--wb-muted); + font-size: 0.88rem; +} + +.back-link { + display: inline-flex; + align-items: center; + gap: 0.65rem; + margin-top: 1.5rem; + color: var(--wb-accent); + font-weight: 600; +} + +.back-link::before { + content: "←"; +} + +.rich-text { + line-height: 2; + color: #444; +} + +.rich-text h2, +.rich-text h3 { + color: #1d1d1d; + margin-top: 1.5rem; +} + +.rich-text p { + margin: 0 0 1rem; +} + +.rich-text img { + max-width: 100%; + height: auto; + border-radius: 12px; +} + +.detail-image img { + width: 100%; + height: auto; + border-radius: 16px; +} + +.entity-tabs { + margin-top: 2rem; + border: 1px solid var(--wb-border); + border-radius: 16px; + background: #fff; + padding: 1.25rem; +} + +.entity-tabs__nav { + display: flex; + gap: 0.45rem; + border-bottom: 1px solid var(--wb-border); + padding-bottom: 0.75rem; +} + +.entity-tabs__nav button { + border: 0; + background: transparent; + padding: 0.45rem 0.85rem; + border-radius: 10px; + color: var(--wb-muted); + font-size: 0.9rem; +} + +.entity-tabs__nav button.active { + background: var(--wb-primary-color); + color: var(--wb-accent); + font-weight: 600; +} + +.entity-tabs__title { + margin: 0; + font-size: 1rem; +} + +.entity-tabs__body { + margin-top: 1rem; +} + +.entity-tabs__empty { + margin: 0; + color: var(--wb-muted); + font-size: 0.9rem; +} + +.comment-list { + display: grid; + gap: 0.75rem; +} + +.comment-item { + background: #f8fbff; + border-radius: 12px; + padding: 0.85rem 1rem; +} + +.comment-item__author { + margin: 0; + font-weight: 700; + color: #1d1d1d; +} + +.comment-item__date { + margin: 0.2rem 0 0; + font-size: 0.78rem; + color: var(--wb-muted); +} + +.comment-item__text { + margin: 0.45rem 0 0; + line-height: 1.9; +} + +.login-prompt { + margin-top: 1rem; + padding: 1rem; + border-radius: 14px; + background: #f8fbff; +} + +.login-prompt--inline { + margin-top: 0; +} + +.login-prompt__title { + margin: 0; + font-weight: 700; +} + +.login-prompt__text { + margin: 0.35rem 0 0.85rem; + color: var(--wb-muted); + font-size: 0.9rem; +} + +.workshop-detail { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 1.5rem; + align-items: start; +} + +.workshop-gallery__main { + position: relative; + display: block; + width: 100%; + aspect-ratio: 4 / 3; + border: 0; + padding: 0; + border-radius: 16px; + overflow: hidden; + background: #eef3fb; + cursor: zoom-in; +} + +.workshop-gallery__image { + object-fit: cover; +} + +.workshop-gallery__zoom { + pointer-events: none; + position: absolute; + inset: 0; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + transition: opacity 0.15s ease, transform 0.15s ease; +} + +.workshop-gallery__thumbs { + display: flex; + gap: 0.45rem; + margin-top: 0.65rem; + overflow-x: auto; +} + +.workshop-gallery__thumbs button { + border: 2px solid transparent; + border-radius: 10px; + overflow: hidden; + padding: 0; + background: transparent; + flex: 0 0 auto; +} + +.workshop-gallery__thumbs button.active { + border-color: var(--wb-accent); +} + +.workshop-gallery__thumbs img { + display: block; + width: 72px; + height: 72px; + object-fit: cover; +} + +.workshop-registration { + margin-top: 1rem; + border: 1px solid var(--wb-border); + border-radius: 16px; + padding: 1rem; + background: #f8fbff; +} + +.workshop-registration__meta { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.75rem; +} + +.workshop-registration__meta span { + display: block; + color: var(--wb-muted); + font-size: 0.82rem; +} + +.workshop-registration__meta strong { + display: block; + margin-top: 0.15rem; + color: #1d1d1d; +} + +.workshop-registration__action { + margin-top: 1rem; +} + +.workshop-registration__success { + margin: 0.65rem 0 0; + color: #168a5b; + font-size: 0.9rem; +} + +.workshop-registration__error { + margin: 0.65rem 0 0; + color: #d64545; + font-size: 0.9rem; +} + +.lightbox { + position: fixed; + inset: 0; + z-index: 100; + display: grid; + place-items: center; + background: rgba(11, 31, 77, 0.86); + padding: 1rem; +} + +.lightbox__close { + position: absolute; + top: 1rem; + left: 1rem; + width: 2.5rem; + height: 2.5rem; + border: 0; + border-radius: 999px; + background: #fff; + color: #1d1d1d; + font-size: 1.1rem; +} + +.lightbox__nav { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 2.6rem; + height: 2.6rem; + border: 0; + border-radius: 999px; + background: rgba(255, 255, 255, 0.92); + color: #1d1d1d; + font-size: 1.6rem; + line-height: 1; +} + +.lightbox__nav--prev { + right: 1rem; +} + +.lightbox__nav--next { + left: 1rem; +} + +.lightbox__figure { + margin: 0; + max-width: min(960px, 100%); +} + +.lightbox__figure img { + max-height: 85vh; + width: auto; + max-width: 100%; + border-radius: 12px; +} + +.lightbox__figure figcaption { + margin-top: 0.65rem; + text-align: center; + color: #fff; + font-size: 0.9rem; +} + +@media (max-width: 860px) { + .page-hero__inner, + .workshop-detail { + grid-template-columns: 1fr; + } + + .page-hero__image { + max-width: none; + } + + .account-menu__dropdown { + left: auto; + right: 0; + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..a875949 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,49 @@ +import type { Metadata } from "next"; + +import Footer from "@/components/Footer"; +import Header from "@/components/Header"; +import Providers from "@/components/Providers"; +import { site } from "@/data/site"; +import { websiteDomain } from "@/lib/config"; +import { getBusinessId } from "@/lib/meshkee"; + +import "./globals.css"; + +export const metadata: Metadata = { + metadataBase: new URL(`https://${websiteDomain}`), + title: { + default: "کلینیک مشاوره و روانشناسی ثامن قم", + template: "%s | کلینیک ثامن قم", + }, + description: site.description, + icons: { + icon: "/favicon.png", + }, + openGraph: { + locale: "fa_IR", + siteName: site.shortName, + type: "website", + }, +}; + +export default async function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + const businessId = await getBusinessId(); + + return ( + <html lang="fa" dir="rtl"> + <body> + <Providers businessId={businessId}> + <div className="wrapper"> + <Header /> + <main>{children}</main> + <Footer /> + </div> + </Providers> + </body> + </html> + ); +} diff --git a/src/app/meshkee/sitemap-config.json/route.ts b/src/app/meshkee/sitemap-config.json/route.ts new file mode 100644 index 0000000..998558b --- /dev/null +++ b/src/app/meshkee/sitemap-config.json/route.ts @@ -0,0 +1,17 @@ +import sitemapConfig from "@/lib/sitemap-config.generated.json"; + +const headers = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type", + "Cache-Control": "public, max-age=60", + "Content-Type": "application/json; charset=utf-8", +}; + +export async function OPTIONS() { + return new Response(null, { status: 204, headers }); +} + +export async function GET() { + return Response.json(sitemapConfig, { headers }); +} diff --git a/src/app/meshkee/static-image-slots/route.ts b/src/app/meshkee/static-image-slots/route.ts new file mode 100644 index 0000000..0f648ec --- /dev/null +++ b/src/app/meshkee/static-image-slots/route.ts @@ -0,0 +1,16 @@ +import { STATIC_IMAGE_SLOTS } from "@/lib/static-images"; + +const headers = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type", + "Cache-Control": "public, max-age=60", +}; + +export async function OPTIONS() { + return new Response(null, { status: 204, headers }); +} + +export async function GET() { + return Response.json({ slots: STATIC_IMAGE_SLOTS }, { headers }); +} diff --git a/src/app/ourdr/page.tsx b/src/app/ourdr/page.tsx new file mode 100644 index 0000000..4d2f36d --- /dev/null +++ b/src/app/ourdr/page.tsx @@ -0,0 +1,49 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; + +import { site, therapists } from "@/data/site"; +import { pageMetadata } from "@/lib/seo"; + +export const metadata: Metadata = pageMetadata({ + title: "درمانگران", + description: `درمانگران و مشاوران ${site.name} — رزرو نوبت مشاوره فردی، خانواده و ازدواج در قم.`, + path: "/ourdr", +}); + +export default function TherapistsPage() { + return ( + <> + <div className="page-hero"> + <div className="container"> + <h1>درمانگران</h1> + <div className="breadcrumb"> + <Link href="/">خانه</Link> / درمانگران + </div> + </div> + </div> + + <section className="section"> + <div className="container"> + <div className="section-head"> + <h2>مشاوران کلینیک روانشناسی ثامن</h2> + <p>جهت رزرو نوبت مشاوره تماس بگیرید</p> + </div> + <div className="therapist-page-grid"> + {therapists.map((item) => ( + <article key={item.name} className="therapist-detail"> + <div className="photo"> + <Image src={item.image} alt={item.name} width={420} height={440} /> + </div> + <div className="body"> + <h3>{item.name}</h3> + <p>{item.bio}</p> + </div> + </article> + ))} + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 0000000..9b33c2e --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,102 @@ +import HeroSlider from "@/components/HeroSlider"; +import HomeSections from "@/components/HomeSections"; +import { homeTherapists, serviceCards, site, slides } from "@/data/site"; +import { fetchBlogs, getLocalBlogPosts } from "@/lib/blog"; +import { pageMetadata } from "@/lib/seo"; +import { fetchStaticImageSlots, overlaySlotImages, pickSlot } from "@/lib/static-images"; +import { fetchWorkshops } from "@/lib/workshops"; + +export const revalidate = 60; + +export const metadata = pageMetadata({ + title: "کلینیک مشاوره و روانشناسی ثامن قم", + description: `${site.description} — مشاوره فردی، خانواده، ازدواج، کودک و کارگاه‌های تخصصی در قم.`, + path: "/", +}); + +export default async function HomePage() { + const [slots, blogResult, workshopResult] = await Promise.all([ + fetchStaticImageSlots("home"), + fetchBlogs({ pageSize: 8 }), + fetchWorkshops({ pageSize: 4 }), + ]); + + const blogPosts = + blogResult.items.length > 0 && !String(blogResult.items[0]?.id).startsWith("local-") + ? blogResult.items + : getLocalBlogPosts(); + const workshops = workshopResult.items; + + const slider = overlaySlotImages( + pickSlot(slots, "slider"), + slides.map((slide, index) => { + const item = slide as { image: string; title: string; english: string; alt: string }; + return { + id: `slide-${index}`, + image: item.image, + title: item.alt || item.title, + kicker: item.english, + }; + }), + "slider", + ); + + const people = overlaySlotImages( + pickSlot(slots, "4-people-image"), + homeTherapists.map((person, index) => ({ + id: `person-${index}`, + image: person.image, + href: "/ourdr", + title: person.name, + text: person.role, + })), + "4-people-image", + ); + + const serviceIcons = overlaySlotImages( + pickSlot(slots, "our-services-icon"), + serviceCards.map((service, index) => ({ + id: `service-${index}`, + image: service.image, + href: service.href, + title: service.title, + kicker: service.english, + })), + "our-services-icon", + ); + + const banners = overlaySlotImages( + pickSlot(slots, "two-banner-bg"), + [ + { + id: "banner-workshops", + image: "/images/banners/workshops.jpg", + href: "/workshops", + title: "کارگاه عمومی", + }, + { + id: "banner-individual", + image: "/images/banners/individual.jpg", + href: "/contact", + title: "مشاوره فردی", + }, + ], + "two-banner-bg", + ); + + return ( + <> + <HeroSlider slides={slider.items} aspectRatio={slider.aspectRatio} /> + <HomeSections + people={people.items} + peopleAspectRatio={people.aspectRatio} + serviceIcons={serviceIcons.items} + serviceIconsAspectRatio={serviceIcons.aspectRatio} + banners={banners.items} + bannersAspectRatio={banners.aspectRatio} + workshops={workshops} + articles={blogPosts} + /> + </> + ); +} diff --git a/src/app/workshops/[slug]/page.tsx b/src/app/workshops/[slug]/page.tsx new file mode 100644 index 0000000..9759f86 --- /dev/null +++ b/src/app/workshops/[slug]/page.tsx @@ -0,0 +1,77 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import { notFound } from "next/navigation"; + +import EntityTabs from "@/components/EntityTabs"; +import PageHero from "@/components/PageHero"; +import WorkshopGallery from "@/components/WorkshopGallery"; +import WorkshopRegistration from "@/components/WorkshopRegistration"; +import { formatFaDate } from "@/lib/format"; +import { fetchWorkshopBySlug, workshopHref, workshopImage, workshopImages } from "@/lib/workshops"; +import { pageMetadata } from "@/lib/seo"; + +export const revalidate = 60; + +export async function generateMetadata({ + params, +}: { + params: Promise<{ slug: string }>; +}): Promise<Metadata> { + const { slug } = await params; + const workshop = await fetchWorkshopBySlug(slug); + if (!workshop) return { title: "کارگاه" }; + return pageMetadata({ + title: workshop.title, + description: workshop.abstract ?? workshop.title, + path: workshopHref(workshop), + image: workshopImage(workshop), + }); +} + +export default async function WorkshopDetailPage({ + params, +}: { + params: Promise<{ slug: string }>; +}) { + const { slug } = await params; + const workshop = await fetchWorkshopBySlug(slug); + if (!workshop) notFound(); + + const comments = workshop.comments ?? []; + + return ( + <> + <PageHero title={workshop.title} subtitle={workshop.abstract ?? undefined} /> + <section className="section"> + <div className="container detail-page"> + <div className="workshop-detail"> + <WorkshopGallery images={workshopImages(workshop)} alt={workshop.title} /> + <div className="workshop-detail__content"> + {workshop.eventDate ? ( + <p className="meta-line">تاریخ: {formatFaDate(workshop.eventDate)}</p> + ) : null} + {workshop.abstract ? <p className="detail-lead">{workshop.abstract}</p> : null} + <WorkshopRegistration + workshopId={workshop.id} + eventDate={workshop.eventDate} + eventTime={workshop.eventTime} + duration={workshop.duration} + status={workshop.status} + /> + </div> + </div> + + <EntityTabs + descriptionHtml={workshop.mainTextHtml} + comments={comments} + showDescription + /> + + <Link href="/workshops" className="back-link"> + بازگشت به کارگاه‌ها + </Link> + </div> + </section> + </> + ); +} diff --git a/src/app/workshops/page.tsx b/src/app/workshops/page.tsx new file mode 100644 index 0000000..cdfb472 --- /dev/null +++ b/src/app/workshops/page.tsx @@ -0,0 +1,79 @@ +import Image from "next/image"; +import Link from "next/link"; + +import PageHero from "@/components/PageHero"; +import { faDigits, formatFaDate } from "@/lib/format"; +import { pageMetadata } from "@/lib/seo"; +import { fetchWorkshops, workshopHref, workshopImage } from "@/lib/workshops"; + +export const revalidate = 60; + +export const metadata = pageMetadata({ + title: "کارگاه‌ها", + description: "کارگاه‌های تخصصی کلینیک روانشناسی و مرکز مشاوره ثامن قم", + path: "/workshops", + image: "/images/banners/workshops.jpg", +}); + +export default async function WorkshopsPage({ + searchParams, +}: { + searchParams: Promise<{ page?: string }>; +}) { + const { page: pageParam } = await searchParams; + const page = Math.max(1, Number(pageParam) || 1); + const result = await fetchWorkshops({ page, pageSize: 12 }); + const usingApi = result.items.length > 0 && !String(result.items[0]?.id).startsWith("local-"); + const pageCount = usingApi + ? Math.max(1, Math.ceil((result.total || result.items.length) / (result.pageSize || 12))) + : 1; + + return ( + <> + <PageHero + title="کارگاه‌های تخصصی" + subtitle="کارگاه‌های در حال ثبت‌نام کلینیک ثامن" + image="/images/banners/workshops.jpg" + /> + <section className="section section-muted"> + <div className="container"> + <div className="card-grid"> + {result.items.map((item) => ( + <Link key={item.id} href={workshopHref(item)} className="media-card media-card--link"> + <div className="thumb"> + <Image src={workshopImage(item)} alt={item.title} width={400} height={275} /> + </div> + <div className="body"> + {item.tag ? <span className="tag">{item.tag}</span> : null} + <h2>{item.title}</h2> + {item.abstract ? <p>{item.abstract}</p> : null} + <div className="meta"> + <span>{item.status || "جزئیات رویداد"}</span> + {item.eventDate ? <span>{formatFaDate(item.eventDate)}</span> : null} + </div> + </div> + </Link> + ))} + </div> + + {pageCount > 1 ? ( + <div className="pagination"> + {Array.from({ length: pageCount }, (_, index) => { + const number = index + 1; + return ( + <Link + key={number} + href={`/workshops?page=${number}`} + className={number === page ? "active" : undefined} + > + {faDigits(number)} + </Link> + ); + })} + </div> + ) : null} + </div> + </section> + </> + ); +} diff --git a/src/components/AccountMenu.tsx b/src/components/AccountMenu.tsx new file mode 100644 index 0000000..2437c06 --- /dev/null +++ b/src/components/AccountMenu.tsx @@ -0,0 +1,167 @@ +"use client"; + +import { useEffect, useRef, useState, type MouseEvent } from "react"; + +import { businessDashboardUrl, customerPortalUrl } from "@/lib/config"; +import { useSession, userDisplayName } from "@/lib/session"; + +const itemClass = + "block w-full px-3.5 py-2.5 text-right text-sm text-[var(--wb-text)] transition-colors hover:bg-[var(--wb-primary-color)] hover:text-[var(--wb-accent)]"; + +function UserIcon() { + return ( + <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden> + <circle cx="12" cy="8" r="3.25" stroke="currentColor" strokeWidth="1.75" /> + <path + d="M5.5 19.25c1.4-3 3.8-4.5 6.5-4.5s5.1 1.5 6.5 4.5" + stroke="currentColor" + strokeWidth="1.75" + strokeLinecap="round" + /> + </svg> + ); +} + +function ChevronIcon({ open }: { open: boolean }) { + return ( + <svg + width="14" + height="14" + viewBox="0 0 24 24" + fill="none" + aria-hidden + className={open ? "account-menu__chevron open" : "account-menu__chevron"} + > + <path d="m6 9 6 6 6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" /> + </svg> + ); +} + +export default function AccountMenu() { + const { user, isAuthenticated, ready, isWebsiteAdmin, logout, getAccessToken } = useSession(); + const [open, setOpen] = useState(false); + const [handoffBusy, setHandoffBusy] = useState(false); + const menuRef = useRef<HTMLDivElement>(null); + + useEffect(() => { + if (!open) return; + const onClickOutside = (event: Event) => { + if (menuRef.current && event.target instanceof Node && !menuRef.current.contains(event.target)) { + setOpen(false); + } + }; + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") setOpen(false); + }; + document.addEventListener("mousedown", onClickOutside); + document.addEventListener("keydown", onKeyDown); + return () => { + document.removeEventListener("mousedown", onClickOutside); + document.removeEventListener("keydown", onKeyDown); + }; + }, [open]); + + async function openBusinessDashboard(event: MouseEvent<HTMLAnchorElement>) { + if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) { + return; + } + event.preventDefault(); + if (handoffBusy) return; + + const baseUrl = businessDashboardUrl; + const popup = window.open("about:blank", "_blank"); + setHandoffBusy(true); + try { + const token = getAccessToken(); + const res = await fetch("/api/auth/handoff", { + method: "POST", + headers: token ? { Authorization: `Bearer ${token}` } : undefined, + }); + if (!res.ok) throw new Error("handoff failed"); + const data = (await res.json()) as { ticket?: string }; + const url = new URL(baseUrl); + if (data.ticket) url.searchParams.set("handoff", data.ticket); + if (popup) { + popup.opener = null; + popup.location.replace(url.toString()); + } else { + window.open(url.toString(), "_blank", "noopener,noreferrer"); + } + } catch { + if (popup) popup.location.replace(baseUrl); + else window.open(baseUrl, "_blank", "noopener,noreferrer"); + } finally { + setHandoffBusy(false); + setOpen(false); + } + } + + if (!ready) { + return ( + <span className="account-menu account-menu--loading" aria-hidden> + <UserIcon /> + </span> + ); + } + + if (!isAuthenticated || !user) { + return ( + <a href={customerPortalUrl} className="account-menu account-menu--login" aria-label="ورود / ثبت‌نام"> + <UserIcon /> + <span>ورود / ثبت‌نام</span> + </a> + ); + } + + const displayName = userDisplayName(user); + + return ( + <div ref={menuRef} className="account-menu account-menu--user"> + <button + type="button" + onClick={() => setOpen((value) => !value)} + aria-expanded={open} + aria-haspopup="menu" + className="account-menu__trigger" + > + <UserIcon /> + <span className="account-menu__name">{displayName} عزیز</span> + <ChevronIcon open={open} /> + </button> + + {open ? ( + <div role="menu" className="account-menu__dropdown"> + <a + role="menuitem" + href={`${customerPortalUrl}/profile`} + className={itemClass} + onClick={() => setOpen(false)} + > + پروفایل من + </a> + {isWebsiteAdmin ? ( + <a + role="menuitem" + href={businessDashboardUrl} + className={itemClass} + onClick={openBusinessDashboard} + > + {handoffBusy ? "در حال انتقال…" : "مدیریت وبسایت"} + </a> + ) : null} + <button + type="button" + role="menuitem" + className={`${itemClass} account-menu__logout`} + onClick={() => { + setOpen(false); + logout(); + }} + > + خروج + </button> + </div> + ) : null} + </div> + ); +} diff --git a/src/components/ArticlesCarousel.tsx b/src/components/ArticlesCarousel.tsx new file mode 100644 index 0000000..01428b2 --- /dev/null +++ b/src/components/ArticlesCarousel.tsx @@ -0,0 +1,130 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { useEffect, useState, type CSSProperties } from "react"; + +import { articles } from "@/data/site"; +import { blogHref, blogImage, type BlogPost } from "@/lib/blog"; + +function Chevron({ direction }: { direction: "prev" | "next" }) { + return ( + <svg width="14" height="22" viewBox="0 0 14 22" fill="none" aria-hidden> + <path + d={direction === "prev" ? "M12 2L3 11l9 9" : "M2 2l9 9-9 9"} + stroke="currentColor" + strokeWidth="2.4" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + ); +} + +type CarouselItem = { + id: string; + title: string; + excerpt?: string | null; + image: string; + href: string; +}; + +function toCarouselItems(posts: BlogPost[]): CarouselItem[] { + return posts.map((post) => ({ + id: post.id, + title: post.title, + excerpt: post.abstract, + image: blogImage(post), + href: blogHref(post), + })); +} + +function staticCarouselItems(): CarouselItem[] { + return articles.map((item, index) => ({ + id: `static-${index}`, + title: item.title, + excerpt: item.excerpt, + image: item.image, + href: "/blog", + })); +} + +export default function ArticlesCarousel({ posts = [] }: { posts?: BlogPost[] }) { + const items = posts.length ? toCarouselItems(posts) : staticCarouselItems(); + const [index, setIndex] = useState(0); + const [perView, setPerView] = useState(4); + + useEffect(() => { + const update = () => { + const width = window.innerWidth; + if (width <= 575) setPerView(1); + else if (width <= 860) setPerView(2); + else setPerView(4); + }; + update(); + window.addEventListener("resize", update); + return () => window.removeEventListener("resize", update); + }, []); + + const maxIndex = Math.max(0, items.length - perView); + + useEffect(() => { + setIndex((current) => Math.min(current, maxIndex)); + }, [maxIndex]); + + useEffect(() => { + if (maxIndex === 0) return; + const id = window.setInterval(() => { + setIndex((current) => (current >= maxIndex ? 0 : current + 1)); + }, 3500); + return () => window.clearInterval(id); + }, [maxIndex]); + + function go(delta: number) { + setIndex((current) => { + const next = current + delta; + if (next < 0) return maxIndex; + if (next > maxIndex) return 0; + return next; + }); + } + + return ( + <div className="articles-carousel" style={{ "--per-view": perView } as CSSProperties}> + <div className="articles-carousel__viewport"> + <div + className="articles-carousel__track" + style={{ + transform: `translateX(${index * (100 / perView)}%)`, + }} + > + {items.map((item) => ( + <div key={item.id} className="articles-carousel__item"> + <Link href={item.href} className="media-card media-card--link"> + <div className="thumb"> + <Image src={item.image} alt={item.title} width={400} height={275} /> + </div> + <div className="body"> + <h3>{item.title}</h3> + {item.excerpt ? <p>{item.excerpt}</p> : null} + <div className="meta"> + <span>مشاهده بیشتر</span> + </div> + </div> + </Link> + </div> + ))} + </div> + </div> + + <div className="articles-carousel__controls" dir="ltr"> + <button type="button" aria-label="قبلی" onClick={() => go(-1)}> + <Chevron direction="prev" /> + </button> + <button type="button" aria-label="بعدی" onClick={() => go(1)}> + <Chevron direction="next" /> + </button> + </div> + </div> + ); +} diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx new file mode 100644 index 0000000..b6c5008 --- /dev/null +++ b/src/components/ContactForm.tsx @@ -0,0 +1,49 @@ +"use client"; + +import { FormEvent, useState } from "react"; + +export default function ContactForm() { + const [sent, setSent] = useState(false); + + function onSubmit(event: FormEvent<HTMLFormElement>) { + event.preventDefault(); + setSent(true); + } + + return ( + <form className="contact-form form-grid" onSubmit={onSubmit}> + <h2>برای ما پیام بفرستید</h2> + <p style={{ margin: 0, color: "#707070", fontSize: "0.9rem" }}> + با نظراتتون ما رو تو مسیر سلامتی کشور عزیزمون کمک کنید. + </p> + <label> + نام + <input name="name" type="text" placeholder="نام" required /> + </label> + <label> + موضوع + <input name="title" type="text" placeholder="موضوع" required /> + </label> + <label> + شماره همراه + <input name="cell_number" type="tel" placeholder="شماره همراه" required /> + </label> + <label> + ایمیل + <input name="email" type="email" placeholder="ایمیل" /> + </label> + <label> + متن پیام + <textarea name="message" placeholder="*متن پیام" required /> + </label> + <button type="submit" className="btn btn-primary"> + ارسال پیام + </button> + {sent ? ( + <p style={{ margin: 0, color: "var(--wb-mint)", fontWeight: 600 }}> + پیام شما ثبت شد. به‌زودی با بک‌اند متصل می‌شود. + </p> + ) : null} + </form> + ); +} diff --git a/src/components/EntityTabs.tsx b/src/components/EntityTabs.tsx new file mode 100644 index 0000000..08f224f --- /dev/null +++ b/src/components/EntityTabs.tsx @@ -0,0 +1,86 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { customerPortalUrl } from "@/lib/config"; +import type { CommentItem } from "@/lib/comments"; +import { formatFaDate } from "@/lib/format"; +import { useSession } from "@/lib/session"; + +export default function EntityTabs({ + descriptionHtml, + comments, + showDescription = true, +}: { + descriptionHtml?: string | null; + comments: CommentItem[]; + showDescription?: boolean; +}) { + const [tab, setTab] = useState<"description" | "comments">(showDescription ? "description" : "comments"); + const { isAuthenticated, ready } = useSession(); + + useEffect(() => { + if (!showDescription) setTab("comments"); + }, [showDescription]); + + return ( + <section className="entity-tabs"> + {showDescription ? ( + <div className="entity-tabs__nav"> + <button + type="button" + onClick={() => setTab("description")} + className={tab === "description" ? "active" : undefined} + > + توضیحات + </button> + <button + type="button" + onClick={() => setTab("comments")} + className={tab === "comments" ? "active" : undefined} + > + نظرات + </button> + </div> + ) : ( + <h2 className="entity-tabs__title">نظرات</h2> + )} + + {tab === "description" ? ( + descriptionHtml ? ( + <div className="rich-text entity-tabs__body" dangerouslySetInnerHTML={{ __html: descriptionHtml }} /> + ) : ( + <p className="entity-tabs__empty">توضیحاتی ثبت نشده است.</p> + ) + ) : ( + <div className="entity-tabs__body"> + {comments.length === 0 ? ( + <p className="entity-tabs__empty">نظری ثبت نشده است.</p> + ) : ( + <div className="comment-list"> + {comments.map((comment, index) => ( + <article key={comment.id ?? index} className="comment-item"> + <p className="comment-item__author">{comment.authorName || "کاربر"}</p> + {comment.createdAt ? ( + <p className="comment-item__date">{formatFaDate(comment.createdAt)}</p> + ) : null} + <p className="comment-item__text">{comment.text}</p> + </article> + ))} + </div> + )} + + {ready && !isAuthenticated ? ( + <div className="login-prompt"> + <p className="login-prompt__title">برای ثبت نظر وارد شوید</p> + <p className="login-prompt__text">نظرات فقط برای کاربران واردشده فعال است.</p> + <a href={customerPortalUrl} className="btn btn-primary"> + ورود / ثبت‌نام + </a> + </div> + ) : null} + </div> + )} + </section> + ); +} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..f10c205 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,86 @@ +import Image from "next/image"; +import Link from "next/link"; + +import SocialLinks from "@/components/SocialLinks"; +import { footerQuickLinks, site } from "@/data/site"; + +export default function Footer() { + return ( + <footer className="site-footer"> + <div className="footer-main"> + <div className="container footer-grid"> + <div> + <h3>{site.shortName}</h3> + <p>{site.description}</p> + <div style={{ marginTop: "1rem" }}> + <SocialLinks items={site.socials} /> + </div> + </div> + + <div> + <h3>آدرس ما</h3> + <ul className="footer-list"> + <li>{site.address}</li> + </ul> + </div> + + <div> + <h3>تماس با ما</h3> + <ul className="footer-list"> + {site.phones.map((phone) => ( + <li key={phone}> + <a href={`tel:${phone.replace(/-/g, "")}`}>{phone}</a> + </li> + ))} + </ul> + </div> + + <div> + <h3>دسترسی سریع</h3> + <ul className="footer-list"> + {footerQuickLinks.map((link) => ( + <li key={link.label}> + <Link href={link.href}>{link.label}</Link> + </li> + ))} + </ul> + <h3 style={{ marginTop: "1.25rem" }}>ما را در اینجا بیابید (:</h3> + </div> + </div> + </div> + + <div className="footer-bottom"> + <div className="container"> + <div className="footer-bottom-bar"> + <div className="footer-bottom-site">{site.shortName}</div> + <a + href="https://meshkee.com" + target="_blank" + rel="noopener noreferrer" + dir="ltr" + className="meshkee-credit" + > + <span className="meshkee-credit__frame" aria-hidden> + <span className="meshkee-credit__line meshkee-credit__line--l" /> + <span className="meshkee-credit__line meshkee-credit__line--t" /> + <span className="meshkee-credit__line meshkee-credit__line--r" /> + <span className="meshkee-credit__line meshkee-credit__line--b" /> + </span> + <Image + src="/images/footer/MeshkeeLogo-White.png" + alt="Meshkee" + className="meshkee-credit__logo" + width={42} + height={42} + /> + <span className="meshkee-credit__text"> + <span className="meshkee-credit__label">Designed And Developed By</span> + <span className="meshkee-credit__name">Meshkee E-Commerce Team</span> + </span> + </a> + </div> + </div> + </div> + </footer> + ); +} diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 0000000..d7e0aa8 --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,87 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { useState } from "react"; + +import SocialLinks from "@/components/SocialLinks"; +import AccountMenu from "@/components/AccountMenu"; +import { navLinks, site } from "@/data/site"; + +export default function Header() { + const pathname = usePathname(); + const [open, setOpen] = useState(false); + + return ( + <> + <div className="topbar"> + <div className="container topbar-inner"> + <div className="topbar-meta"> + <a href={`tel:${site.phone.replace(/-/g, "")}`}>{site.phone}</a> + <span>{site.hours}</span> + </div> + <div className="topbar-actions"> + <SocialLinks items={site.socials} /> + <AccountMenu /> + </div> + </div> + </div> + + <header className="site-header"> + <div className="container header-brand"> + <Link href="/" className="logo-link" aria-label={site.name}> + <Image src="/images/logo/clinic-logo.png" alt={site.name} width={180} height={72} priority /> + </Link> + <div className="brand-copy"> + {pathname === "/" ? ( + <h1>{site.name}</h1> + ) : ( + <p className="brand-title">{site.name}</p> + )} + <p>{site.tagline}</p> + <button + type="button" + className="nav-toggle" + aria-label="منو" + aria-expanded={open} + onClick={() => setOpen((v) => !v)} + style={{ marginTop: "0.65rem" }} + > + منو + </button> + </div> + <div className="org-logo"> + <Image + src="/images/logo/org-logo.png" + alt="سازمان نظام روانشناسی" + width={72} + height={72} + /> + </div> + </div> + + <nav className={`main-nav${open ? " open" : ""}`}> + <div className="container"> + <ul> + {navLinks.map((link) => { + const active = link.href === "/" ? pathname === "/" : pathname.startsWith(link.href); + return ( + <li key={link.href}> + <Link + href={link.href} + className={active ? "active" : undefined} + onClick={() => setOpen(false)} + > + {link.label} + </Link> + </li> + ); + })} + </ul> + </div> + </nav> + </header> + </> + ); +} diff --git a/src/components/HeroSlider.tsx b/src/components/HeroSlider.tsx new file mode 100644 index 0000000..d910f5a --- /dev/null +++ b/src/components/HeroSlider.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import SlotImage from "@/components/SlotImage"; +import SlotLink from "@/components/SlotLink"; +import { parseAspectRatio, type SlotMediaItem } from "@/lib/static-images"; + +function Chevron({ direction }: { direction: "prev" | "next" }) { + return ( + <svg width="14" height="22" viewBox="0 0 14 22" fill="none" aria-hidden> + <path + d={direction === "prev" ? "M12 2L3 11l9 9" : "M2 2l9 9-9 9"} + stroke="currentColor" + strokeWidth="2.4" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + ); +} + +export default function HeroSlider({ + slides, + aspectRatio, +}: { + slides: SlotMediaItem[]; + aspectRatio?: string; +}) { + const [index, setIndex] = useState(0); + const ratio = parseAspectRatio(aspectRatio) ?? "1920 / 740"; + + useEffect(() => { + setIndex(0); + }, [slides.length]); + + useEffect(() => { + if (slides.length < 2) return; + const id = window.setInterval(() => { + setIndex((current) => (current + 1) % slides.length); + }, 5500); + return () => window.clearInterval(id); + }, [slides.length]); + + if (!slides.length) return null; + + return ( + <section className="hero"> + <div className="container"> + <div className="hero-frame" style={{ aspectRatio: ratio }}> + {slides.map((slide, i) => ( + <div key={slide.id} className={`hero-slide${i === index ? " active" : ""}`}> + <SlotLink href={slide.href} className="hero-slide-link"> + <SlotImage + src={slide.image} + fallbackSrc={slide.fallbackSrc} + alt={slide.title || slide.kicker || ""} + fill + priority={i === 0} + sizes="(max-width: 1200px) 100vw, 1180px" + /> + </SlotLink> + </div> + ))} + + {slides.length > 1 ? ( + <> + <div className="hero-controls"> + <button + type="button" + aria-label="اسلاید قبلی" + onClick={() => setIndex((i) => (i - 1 + slides.length) % slides.length)} + > + <Chevron direction="prev" /> + </button> + <button + type="button" + aria-label="اسلاید بعدی" + onClick={() => setIndex((i) => (i + 1) % slides.length)} + > + <Chevron direction="next" /> + </button> + </div> + + <div className="hero-dots"> + {slides.map((slide, i) => ( + <button + key={slide.id} + type="button" + aria-label={`اسلاید ${i + 1}`} + className={i === index ? "active" : undefined} + onClick={() => setIndex(i)} + /> + ))} + </div> + </> + ) : null} + </div> + </div> + </section> + ); +} diff --git a/src/components/HomeSections.tsx b/src/components/HomeSections.tsx new file mode 100644 index 0000000..49f5de0 --- /dev/null +++ b/src/components/HomeSections.tsx @@ -0,0 +1,208 @@ +import Link from "next/link"; + +import ArticlesCarousel from "@/components/ArticlesCarousel"; +import SlotImage from "@/components/SlotImage"; +import SlotLink from "@/components/SlotLink"; +import TestimonialsCarousel from "@/components/TestimonialsCarousel"; +import { consultModes, stats } from "@/data/site"; +import type { BlogPost } from "@/lib/blog"; +import { parseAspectRatio, type SlotMediaItem } from "@/lib/static-images"; +import type { Workshop } from "@/lib/workshops"; +import { workshopHref, workshopImage } from "@/lib/workshops"; + +type Props = { + people: SlotMediaItem[]; + peopleAspectRatio?: string; + serviceIcons: SlotMediaItem[]; + serviceIconsAspectRatio?: string; + banners: SlotMediaItem[]; + bannersAspectRatio?: string; + workshops: Workshop[]; + articles: BlogPost[]; +}; + +export default function HomeSections({ + people, + peopleAspectRatio, + serviceIcons, + serviceIconsAspectRatio, + banners, + bannersAspectRatio, + workshops, + articles, +}: Props) { + const peopleRatio = parseAspectRatio(peopleAspectRatio) ?? "325 / 356"; + const iconRatio = parseAspectRatio(serviceIconsAspectRatio) ?? "1 / 1"; + const bannerRatio = parseAspectRatio(bannersAspectRatio) ?? "540 / 312"; + + return ( + <> + <section className="section"> + <div className="container"> + <div className="section-head"> + <h2>مشاوران کلینیک روانشناسی ثامن</h2> + <p>جهت رزرو نوبت مشاوره تماس بگیرید</p> + </div> + <div className="therapist-grid"> + {people.map((item) => ( + <SlotLink key={item.id} href={item.href || "/ourdr"} className="therapist-card"> + <div className="photo" style={{ aspectRatio: peopleRatio }}> + <SlotImage + src={item.image} + fallbackSrc={item.fallbackSrc} + alt={item.title || ""} + width={325} + height={356} + /> + </div> + {item.title ? <h3>{item.title}</h3> : null} + {item.text ? <p>{item.text}</p> : null} + </SlotLink> + ))} + </div> + </div> + </section> + + <section id="workshops" className="section section-muted"> + <div className="container"> + <div className="section-head"> + <h2>کارگاه‌های تخصصی</h2> + <p>کارگاه‌های در حال ثبت‌نام کلینیک ثامن</p> + </div> + <div className="card-grid"> + {workshops.map((item) => ( + <Link key={item.id} href={workshopHref(item)} className="media-card media-card--link"> + <div className="thumb"> + <SlotImage src={workshopImage(item)} alt={item.title} width={400} height={275} /> + </div> + <div className="body"> + {item.tag ? <span className="tag">{item.tag}</span> : null} + <h3>{item.title}</h3> + <div className="meta"> + <span>{item.status || "در حال ثبت نام"}</span> + <span>جزئیات رویداد</span> + </div> + </div> + </Link> + ))} + </div> + <div className="section-cta"> + <Link href="/workshops" className="btn btn-outline"> + مشاهده همه کارگاه‌ها + </Link> + </div> + </div> + </section> + + <section className="section"> + <div className="container consult-row"> + <div className="consult-modes"> + {consultModes.map((item) => ( + <div key={item.title} className="consult-item"> + <SlotImage src={item.image} alt={item.title} width={52} height={52} /> + <h3>{item.title}</h3> + <p className="latin">{item.english}</p> + </div> + ))} + </div> + <Link href="/about" className="about-cta"> + <SlotImage + src="/images/about/about-banner.png" + alt="درباره کلینیک ثامن" + fill + sizes="480px" + /> + <div className="content"> + <h3>درباره ما بیشتر بدانید</h3> + <span className="btn btn-light">مشاهده درباره ما</span> + </div> + </Link> + </div> + </section> + + <section id="services" className="section section-muted"> + <div className="container"> + <div className="section-head"> + <h2>خدمات کلینیک ثامن</h2> + <p>مشاوره تخصصی در حوزه‌های فردی، خانواده، ازدواج و تحصیل</p> + </div> + <div className="service-grid"> + {serviceIcons.map((item) => ( + <SlotLink key={item.id} href={item.href || "/#services"} className="service-card"> + <div className="service-icon" style={{ aspectRatio: iconRatio }}> + <SlotImage + src={item.image} + fallbackSrc={item.fallbackSrc} + alt={item.title || ""} + width={110} + height={110} + /> + </div> + {item.title ? <h3>{item.title}</h3> : null} + {item.kicker ? <p className="latin">{item.kicker}</p> : null} + </SlotLink> + ))} + </div> + + <div className="banner-row" style={{ marginTop: "1.5rem" }}> + {banners.map((item, index) => ( + <div key={item.id} className="promo-banner" style={{ aspectRatio: bannerRatio }}> + <SlotImage + src={item.image} + fallbackSrc={item.fallbackSrc} + alt={item.title || ""} + fill + sizes="560px" + /> + <div className="shade" /> + <div className="content"> + {item.title ? <h3>{item.title}</h3> : null} + <SlotLink + href={item.href || (index === 0 ? "/workshops" : "/contact")} + className="btn btn-outline" + > + {index === 0 ? "مشاهده بیشتر" : "رزرو نوبت"} + </SlotLink> + </div> + </div> + ))} + </div> + </div> + </section> + + <section id="articles" className="section"> + <div className="container"> + <div className="section-head"> + <h2>مقالات</h2> + <p>آخرین مطالب آموزشی کلینیک ثامن</p> + </div> + <ArticlesCarousel posts={articles} /> + <div className="section-cta"> + <Link href="/blog" className="btn btn-outline"> + مشاهده همه مقالات + </Link> + </div> + </div> + </section> + + <section className="section section-muted"> + <div className="container"> + <div className="section-head"> + <h2>نظرات کاربران</h2> + </div> + <TestimonialsCarousel /> + + <div className="stats-grid"> + {stats.map((item) => ( + <div key={item.label} className="stat-item"> + <strong>{item.value}</strong> + <span>{item.label}</span> + <span className="latin">{item.english}</span> + </div> + ))} + </div> + </div> + </section> + </> + ); +} diff --git a/src/components/PageHero.tsx b/src/components/PageHero.tsx new file mode 100644 index 0000000..386295f --- /dev/null +++ b/src/components/PageHero.tsx @@ -0,0 +1,26 @@ +import Image from "next/image"; + +type Props = { + title: string; + subtitle?: string; + image?: string; +}; + +export default function PageHero({ title, subtitle, image }: Props) { + return ( + <section className="page-hero"> + <div className="container page-hero__inner"> + <div> + <p className="page-hero__kicker latin">Clinic Samen</p> + <h1>{title}</h1> + {subtitle ? <p>{subtitle}</p> : null} + </div> + {image ? ( + <div className="page-hero__image"> + <Image src={image} alt={title} width={420} height={260} /> + </div> + ) : null} + </div> + </section> + ); +} diff --git a/src/components/Providers.tsx b/src/components/Providers.tsx new file mode 100644 index 0000000..abe0ebe --- /dev/null +++ b/src/components/Providers.tsx @@ -0,0 +1,13 @@ +"use client"; + +import { SessionProvider } from "@/lib/session"; + +export default function Providers({ + businessId, + children, +}: { + businessId: string; + children: React.ReactNode; +}) { + return <SessionProvider businessId={businessId}>{children}</SessionProvider>; +} diff --git a/src/components/SlotImage.tsx b/src/components/SlotImage.tsx new file mode 100644 index 0000000..86ed599 --- /dev/null +++ b/src/components/SlotImage.tsx @@ -0,0 +1,88 @@ +import Image from "next/image"; +import type { CSSProperties } from "react"; + +type Props = { + src: string; + alt: string; + width?: number; + height?: number; + fill?: boolean; + className?: string; + sizes?: string; + priority?: boolean; + style?: CSSProperties; + fallbackSrc?: string; +}; + +function isRemote(src: string) { + return /^https?:\/\//i.test(src); +} + +export default function SlotImage({ + src, + alt, + width, + height, + fill, + className, + sizes, + priority, + style, + fallbackSrc, +}: Props) { + const resolved = src || fallbackSrc || ""; + if (!resolved) return null; + + if (isRemote(resolved)) { + if (fill) { + return ( + // eslint-disable-next-line @next/next/no-img-element + <img + src={resolved} + alt={alt} + className={className} + style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", ...style }} + /> + ); + } + + return ( + // eslint-disable-next-line @next/next/no-img-element + <img + src={resolved} + alt={alt} + width={width} + height={height} + className={className} + style={style} + /> + ); + } + + if (fill) { + return ( + <Image + src={resolved} + alt={alt} + fill + className={className} + sizes={sizes} + priority={priority} + style={style} + /> + ); + } + + return ( + <Image + src={resolved} + alt={alt} + width={width ?? 800} + height={height ?? 600} + className={className} + sizes={sizes} + priority={priority} + style={style} + /> + ); +} diff --git a/src/components/SlotLink.tsx b/src/components/SlotLink.tsx new file mode 100644 index 0000000..e92f116 --- /dev/null +++ b/src/components/SlotLink.tsx @@ -0,0 +1,32 @@ +import Link from "next/link"; +import type { ReactNode } from "react"; + +function isExternal(href: string) { + return /^https?:\/\//i.test(href) || href.startsWith("//"); +} + +export default function SlotLink({ + href, + className, + children, +}: { + href?: string; + className?: string; + children: ReactNode; +}) { + if (!href) return <>{children}</>; + + if (isExternal(href)) { + return ( + <a href={href} className={className} target="_blank" rel="noopener noreferrer"> + {children} + </a> + ); + } + + return ( + <Link href={href} className={className}> + {children} + </Link> + ); +} diff --git a/src/components/SocialLinks.tsx b/src/components/SocialLinks.tsx new file mode 100644 index 0000000..a202e56 --- /dev/null +++ b/src/components/SocialLinks.tsx @@ -0,0 +1,60 @@ +type Social = { + name: string; + href: string; + label: string; +}; + +function SocialIcon({ name }: { name: string }) { + const common = { + width: 14, + height: 14, + viewBox: "0 0 24 24", + fill: "currentColor", + "aria-hidden": true as const, + }; + + switch (name) { + case "instagram": + return ( + <svg {...common}> + <path d="M7 2h10a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H7a5 5 0 0 1-5-5V7a5 5 0 0 1 5-5zm5 5a5 5 0 1 0 0 10 5 5 0 0 0 0-10zm6.5-.9a1.1 1.1 0 1 0 0 2.2 1.1 1.1 0 0 0 0-2.2z" /> + </svg> + ); + case "whatsapp": + return ( + <svg {...common}> + <path d="M12.04 2C6.58 2 2.15 6.4 2.15 11.84c0 1.96.52 3.8 1.44 5.4L2 22l4.92-1.53a9.86 9.86 0 0 0 5.12 1.4c5.46 0 9.89-4.4 9.89-9.84S17.5 2 12.04 2zm5.74 14.07c-.24.68-1.4 1.25-1.94 1.33-.5.07-1.12.1-1.81-.11-.42-.13-.95-.31-1.64-.6-2.89-1.25-4.77-4.16-4.92-4.35-.14-.2-1.2-1.6-1.2-3.05s.76-2.16 1.03-2.46c.26-.29.57-.37.76-.37h.55c.17 0 .4-.07.63.48.24.57.81 1.98.88 2.12.07.14.12.31.02.5-.1.2-.15.31-.3.48-.14.17-.3.37-.43.5-.14.14-.29.29-.12.57.17.29.75 1.23 1.61 2 .111.1.2.08 1.55.69.18.08.33.07.46-.08.12-.14.55-.64.7-.86.14-.22.29-.18.48-.11.2.07 1.24.58 1.45.69.22.1.36.15.41.24.06.08.06.48-.18 1.16z" /> + </svg> + ); + case "telegram": + return ( + <svg {...common}> + <path d="M9.78 14.65 9.5 18.5c.4 0 .57-.17.78-.37l1.87-1.79 3.88 2.84c.71.39 1.22.19 1.41-.66l2.56-12.03h.01c.23-1.06-.38-1.48-1.07-1.22L3.3 10.2c-1.03.4-1.01.97-.18 1.23l4.05 1.26 9.4-5.92c.44-.27.85-.12.52.15L9.78 14.65z" /> + </svg> + ); + default: + return ( + <svg {...common}> + <path d="M12 2a10 10 0 1 0 .001 20.001A10 10 0 0 0 12 2zm1 14.93V13h3l.5-3H13V8.5c0-.87.28-1.5 1.55-1.5H16V4.14C15.66 4.1 14.77 4 13.74 4 11.48 4 10 5.35 10 7.92V10H7v3h3v3.93A8.03 8.03 0 0 0 13 16.93z" /> + </svg> + ); + } +} + +export default function SocialLinks({ + items, + className = "social-row", +}: { + items: readonly Social[]; + className?: string; +}) { + return ( + <div className={className}> + {items.map((item) => ( + <a key={item.name} href={item.href} target="_blank" rel="noopener noreferrer" title={item.label}> + <SocialIcon name={item.name} /> + </a> + ))} + </div> + ); +} diff --git a/src/components/TestimonialsCarousel.tsx b/src/components/TestimonialsCarousel.tsx new file mode 100644 index 0000000..3b990f9 --- /dev/null +++ b/src/components/TestimonialsCarousel.tsx @@ -0,0 +1,86 @@ +"use client"; + +import { useEffect, useState, type CSSProperties } from "react"; + +import { testimonials } from "@/data/site"; + +function Chevron({ direction }: { direction: "prev" | "next" }) { + return ( + <svg width="14" height="22" viewBox="0 0 14 22" fill="none" aria-hidden> + <path + d={direction === "prev" ? "M12 2L3 11l9 9" : "M2 2l9 9-9 9"} + stroke="currentColor" + strokeWidth="2.4" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + ); +} + +export default function TestimonialsCarousel() { + const [index, setIndex] = useState(0); + const [perView, setPerView] = useState(2); + + useEffect(() => { + const update = () => { + setPerView(window.innerWidth <= 860 ? 1 : 2); + }; + update(); + window.addEventListener("resize", update); + return () => window.removeEventListener("resize", update); + }, []); + + const maxIndex = Math.max(0, testimonials.length - perView); + + useEffect(() => { + setIndex((current) => Math.min(current, maxIndex)); + }, [maxIndex]); + + useEffect(() => { + if (maxIndex === 0) return; + const id = window.setInterval(() => { + setIndex((current) => (current >= maxIndex ? 0 : current + 1)); + }, 4000); + return () => window.clearInterval(id); + }, [maxIndex]); + + function go(delta: number) { + setIndex((current) => { + const next = current + delta; + if (next < 0) return maxIndex; + if (next > maxIndex) return 0; + return next; + }); + } + + return ( + <div className="testimonials-carousel" style={{ "--per-view": perView } as CSSProperties}> + <div className="testimonials-carousel__viewport"> + <div + className="testimonials-carousel__track" + style={{ transform: `translateX(${index * (100 / perView)}%)` }} + > + {testimonials.map((item) => ( + <div key={`${item.name}-${item.date}`} className="testimonials-carousel__item"> + <blockquote className="testimonial"> + <div className="name">{item.name}</div> + <h5>{item.text}</h5> + <div className="date">{item.date}</div> + </blockquote> + </div> + ))} + </div> + + <div className="testimonials-carousel__controls"> + <button type="button" aria-label="قبلی" onClick={() => go(-1)}> + <Chevron direction="prev" /> + </button> + <button type="button" aria-label="بعدی" onClick={() => go(1)}> + <Chevron direction="next" /> + </button> + </div> + </div> + </div> + ); +} diff --git a/src/components/WorkshopGallery.tsx b/src/components/WorkshopGallery.tsx new file mode 100644 index 0000000..d4358c3 --- /dev/null +++ b/src/components/WorkshopGallery.tsx @@ -0,0 +1,127 @@ +"use client"; + +import Image from "next/image"; +import { useCallback, useEffect, useState } from "react"; + +export default function WorkshopGallery({ images, alt }: { images: string[]; alt: string }) { + const gallery = images.length ? images : ["/images/blog/post-1.jpg"]; + const [active, setActive] = useState(0); + const [lightbox, setLightbox] = useState(false); + const [origin, setOrigin] = useState("50% 50%"); + const [zoomed, setZoomed] = useState(false); + const current = gallery[active] ?? gallery[0]; + + const close = useCallback(() => setLightbox(false), []); + const step = useCallback( + (delta: number) => setActive((index) => (index + delta + gallery.length) % gallery.length), + [gallery.length], + ); + + useEffect(() => { + if (!lightbox) return; + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") close(); + if (event.key === "ArrowLeft") step(1); + if (event.key === "ArrowRight") step(-1); + }; + document.addEventListener("keydown", onKeyDown); + const previousOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + return () => { + document.removeEventListener("keydown", onKeyDown); + document.body.style.overflow = previousOverflow; + }; + }, [lightbox, close, step]); + + return ( + <> + <div className="workshop-gallery"> + <button + type="button" + className="workshop-gallery__main" + onClick={() => setLightbox(true)} + onMouseEnter={() => setZoomed(true)} + onMouseLeave={() => { + setZoomed(false); + setOrigin("50% 50%"); + }} + onMouseMove={(event) => { + const box = event.currentTarget.getBoundingClientRect(); + const x = ((event.clientX - box.left) / box.width) * 100; + const y = ((event.clientY - box.top) / box.height) * 100; + setOrigin(`${x}% ${y}%`); + }} + aria-label={`نمایش بزرگ ${alt}`} + > + <Image src={current} alt={alt} fill sizes="(max-width: 860px) 100vw, 640px" className="workshop-gallery__image" /> + <span + className="workshop-gallery__zoom" + style={{ + backgroundImage: `url(${current})`, + transform: zoomed ? "scale(1.85)" : "scale(1)", + transformOrigin: origin, + opacity: zoomed ? 1 : 0, + }} + /> + </button> + + {gallery.length > 1 ? ( + <div className="workshop-gallery__thumbs"> + {gallery.map((image, index) => ( + <button + key={`${image}-${index}`} + type="button" + onClick={() => setActive(index)} + className={index === active ? "active" : undefined} + aria-label={`تصویر ${index + 1}`} + > + <Image src={image} alt="" width={72} height={72} /> + </button> + ))} + </div> + ) : null} + </div> + + {lightbox ? ( + <div className="lightbox" role="dialog" aria-modal="true" aria-label={alt} onClick={close}> + <button type="button" className="lightbox__close" onClick={close} aria-label="بستن"> + ✕ + </button> + {gallery.length > 1 ? ( + <> + <button + type="button" + className="lightbox__nav lightbox__nav--prev" + onClick={(event) => { + event.stopPropagation(); + step(-1); + }} + aria-label="تصویر قبلی" + > + ‹ + </button> + <button + type="button" + className="lightbox__nav lightbox__nav--next" + onClick={(event) => { + event.stopPropagation(); + step(1); + }} + aria-label="تصویر بعدی" + > + › + </button> + </> + ) : null} + <figure className="lightbox__figure" onClick={(event) => event.stopPropagation()}> + {/* eslint-disable-next-line @next/next/no-img-element */} + <img src={current} alt={alt} /> + <figcaption> + {active + 1} / {gallery.length} + </figcaption> + </figure> + </div> + ) : null} + </> + ); +} diff --git a/src/components/WorkshopRegistration.tsx b/src/components/WorkshopRegistration.tsx new file mode 100644 index 0000000..ba03211 --- /dev/null +++ b/src/components/WorkshopRegistration.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { useState } from "react"; + +import { customerPortalUrl } from "@/lib/config"; +import { formatFaDate } from "@/lib/format"; +import { useSession } from "@/lib/session"; + +type Props = { + workshopId: string; + eventDate?: string | null; + eventTime?: string | null; + duration?: string | null; + status?: string | null; +}; + +export default function WorkshopRegistration({ + workshopId, + eventDate, + eventTime, + duration, + status, +}: Props) { + const { isAuthenticated, ready, getAccessToken } = useSession(); + const [busy, setBusy] = useState(false); + const [message, setMessage] = useState<string | null>(null); + const [error, setError] = useState<string | null>(null); + + async function register() { + const token = getAccessToken(); + if (!token) return; + + setBusy(true); + setMessage(null); + setError(null); + try { + const res = await fetch(`/api/workshops/${encodeURIComponent(workshopId)}/register`, { + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + }); + const data = (await res.json()) as { message?: string; error?: string }; + if (!res.ok) { + setError(data.error ?? data.message ?? "ثبت‌نام انجام نشد."); + return; + } + setMessage(data.message ?? "ثبت‌نام شما با موفقیت انجام شد."); + } catch { + setError("خطا در ارتباط با سرور."); + } finally { + setBusy(false); + } + } + + return ( + <section className="workshop-registration"> + <div className="workshop-registration__meta"> + {eventDate ? ( + <div> + <span>تاریخ برگزاری</span> + <strong>{formatFaDate(eventDate)}</strong> + </div> + ) : null} + {eventTime ? ( + <div> + <span>ساعت</span> + <strong>{eventTime}</strong> + </div> + ) : null} + {duration ? ( + <div> + <span>مدت</span> + <strong>{duration}</strong> + </div> + ) : null} + {status ? ( + <div> + <span>وضعیت</span> + <strong>{status}</strong> + </div> + ) : null} + </div> + + <div className="workshop-registration__action"> + {!ready ? null : isAuthenticated ? ( + <> + <button type="button" className="btn btn-primary" disabled={busy} onClick={register}> + {busy ? "در حال ثبت‌نام…" : "ثبت‌نام در کارگاه"} + </button> + {message ? <p className="workshop-registration__success">{message}</p> : null} + {error ? <p className="workshop-registration__error">{error}</p> : null} + </> + ) : ( + <div className="login-prompt login-prompt--inline"> + <p className="login-prompt__title">برای ثبت‌نام در کارگاه وارد شوید</p> + <a href={customerPortalUrl} className="btn btn-primary"> + ورود / ثبت‌نام + </a> + </div> + )} + </div> + </section> + ); +} diff --git a/src/data/site.ts b/src/data/site.ts new file mode 100644 index 0000000..2699632 --- /dev/null +++ b/src/data/site.ts @@ -0,0 +1,338 @@ +export const site = { + name: "کلینیک روانشناسی و مرکز مشاوره ثامن", + shortName: "کلینیک ثامن", + tagline: "با مجوز رسمی از سازمان نظام روانشناسی و مشاوره کشور (ش‌ثبت 654-م) تاسیس 1395", + description: + "کلینیک روانشناسی ثامن اولین مرکز رواندرمانی با رویکرد مزاج در کشور", + phone: "025-32706211", + phones: ["025-32706211", "025-32702623", "09936221511"], + hours: "ساعت کاری : ۹ صبح الی ۹ شب", + address: "بنیاد - میدان جوان - بلوار آفرینش - خیابان ذوالفقار - نبش کوچه ۳", + mapEmbed: + "https://www.openstreetmap.org/export/embed.html?bbox=50.873002409935%2C34.59505879609959%2C50.877481698989875%2C34.596988526468955&layer=mapnik&marker=34.59602366688795%2C50.87524205446243", + socials: [ + { name: "instagram", href: "https://instagram.com/Psy.samen", label: "اینستاگرام" }, + { name: "whatsapp", href: "https://wa.me/989195362393", label: "واتساپ" }, + { name: "telegram", href: "https://t.me/clinicsamen", label: "تلگرام" }, + { name: "eitaa", href: "https://eitaa.com/psysamen", label: "ایتا" }, + ], +} as const; + +export const navLinks = [ + { href: "/", label: "صفحه اصلی" }, + { href: "/ourdr", label: "درمانگران" }, + { href: "/#services", label: "خدمات" }, + { href: "/workshops", label: "کارگاه‌ها" }, + { href: "/blog", label: "مقالات" }, + { href: "/about", label: "درباره ما" }, + { href: "/contact", label: "تماس با ما" }, +] as const; + +export const footerQuickLinks = [ + { href: "/about", label: "مشاوره کودک قم" }, + { href: "/about", label: "مشاوره ازدواج قم" }, + { href: "/about", label: "مشاوره فردی قم" }, +] as const; + +export const slides = [ + { + image: "/images/slider/slide-1.jpg", + title: "کارگاه عمومی", + english: "WORK PUBLIC", + alt: "کلینیک روانشناسی ثامن", + }, + { + image: "/images/slider/slide-2.jpg", + title: "مشاوره ازدواج", + english: "MARRIAGE", + alt: "مشاوره ازدواج قم", + }, + { + image: "/images/slider/slide-3.jpg", + title: "مشاوره خانواده", + english: "FAMILY", + alt: "مشاوره خانواده", + }, + { + image: "/images/slider/slide-4.jpg", + title: "کلینیک ثامن", + english: "SAMEN CLINIC", + alt: "کلینیک روانشناسی ثامن", + }, +] as const; + +export const homeTherapists = [ + { + name: "دکتر سید علیرضا سیفی", + role: "مدیرعامل و موسس کلینیک ثامن", + image: "/images/therapists/home-seifi.webp", + }, + { + name: "دکتر ابوالفضل رشیدی", + role: "دکترای روانشناسی دانشگاه تهران", + image: "/images/therapists/home-rashidi.jpg", + }, + { + name: "دکتر سیده زهرا هدایی نیا", + role: "دکترای روانشناسی سلامت و مدرس دانشگاه", + image: "/images/therapists/hodaeinia.jpg", + }, + { + name: "دکتر محبوبه شاهسوار", + role: "دکتری روانشناسی عمومی", + image: "/images/therapists/home-shahsavar.jpg", + }, +] as const; + +export const therapists = [ + { + name: "دکتر سیدعلیرضا سیفی", + image: "/images/therapists/seifi.webp", + bio: "مدیر عامل و موسس کلینیک روانشناسی و مشاوره ثامن تاسیس ۱۳۹۵ — مدیرعامل و موسس کلینیک تخصصی ازدواج و تحکیم خانواده ثنامهر تاسیس ۱۴۰۱ — کد پروانه اشتغال سازمان نظام روانشناسی ج.ا.ا ۶۹۱۴ — عضو انجمن روانشناسی آمریکا APA — بازرس و مدیر کمیته آموزش سازمان نظام روانشناسی در قم در سال ۱۴۰۳ — مسئول کانون مشاوره و مددکاری آستان قدس رضوی در قم — دکترای روانشناسی سلامت دانشگاه تهران — دکترای الهیات و فلسفه (حوزوی) — دکترای طب سنتی از ارمنستان — کارشناسی ارشد روانشناسی مثبت‌گرا — مدرس دانشگاه. حوزه‌های تخصص: شخصیت‌شناسی و مزاج‌شناسی، مشاوره پیش از ازدواج و طلاق، سکس‌تراپی، زوج‌درمانی، مشاوره مذهبی و معنوی، افسردگی و اضطراب.", + }, + { + name: "دکتر محمدرضا احمدی", + image: "/images/therapists/ahmadi.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۴۷۹ — دکترای روانشناسی تربیتی — عضو هیات علمی دانشگاه و حوزه — حوزه تخصصی روانشناسی رشد و تحول و روش تحقیق — استاد راهنمای دانشجویان روانشناسی — سردبیر چهار مجله تخصصی روانشناسی.", + }, + { + name: "دکتر سیده زهرا هدایی نیا", + image: "/images/therapists/hodaeinia.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۴۲۳۴۵۳ — دکترای روانشناسی سلامت — هیات علمی دانشگاه اراک — مدرس دانشگاه — دانش‌آموخته دکتر نیما قربانی و دکتر علیرضا طهماسب — روانکاو و درمانگر اختلالات بالینی افسردگی، اضطراب، وسواس و شخصیت با رویکرد روان‌پویشی کوتاه‌مدت (ISTDP).", + }, + { + name: "دکتر ابوالفضل رشیدی", + image: "/images/therapists/rashidi.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۴۵۸۳ — دکتری روانشناسی و آموزش کودکان استثنایی دانشگاه تهران — رتبه ۲ دانشگاه تهران — درمانگر اختلالات کودک و نوجوان (یادگیری، اضطراب، بیش‌فعالی و ...).", + }, + { + name: "حسین شریفی", + image: "/images/therapists/sharifi.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۳۳۴۵۱ — هیات علمی دانشگاه — دکترای الهیات و معارف — کارشناسی ارشد مشاوره — زوج‌درمانی، ازدواج و طلاق، مشاوره فردی.", + }, + { + name: "دکتر محبوبه شاهسوار", + image: "/images/therapists/shahsavar.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۳۷۱۲ — دکتری روانشناسی عمومی — مشاوره پیش از ازدواج — زوج‌درمانگر — مشاوره فردی.", + }, + { + name: "دکتر بهاره احدی نیا", + image: "/images/therapists/ahadinia.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۳۳۰۶۸ — دانشجوی دکترای مشاوره دانشگاه تهران — کارشناسی ارشد روان‌شناسی بالینی — مشاوره بالینی کودک و نوجوان — استعدادسنجی کودک — مدرس کارگاه‌های کودک و نوجوان.", + }, + { + name: "دکتر معصومه سادات رهنمایی", + image: "/images/therapists/rahnamaei.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۴۹۹۰۸۳ — دکترای روانشناسی سلامت دانشگاه تهران — روانشناسی فردی — اختلالات اضطراب، وسواس و افسردگی.", + }, + { + name: "رسول نادری", + image: "/images/therapists/naderi.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۵۵۹۴۸۴ — کارشناسی ارشد روانشناسی اسلامی گرایش مثبت‌گرا — ازدواج، خانواده، افسردگی، اضطراب، وسواس و اختلالات شخصیت — مشاوره مذهبی و آسیب‌های اجتماعی.", + }, + { + name: "جمشید احمد نژاد", + image: "/images/therapists/ahmadnezhad.jpg", + bio: "کارشناسی ارشد علوم تربیتی — مشاور تحصیلی و انتخاب رشته تخصصی — مدرس کارگاه‌های تحصیلی، خانواده و ازدواج.", + }, + { + name: "محمد باقر ساعدی", + image: "/images/therapists/saedi.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۴۴۲۲۲ — کارشناسی ارشد روانشناسی شخصیت — روان‌درمانگر پویشی ISTDP — درمان مشکلات فردی، اضطراب، افسردگی، مداخله در خیانت.", + }, + { + name: "زینب معینی پور", + image: "/images/therapists/moeini.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۲۹۴۴۹ — کارشناسی ارشد روان‌شناسی شخصیت — مشاوره فردی و اختلالات روانشناختی — درمانگر اضطراب، خانواده و زوج‌درمانگر.", + }, + { + name: "فائزه سادات سبطی", + image: "/images/therapists/sebti.jpg", + bio: "کارشناسی ارشد روانشناس بالینی — کارشناس الهیات — مشاوره فردی بانوان، افسردگی و اضطراب — رویکرد هیجان‌مدار، معنویت‌درمانی و شناختی‌رفتاری.", + }, + { + name: "زهره حیدری", + image: "/images/therapists/heydari.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۲۳۶۱۸۶ — کارشناسی ارشد روانشناسی عمومی — طرحواره‌درمانی — وسواس و اضطراب — تعارضات زناشویی.", + }, + { + name: "نجما صادق زاده", + image: "/images/therapists/sadeghzadeh.jpg", + bio: "کد پروانه اشتغال سازمان نظام روانشناسی ۱۳۷۶۰۸۲ — کارشناسی ارشد روانشناسی خانواده — زوج‌درمانی — مشاوره خانواده — مشاوره پیش از ازدواج.", + }, +] as const; + +/** Static workshop samples — will be replaced by backend later */ +export const workshops = [ + { + title: "دوره جامع تربیت درمانگر بالینی", + tag: "تخصصی", + status: "در حال ثبت نام", + image: "/images/blog/post-1.jpg", + }, + { + title: "کارگاه تربیت درمانگر زوج", + tag: "تخصصی", + status: "در حال ثبت نام", + image: "/images/blog/post-2.jpg", + }, + { + title: "کارگاه تربیت درمانگر کودک", + tag: "تخصصی", + status: "در حال ثبت نام", + image: "/images/blog/post-3.jpg", + }, + { + title: "کارگاه تربیت مشاور و مربی ازدواج", + tag: "تخصصی", + status: "در حال ثبت نام", + image: "/images/blog/post-4.jpg", + }, +] as const; + +export const consultModes = [ + { + title: "مشاوره چت آنلاین", + english: "CHAT ONLINE", + image: "/images/icons/chat-online.png", + }, + { + title: "مشاوره نوشتاری", + english: "WRITTEN", + image: "/images/icons/written.png", + }, + { + title: "مشاوره تلفنی", + english: "PHONE", + image: "/images/icons/phone.png", + }, +] as const; + +export const serviceCards = [ + { + title: "مشاوره شغلی و تحصیلی", + english: "EDUCATION", + image: "/images/services/education.png", + href: "/#services", + }, + { + title: "مشاوره طلاق", + english: "DIVORCE", + image: "/images/services/divorce.png", + href: "/#services", + }, + { + title: "مشاوره ازدواج", + english: "MARRIAGE", + image: "/images/services/marriage.png", + href: "/#services", + }, + { + title: "مشاوره خانواده", + english: "FAMILY", + image: "/images/services/family.png", + href: "/#services", + }, +] as const; + +export const serviceMenu = [ + "مشاوره فردی", + "مشاوره کودک", + "مشاوره ازدواج", + "مشاوره طلاق", + "بیوفیدبک و ریلکسیشن", + "مشاوره زناشویی", + "مشاوره خانواده و زوج درمانی", + "مشاوره شغلی و تحصیلی", + "مشاوره نوجوان و جوان", + "مزاج شناسی تخصصی", +] as const; + +/** Static article samples — will be replaced by backend later */ +export const articles = [ + { + title: "چرا بچه ام به من دروغ می گوید؟", + excerpt: + "امروزه دروغ‌گویی کودکان در دوران رشد اولیه، جزئی از تجربه‌هایشان است و ممکن است به عنوان رفتار طبیعی در نظر گرفته شود.", + image: "/images/blog/post-1.jpg", + }, + { + title: "تربیت فرزند - قسمت اول", + excerpt: + "تربیت کودک یک چالش اساسی برای خانواده‌ها است. والدین نه تنها باید نیازهای اولیه کودکان را تأمین کنند، بلکه باید با آن‌ها با عشق و محبت صحبت کنند.", + image: "/images/blog/post-2.jpg", + }, + { + title: "روش های کاهش استرس", + excerpt: + "یکی از مسائلی که همواره در طول زندگی با آن سر و کار داریم، استرس است. از مسائل کوچک روزمره تا بحران‌های پیچیده، استرس ما را در بر می‌گیرد.", + image: "/images/blog/post-3.jpg", + }, + { + title: "سکس تراپی چیست و چه موقع باید به سکس تراپیست مراجعه کرد؟", + excerpt: + "روابط جنسی یکی از مسائل مهم در زندگی زناشویی محسوب می‌شود. سکس‌تراپی یکی از راه‌های درمان مشکلات جنسی در خانواده است.", + image: "/images/blog/post-4.jpg", + }, + { + title: "چیکار کنم فرزندم به حرفم گوش بده", + excerpt: + "آیا به دنبال راهکارهایی هستید تا فرزندتان به حرف‌های شما گوش کند و ارتباطتان عمیق‌تر شود؟", + image: "/images/blog/post-5.jpg", + }, + { + title: "چگونه اعتماد به نفس خود را بالا ببرم؟", + excerpt: + "اعتماد به نفس، یکی از جنبه‌های کلیدی و مهم در زندگی است که تأثیر قابل ملاحظه‌ای بر روحیه، عملکرد و رضایتمندی ما دارد.", + image: "/images/blog/post-6.jpg", + }, +] as const; + +export const testimonials = [ + { + name: "علی رنجبر", + date: "۱۴۰۰/۰۷/۲۳", + text: "عالی هستن من خیلی راحت باهاشون ارتباط گرفتم بدون قضاوت عالی گوش میدن و بهترین راهنمایی‌ها را میکنن مرسی از خانم دکتر", + }, + { + name: "فاطمه موسوی", + date: "۱۴۰۱/۰۹/۲۵", + text: "بعنوان جلسه اول خوب بود و البته هنوز برای قضاوتم زود هستش ولی مشتاق شدم که جلسات بعدی رو شرکت کنم چون امیدوار شدم که کمک کننده خواهد بود.سپاس", + }, + { + name: "مریم احمدی", + date: "۱۴۰۱/۱۱/۱۲", + text: "برای مشاوره ازدواج مراجعه کردیم، برخورد خیلی حرفه‌ای و دقیق بود. احساس می‌کنم مسیر روشن‌تری برای تصمیم‌گیری پیدا کردیم.", + }, + { + name: "حسین کریمی", + date: "۱۴۰۲/۰۲/۰۸", + text: "جلسات مشاوره فردی خیلی کمکم کرد اضطرابم کمتر بشه. محیط کلینیک آروم و منظم بود و زمان‌بندی جلسات هم دقیق رعایت می‌شد.", + }, + { + name: "زهرا محمدی", + date: "۱۴۰۲/۰۵/۱۹", + text: "برای فرزندم مشاوره کودک گرفتیم. مشاور با صبر و حوصله راهنمایی کرد و بعد از چند جلسه تغییر رفتارش کاملاً محسوس بود.", + }, + { + name: "رضا نوری", + date: "۱۴۰۲/۰۸/۰۳", + text: "از کارگاه‌های آموزشی کلینیک خیلی راضی بودم. مطالب کاربردی و قابل استفاده در زندگی روزمره بود و فضای کارگاه دوستانه و مفید برگزار شد.", + }, +] as const; + +export const stats = [ + { value: "۹۸٪", label: "رضایت مراجعان", english: "SATISFACTION" }, + { value: "۶۵", label: "تعداد کارگاه برگزار شده", english: "WORKSHOP" }, + { value: "۷۵", label: "تعداد مقالات", english: "ARTICLES" }, + { value: "۲۵", label: "تعداد مراجعین در ماه", english: "CLIENTS" }, +] as const; + +export const aboutPoints = [ + "روان درمانی، مشاوره تخصصی و روان سنجی (تست‌ها و آزمون‌های تشخیصی روانشناسی)", + "برگزاری کارگاه‌های آموزشی عمومی و تخصصی، سمینار و همایش در موضوعات مهارت‌های زندگی، مهارت‌های خانواده، مهارت‌های فردی، تربیت روان‌درمانگر برای متخصصان و مشاوران، کارگاه‌های موفقیت، کارگاه‌های ازدواج و حوزه کودک و نوجوان", + "اجرای طرح «ثنامهر» (مشاوره، آموزش، همسان‌گزینی، مددکاری، حمایت‌های مالی و معرفی به مراکز خیریه و ...)", + "مزاج‌شناسی تخصصی، اصلاح تغذیه و سبک زندگی", + "نمایندگی انحصاری بسته جامعه درسا (استعدادسنجی و پرورش هوش کودک و نوجوان) در سطح استان قم", + "تخصصی‌ترین مرکز ازدواج در قم", +] as const; diff --git a/src/lib/blog.ts b/src/lib/blog.ts new file mode 100644 index 0000000..e39878b --- /dev/null +++ b/src/lib/blog.ts @@ -0,0 +1,82 @@ +import { articles } from "@/data/site"; +import { meshkeeGet, tenantPath } from "@/lib/meshkee"; +import { detailPath, slugifyForUrl } from "@/lib/seo-slug"; + +export type BlogPost = { + id: string; + title: string; + slug: string; + abstract?: string | null; + mainTextHtml?: string | null; + titleImageUrl?: string | null; + publishedAt?: string | null; + createdAt?: string | null; + commentCount?: number; + author?: { name?: string } | string | null; +}; + +export type PagedBlogs = { + items: BlogPost[]; + total: number; + page: number; + pageSize: number; +}; + +export async function fetchBlogs(params: { page?: number; pageSize?: number } = {}) { + const query = new URLSearchParams(); + query.set("page", String(params.page ?? 1)); + query.set("pageSize", String(params.pageSize ?? 12)); + return meshkeeGet<PagedBlogs>(tenantPath(`/blogs?${query.toString()}`), { + items: [], + total: 0, + page: 1, + pageSize: params.pageSize ?? 12, + }); +} + +export async function fetchBlogById(id: string) { + const data = await meshkeeGet<{ blog?: BlogPost }>( + tenantPath(`/blogs/by-id/${encodeURIComponent(id)}`), + {}, + ); + return data.blog ?? null; +} + +/** @deprecated Prefer fetchBlogById for public detail pages. */ +export async function fetchBlogBySlug(slug: string) { + const data = await meshkeeGet<{ blog?: BlogPost }>(tenantPath(`/blogs/${encodeURIComponent(slug)}`), {}); + return data.blog ?? null; +} + +export function blogImage(post: BlogPost) { + return post.titleImageUrl || "/images/blog/post-1.jpg"; +} + +export function blogHref(post: Pick<BlogPost, "id" | "title">) { + return detailPath("/blog", post.id, post.title); +} + +export function blogTitleSlug(title: string) { + return slugifyForUrl(title); +} + +export function getLocalBlogPosts(): BlogPost[] { + return articles.map((item, index) => ({ + id: `local-${index}`, + title: item.title, + slug: slugifyForUrl(item.title, `article-${index}`), + abstract: item.excerpt, + titleImageUrl: item.image, + publishedAt: null, + createdAt: null, + })); +} + +export function getLocalBlogPost(idOrSlug: string) { + const posts = getLocalBlogPosts(); + return ( + posts.find((post) => post.id === idOrSlug || post.slug === idOrSlug) ?? + posts.find((post) => slugifyForUrl(post.title) === decodeURIComponent(idOrSlug)) ?? + null + ); +} diff --git a/src/lib/comments.ts b/src/lib/comments.ts new file mode 100644 index 0000000..ab3be15 --- /dev/null +++ b/src/lib/comments.ts @@ -0,0 +1,16 @@ +import { meshkeeGet, tenantPath } from "@/lib/meshkee"; + +export type CommentItem = { + id?: string; + authorName?: string | null; + text?: string | null; + createdAt?: string | null; +}; + +export async function fetchComments(entityType: "product" | "blog" | "portfolio" | "video", entityId: string) { + const data = await meshkeeGet<{ items?: CommentItem[] }>( + tenantPath(`/comments?entityType=${entityType}&entityId=${encodeURIComponent(entityId)}`), + { items: [] }, + ); + return data.items ?? []; +} diff --git a/src/lib/config.ts b/src/lib/config.ts new file mode 100644 index 0000000..1219a2a --- /dev/null +++ b/src/lib/config.ts @@ -0,0 +1,20 @@ +export const websiteDomain = + process.env.NEXT_PUBLIC_WEBSITE_DOMAIN ?? + process.env.WEBSITE_DOMAIN ?? + process.env.NEXT_PUBLIC_MESHKEE_DOMAIN ?? + "clinicsamen.com"; + +export const meshkeeApiBase = ( + process.env.NEXT_PUBLIC_MESHKEE_API_BASE ?? + process.env.MESHKEE_API_BASE ?? + process.env.NEXT_PUBLIC_MESHKEE_API_URL ?? + "https://api.meshkee.com/api/v1" +).replace(/\/$/, ""); + +export const customerPortalUrl = ( + process.env.NEXT_PUBLIC_CUSTOMER_PORTAL_URL ?? `https://customer.${websiteDomain}` +).replace(/\/$/, ""); + +export const businessDashboardUrl = ( + process.env.NEXT_PUBLIC_BUSINESS_ORIGIN ?? `https://business.${websiteDomain}` +).replace(/\/$/, ""); diff --git a/src/lib/format.ts b/src/lib/format.ts new file mode 100644 index 0000000..464ad12 --- /dev/null +++ b/src/lib/format.ts @@ -0,0 +1,16 @@ +export function faDigits(value: number | string) { + return String(value).replace(/\d/g, (digit) => "۰۱۲۳۴۵۶۷۸۹"[Number(digit)]); +} + +export function formatFaDate(value?: string | null) { + if (!value) return ""; + try { + return new Intl.DateTimeFormat("fa-IR", { + year: "numeric", + month: "long", + day: "numeric", + }).format(new Date(value)); + } catch { + return value; + } +} diff --git a/src/lib/meshkee-server.ts b/src/lib/meshkee-server.ts new file mode 100644 index 0000000..97b9bce --- /dev/null +++ b/src/lib/meshkee-server.ts @@ -0,0 +1,42 @@ +import { meshkeeApiBase } from "@/lib/config"; + +export function getBearerToken(request: Request): string | null { + const auth = request.headers.get("authorization"); + if (auth?.startsWith("Bearer ")) return auth.slice(7); + return null; +} + +export async function meshkeeFetch( + path: string, + init?: RequestInit & { token?: string | null }, +): Promise<{ ok: boolean; status: number; data: unknown }> { + const headers = new Headers(init?.headers); + if (!headers.has("Content-Type") && init?.body) { + headers.set("Content-Type", "application/json"); + } + if (init?.token) { + headers.set("Authorization", `Bearer ${init.token}`); + } + + const res = await fetch(`${meshkeeApiBase}${path}`, { + ...init, + headers, + }); + + let data: unknown = null; + try { + data = await res.json(); + } catch { + data = null; + } + + return { ok: res.ok, status: res.status, data }; +} + +export function jsonResponse(data: unknown, status = 200) { + return Response.json(data, { status }); +} + +export function unauthorizedResponse() { + return jsonResponse({ error: "Unauthorized" }, 401); +} diff --git a/src/lib/meshkee.ts b/src/lib/meshkee.ts new file mode 100644 index 0000000..a93c11c --- /dev/null +++ b/src/lib/meshkee.ts @@ -0,0 +1,33 @@ +import { meshkeeApiBase, websiteDomain } from "@/lib/config"; + +export async function meshkeeGet<T>(path: string, fallback: T, revalidate = 60): Promise<T> { + try { + const response = await fetch(`${meshkeeApiBase}${path}`, { + next: { revalidate }, + }); + if (!response.ok) return fallback; + return (await response.json()) as T; + } catch { + return fallback; + } +} + +export function tenantPath(suffix: string) { + return `/tenants/${encodeURIComponent(websiteDomain)}${suffix}`; +} + +type Tenant = { + id: number | string; + nameFa?: string; + name?: string; + domain?: string; +}; + +export async function getTenant() { + return meshkeeGet<Tenant | null>(`/tenants/${encodeURIComponent(websiteDomain)}`, null); +} + +export async function getBusinessId() { + const tenant = await getTenant(); + return tenant?.id != null ? String(tenant.id) : ""; +} diff --git a/src/lib/seo-slug.ts b/src/lib/seo-slug.ts new file mode 100644 index 0000000..321b35d --- /dev/null +++ b/src/lib/seo-slug.ts @@ -0,0 +1,17 @@ +/** Build a URL path segment from a title (Persian / Arabic / Latin). */ +export function slugifyForUrl(value: string, fallback = "item"): string { + const slug = value + .trim() + .normalize("NFC") + .replace(/\s+/g, "-") + .replace(/[^\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFFa-zA-Z0-9-]+/g, "") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); + + return slug || fallback; +} + +export function detailPath(base: string, id: string | number, title: string) { + const slug = slugifyForUrl(title); + return `${base}/${encodeURIComponent(String(id))}/${encodeURIComponent(slug)}`; +} diff --git a/src/lib/seo.ts b/src/lib/seo.ts new file mode 100644 index 0000000..33c0139 --- /dev/null +++ b/src/lib/seo.ts @@ -0,0 +1,42 @@ +import type { Metadata } from "next"; + +import { site } from "@/data/site"; +import { websiteDomain } from "@/lib/config"; + +export const siteUrl = `https://${websiteDomain}`; + +export function pageMetadata({ + title, + description, + path = "/", + image, +}: { + title: string; + description: string; + path?: string; + image?: string | null; +}): Metadata { + const url = `${siteUrl}${path.startsWith("/") ? path : `/${path}`}`; + const ogImage = image || `${siteUrl}/images/logo/clinic-logo.png`; + + return { + title, + description, + alternates: { canonical: url }, + openGraph: { + type: path === "/" ? "website" : "article", + locale: "fa_IR", + url, + siteName: site.shortName, + title, + description, + images: [{ url: ogImage, alt: title }], + }, + twitter: { + card: "summary_large_image", + title, + description, + images: [ogImage], + }, + }; +} diff --git a/src/lib/session.tsx b/src/lib/session.tsx new file mode 100644 index 0000000..bc953a3 --- /dev/null +++ b/src/lib/session.tsx @@ -0,0 +1,188 @@ +"use client"; + +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, + type ReactNode, +} from "react"; + +import { + clearSharedAuthCookies, + hydrateLocalTokensFromSharedCookies, + SHARED_ACCESS_TOKEN_KEY, + SHARED_REFRESH_TOKEN_KEY, + writeSharedAuthCookies, +} from "@/lib/shared-auth-cookie"; + +export type AuthBusinessMembership = { + id: string; + name: string; + slug: string; + isOwner: boolean; + teamRole: string | null; +}; + +export type AuthUser = { + id: string; + firstName?: string; + lastName?: string; + cellNumber?: string; + email?: string; + roles?: string[]; + isSuperAdmin?: boolean; + businesses?: AuthBusinessMembership[]; +}; + +type SessionContextValue = { + user: AuthUser | null; + isAuthenticated: boolean; + ready: boolean; + businessId: string; + isWebsiteAdmin: boolean; + logout: () => void; + getAccessToken: () => string | null; +}; + +function normalizeUser(raw: Partial<AuthUser> & { id?: string | number }): AuthUser | null { + if (raw.id == null) return null; + return { + id: String(raw.id), + firstName: raw.firstName ?? undefined, + lastName: raw.lastName ?? undefined, + cellNumber: raw.cellNumber ?? undefined, + email: raw.email ?? undefined, + roles: Array.isArray(raw.roles) ? raw.roles : undefined, + isSuperAdmin: Boolean(raw.isSuperAdmin), + businesses: Array.isArray(raw.businesses) + ? raw.businesses.map((business) => ({ + id: String(business.id), + name: business.name, + slug: business.slug, + isOwner: Boolean(business.isOwner), + teamRole: business.teamRole ?? null, + })) + : undefined, + }; +} + +export function isWebsiteAdminForBusiness(user: AuthUser | null | undefined, businessId: string): boolean { + if (!user || !businessId) return false; + if (user.isSuperAdmin || user.roles?.includes("super_admin")) return true; + return Boolean( + user.businesses?.some( + (business) => String(business.id) === String(businessId) && (business.isOwner || Boolean(business.teamRole)), + ), + ); +} + +const SessionContext = createContext<SessionContextValue | null>(null); + +function readToken(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} + +function writeToken(key: string, value: string | null) { + try { + if (value) localStorage.setItem(key, value); + else localStorage.removeItem(key); + } catch { + // ignore + } +} + +export function SessionProvider({ + children, + businessId, +}: { + children: ReactNode; + businessId: string; +}) { + const [user, setUser] = useState<AuthUser | null>(null); + const [ready, setReady] = useState(false); + + const getAccessToken = useCallback(() => { + hydrateLocalTokensFromSharedCookies(SHARED_ACCESS_TOKEN_KEY, SHARED_REFRESH_TOKEN_KEY); + return ( + readToken(SHARED_ACCESS_TOKEN_KEY) || + readToken("accessToken") || + readToken("meshkeeToken") || + readToken("token") + ); + }, []); + + const clearTokens = useCallback(() => { + writeToken(SHARED_ACCESS_TOKEN_KEY, null); + writeToken(SHARED_REFRESH_TOKEN_KEY, null); + writeToken("accessToken", null); + writeToken("meshkeeToken", null); + writeToken("token", null); + clearSharedAuthCookies(); + setUser(null); + }, []); + + useEffect(() => { + const token = getAccessToken(); + if (!token) { + setReady(true); + return; + } + + const refresh = readToken(SHARED_REFRESH_TOKEN_KEY); + writeSharedAuthCookies(token, refresh ?? undefined); + + fetch("/api/auth/me", { headers: { Authorization: `Bearer ${token}` } }) + .then(async (res) => { + if (res.status === 401) { + clearTokens(); + return; + } + if (!res.ok) return; + const data = (await res.json()) as { user?: AuthUser } & AuthUser; + const next = normalizeUser(data.user ?? data); + if (next) setUser(next); + }) + .catch(() => undefined) + .finally(() => setReady(true)); + }, [clearTokens, getAccessToken]); + + const logout = useCallback(() => { + clearTokens(); + }, [clearTokens]); + + const isWebsiteAdmin = useMemo(() => isWebsiteAdminForBusiness(user, businessId), [user, businessId]); + + const value = useMemo( + () => ({ + user, + isAuthenticated: Boolean(user), + ready, + businessId, + isWebsiteAdmin, + logout, + getAccessToken, + }), + [user, ready, businessId, isWebsiteAdmin, logout, getAccessToken], + ); + + return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>; +} + +export function useSession() { + const ctx = useContext(SessionContext); + if (!ctx) throw new Error("useSession must be used within SessionProvider"); + return ctx; +} + +export function userDisplayName(user: AuthUser | null | undefined) { + if (!user) return "کاربر"; + const full = [user.firstName, user.lastName].filter(Boolean).join(" ").trim(); + return full || user.cellNumber || user.email || "کاربر"; +} diff --git a/src/lib/shared-auth-cookie.ts b/src/lib/shared-auth-cookie.ts new file mode 100644 index 0000000..87843c4 --- /dev/null +++ b/src/lib/shared-auth-cookie.ts @@ -0,0 +1,123 @@ +/** Shared auth cookies so storefront + customer.{domain} share one login. */ + +export const SHARED_ACCESS_TOKEN_KEY = "meshkee_customer_access_token"; +export const SHARED_REFRESH_TOKEN_KEY = "meshkee_customer_refresh_token"; + +const CHUNK_SIZE = 2800; +const MAX_CHUNKS = 24; + +function cookieDomain(): string | undefined { + if (typeof window === "undefined") return undefined; + const host = window.location.hostname.toLowerCase(); + if (host === "localhost" || host === "127.0.0.1") return undefined; + const parts = host.split(".").filter(Boolean); + if (parts.length < 2) return undefined; + return `.${parts.slice(-2).join(".")}`; +} + +function readRawCookie(name: string): string | null { + if (typeof document === "undefined") return null; + const prefix = `${name}=`; + const match = document.cookie.split("; ").find((row) => row.startsWith(prefix)); + if (!match) return null; + return match.slice(prefix.length); +} + +function writeRawCookie(name: string, value: string | null) { + if (typeof document === "undefined") return; + const domain = cookieDomain(); + if (value == null) { + let cookie = `${name}=; path=/; max-age=0; SameSite=Lax`; + if (domain) cookie += `; domain=${domain}`; + document.cookie = cookie; + return; + } + const maxAge = 60 * 60 * 24 * 30; + let cookie = `${name}=${value}; path=/; max-age=${maxAge}; SameSite=Lax`; + if (domain) cookie += `; domain=${domain}`; + document.cookie = cookie; +} + +function clearChunkedCookie(name: string) { + writeRawCookie(name, null); + const n = Number(readRawCookie(`${name}_n`) || "0"); + writeRawCookie(`${name}_n`, null); + for (let i = 0; i < Math.max(n, MAX_CHUNKS); i++) { + writeRawCookie(`${name}_${i}`, null); + } +} + +function writeCookie(name: string, value: string | null) { + clearChunkedCookie(name); + if (value == null || value === "") return; + + const encoded = encodeURIComponent(value); + if (encoded.length <= 3500) { + writeRawCookie(name, encoded); + return; + } + + const chunks: string[] = []; + for (let i = 0; i < encoded.length; i += CHUNK_SIZE) { + chunks.push(encoded.slice(i, i + CHUNK_SIZE)); + } + writeRawCookie(`${name}_n`, String(chunks.length)); + chunks.forEach((chunk, i) => writeRawCookie(`${name}_${i}`, chunk)); +} + +function readCookie(name: string): string | null { + const n = Number(readRawCookie(`${name}_n`) || "0"); + if (n > 0) { + let encoded = ""; + for (let i = 0; i < n; i++) { + const part = readRawCookie(`${name}_${i}`); + if (part == null) return null; + encoded += part; + } + try { + return decodeURIComponent(encoded); + } catch { + return null; + } + } + + const raw = readRawCookie(name); + if (raw == null) return null; + try { + return decodeURIComponent(raw); + } catch { + return null; + } +} + +export function writeSharedAuthCookies(accessToken: string, refreshToken?: string) { + writeCookie(SHARED_ACCESS_TOKEN_KEY, accessToken); + if (refreshToken) writeCookie(SHARED_REFRESH_TOKEN_KEY, refreshToken); +} + +export function clearSharedAuthCookies() { + writeCookie(SHARED_ACCESS_TOKEN_KEY, null); + writeCookie(SHARED_REFRESH_TOKEN_KEY, null); +} + +export function readSharedAccessToken(): string | null { + return readCookie(SHARED_ACCESS_TOKEN_KEY); +} + +export function readSharedRefreshToken(): string | null { + return readCookie(SHARED_REFRESH_TOKEN_KEY); +} + +export function hydrateLocalTokensFromSharedCookies( + accessKey = SHARED_ACCESS_TOKEN_KEY, + refreshKey = SHARED_REFRESH_TOKEN_KEY, +): boolean { + if (typeof window === "undefined") return false; + if (localStorage.getItem(accessKey)) return false; + const access = readSharedAccessToken(); + if (!access) return false; + localStorage.setItem(accessKey, access); + const refresh = readSharedRefreshToken(); + if (refresh) localStorage.setItem(refreshKey, refresh); + return true; +} diff --git a/src/lib/sitemap-config.generated.json b/src/lib/sitemap-config.generated.json new file mode 100644 index 0000000..b5e609e --- /dev/null +++ b/src/lib/sitemap-config.generated.json @@ -0,0 +1,35 @@ +{ + "baseUrl": "https://clinicsamen.com", + "staticPages": [ + { + "path": "/", + "changefreq": "daily", + "priority": 1 + }, + { + "path": "/about", + "changefreq": "monthly", + "priority": 0.6 + }, + { + "path": "/blog", + "changefreq": "weekly", + "priority": 0.8 + }, + { + "path": "/contact", + "changefreq": "monthly", + "priority": 0.5 + }, + { + "path": "/ourdr", + "changefreq": "weekly", + "priority": 0.8 + }, + { + "path": "/workshops", + "changefreq": "weekly", + "priority": 0.8 + } + ] +} diff --git a/src/lib/static-images.ts b/src/lib/static-images.ts new file mode 100644 index 0000000..834fc82 --- /dev/null +++ b/src/lib/static-images.ts @@ -0,0 +1,191 @@ +import { meshkeeApiBase, websiteDomain } from "@/lib/config"; + +export type SlotKind = "single" | "list"; + +export type SlotImage = { + id: string; + url: string; + titleFa?: string | null; + titleEn?: string | null; + subtext?: string | null; + linkUrl?: string | null; + width?: number | null; + height?: number | null; + sortOrder?: number | null; +}; + +export type StaticImageSlotCatalogItem = { + key: string; + label: string; + kind: SlotKind; + pageKey: string; + aspectRatio: string; + itemCount: number | null; + recommendedWidth: number; +}; + +export type StaticImageSlot = StaticImageSlotCatalogItem & { + images: SlotImage[]; +}; + +export type SlotMediaItem = { + id: string; + image: string; + href?: string; + title?: string; + kicker?: string; + text?: string; + fallbackSrc?: string; +}; + +/** + * Homepage slot catalog published at GET /meshkee/static-image-slots. + * Ratios match the live homepage container (~1180px). If a section’s CSS size + * or aspect ratio changes, update this catalog in the same change — Meshkee + * reads it as the static-image source of truth. + */ +export const STATIC_IMAGE_SLOTS: StaticImageSlotCatalogItem[] = [ + { + key: "slider", + label: "Homepage slider", + kind: "list", + pageKey: "home", + aspectRatio: "1920:740", + itemCount: null, + recommendedWidth: 1180, + }, + { + key: "4-people-image", + label: "Four people images", + kind: "list", + pageKey: "home", + aspectRatio: "325:356", + itemCount: 4, + recommendedWidth: 280, + }, + { + key: "our-services-icon", + label: "Our services icons", + kind: "list", + pageKey: "home", + aspectRatio: "1:1", + itemCount: 4, + recommendedWidth: 110, + }, + { + key: "two-banner-bg", + label: "Two banner backgrounds", + kind: "list", + pageKey: "home", + aspectRatio: "540:312", + itemCount: 2, + recommendedWidth: 560, + }, +]; + +export function catalogSlot(key: string) { + return STATIC_IMAGE_SLOTS.find((slot) => slot.key === key); +} + +export function parseAspectRatio(ratio?: string | null) { + if (!ratio) return undefined; + const match = /^(\d+(?:\.\d+)?)\s*:\s*(\d+(?:\.\d+)?)$/.exec(ratio.trim()); + if (!match) return undefined; + return `${match[1]} / ${match[2]}`; +} + +export function pickSlot(slots: StaticImageSlot[], key: string) { + return slots.find((slot) => slot.key === key); +} + +function normalizeImages(images: SlotImage[] | undefined) { + return [...(images ?? [])] + .filter((image) => Boolean(image?.url)) + .sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0)); +} + +export function imagesFromSlot(slot?: StaticImageSlot | null): SlotImage[] { + if (!slot) return []; + const images = normalizeImages(slot.images); + if (slot.kind === "single") return images.slice(0, 1); + return images; +} + +function toMedia(image: SlotImage, fallback?: SlotMediaItem): SlotMediaItem { + return { + id: String(image.id), + image: image.url, + href: image.linkUrl?.trim() || fallback?.href, + title: image.titleFa?.trim() || fallback?.title, + kicker: image.titleEn?.trim() || fallback?.kicker, + text: image.subtext?.trim() || fallback?.text, + fallbackSrc: fallback?.image || fallback?.fallbackSrc, + }; +} + +export function overlaySlotImages( + slot: StaticImageSlot | undefined, + fallbacks: SlotMediaItem[], + key: string, +): { items: SlotMediaItem[]; aspectRatio?: string } { + const catalog = catalogSlot(key); + const aspectRatio = slot?.aspectRatio || catalog?.aspectRatio; + const kind = slot?.kind ?? catalog?.kind ?? "list"; + const itemCount = slot?.itemCount ?? catalog?.itemCount ?? null; + const apiImages = imagesFromSlot(slot ? { ...slot, kind, images: slot.images ?? [] } : undefined); + + if (kind === "single") { + const image = apiImages[0]; + const fallback = fallbacks[0]; + return { + aspectRatio, + items: image ? [toMedia(image, fallback)] : fallbacks.slice(0, 1), + }; + } + + if (apiImages.length === 0) { + return { + aspectRatio, + items: itemCount ? fallbacks.slice(0, itemCount) : fallbacks, + }; + } + + if (itemCount) { + return { + aspectRatio, + items: Array.from({ length: itemCount }, (_, index) => { + const image = apiImages[index]; + const fallback = fallbacks[index] ?? fallbacks[fallbacks.length - 1]; + return image ? toMedia(image, fallback) : fallback; + }).filter(Boolean), + }; + } + + return { + aspectRatio, + items: apiImages.map((image, index) => toMedia(image, fallbacks[index])), + }; +} + +function readItems(payload: unknown): StaticImageSlot[] { + if (Array.isArray(payload)) return payload as StaticImageSlot[]; + if (payload && typeof payload === "object") { + const record = payload as { items?: StaticImageSlot[]; slots?: StaticImageSlot[] }; + return record.items ?? record.slots ?? []; + } + return []; +} + +export async function fetchStaticImageSlots(pageKey = "home"): Promise<StaticImageSlot[]> { + const url = `${meshkeeApiBase}/tenants/${encodeURIComponent(websiteDomain)}/website/static-images?pageKey=${encodeURIComponent(pageKey)}`; + + try { + const response = await fetch(url, { + next: { revalidate: 60 }, + }); + if (!response.ok) return []; + return readItems(await response.json()); + } catch { + return []; + } +} diff --git a/src/lib/workshops.ts b/src/lib/workshops.ts new file mode 100644 index 0000000..01cceb5 --- /dev/null +++ b/src/lib/workshops.ts @@ -0,0 +1,87 @@ +import { workshops as staticWorkshops } from "@/data/site"; +import { meshkeeGet, tenantPath } from "@/lib/meshkee"; +import type { CommentItem } from "@/lib/comments"; +import { slugifyForUrl } from "@/lib/seo-slug"; + +export type Workshop = { + id: string; + title: string; + slug: string; + abstract?: string | null; + mainTextHtml?: string | null; + titleImageUrl?: string | null; + imageUrls?: string[] | null; + eventDate?: string | null; + eventTime?: string | null; + duration?: string | null; + status?: string | null; + tag?: string | null; + comments?: CommentItem[]; + commentCount?: number; +}; + +export type PagedWorkshops = { + items: Workshop[]; + total: number; + page: number; + pageSize: number; +}; + +function staticFallbackWorkshops(): Workshop[] { + return staticWorkshops.map((item, index) => ({ + id: `local-${index}`, + title: item.title, + slug: slugifyForUrl(item.title, `workshop-${index}`), + abstract: null, + titleImageUrl: item.image, + status: item.status, + tag: item.tag, + })); +} + +export async function fetchWorkshops(params: { page?: number; pageSize?: number } = {}) { + const query = new URLSearchParams(); + query.set("page", String(params.page ?? 1)); + query.set("pageSize", String(params.pageSize ?? 12)); + const result = await meshkeeGet<PagedWorkshops>(tenantPath(`/workshops?${query.toString()}`), { + items: [], + total: 0, + page: 1, + pageSize: params.pageSize ?? 12, + }); + + if (result.items.length > 0) return result; + + const items = staticFallbackWorkshops(); + return { + items, + total: items.length, + page: 1, + pageSize: params.pageSize ?? 12, + }; +} + +export async function fetchWorkshopBySlug(slug: string) { + const data = await meshkeeGet<{ workshop?: Workshop }>( + tenantPath(`/workshops/${encodeURIComponent(slug)}`), + {}, + ); + if (data.workshop) return data.workshop; + + const decoded = decodeURIComponent(slug); + return staticFallbackWorkshops().find((item) => item.slug === decoded) ?? null; +} + +export function workshopImages(workshop: Workshop) { + if (workshop.imageUrls?.length) return workshop.imageUrls; + if (workshop.titleImageUrl) return [workshop.titleImageUrl]; + return ["/images/blog/post-1.jpg"]; +} + +export function workshopHref(workshop: Pick<Workshop, "slug">) { + return `/workshops/${encodeURIComponent(workshop.slug)}`; +} + +export function workshopImage(workshop: Workshop) { + return workshopImages(workshop)[0]; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b8cdcc7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +}