Commit f0be4220 by Madhankumar

feat: initial commit

parents
---
description: Optimized Next.js TypeScript Best Practices with Modern UI/UX
globs:
alwaysApply: false
---
You are an expert full-stack developer proficient in TypeScript, React, Next.js, and Tailwind CSS. Your task is to produce the most optimized and maintainable Next.js code, following best practices and adhering to the principles of clean code and robust architecture.
### Objective
- Create a Next.js solution that is not only functional but also adheres to the best practices in performance, security, and maintainability.
### Code Style and Structure
- Write concise, technical TypeScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Favor iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., `isLoading`, `hasError`).
- Structure files with exported components, subcomponents, helpers, static content, and types.
### Optimization and Best Practices
- Minimize the use of `'use client'`, `useEffect`, and `setState`; favor React Server Components (RSC) and Next.js SSR features.
- Implement dynamic imports for code splitting and optimization.
- Use responsive design with a mobile-first approach.
- Optimize images: use WebP format, include size data, implement lazy loading.
### Error Handling and Validation
- Prioritize error handling and edge cases:
- Use early returns for error conditions.
- Implement guard clauses to handle preconditions and invalid states early.
- Use custom error types for consistent error handling.
### UI and Styling
- Use modern UI frameworks (e.g., Tailwind CSS, Shadcn UI, Radix UI) for styling.
- Implement consistent design and responsive patterns across platforms.
### State Management and Data Fetching
- Use modern state management solutions (e.g., Zustand, TanStack React Query) to handle global state and data fetching.
- Implement validation using Zod for schema validation.
### Security and Performance
- Implement proper error handling, user input validation, and secure coding practices.
- Follow performance optimization techniques, such as reducing load times and improving rendering efficiency.
### Testing and Documentation
- Write unit tests for components using Jest and React Testing Library.
- Provide clear and concise comments for complex logic.
- Use JSDoc comments for functions and components to improve IDE intellisense.
### Methodology
1. **System 2 Thinking**: Approach the problem with analytical rigor. Break down the requirements into smaller, manageable parts and thoroughly consider each step before implementation.
2. **Tree of Thoughts**: Evaluate multiple possible solutions and their consequences. Use a structured approach to explore different paths and select the optimal one.
3. **Iterative Refinement**: Before finalizing the code, consider improvements, edge cases, and optimizations. Iterate through potential enhancements to ensure the final solution is robust.
### Instructions
1. Do not assume anything. If you have confusion, Immediately ass for confirmation.
**Process**:
1. **Deep Dive Analysis**: Begin by conducting a thorough analysis of the task at hand, considering the technical requirements and constraints.
2. **Planning**: Develop a clear plan that outlines the architectural structure and flow of the solution, using <PLANNING> tags if necessary.
3. **Implementation**: Implement the solution step-by-step, ensuring that each part adheres to the specified best practices.
4. **Review and Optimize**: Perform a review of the code, looking for areas of potential optimization and improvement.
5. **Finalization**: Finalize the code by ensuring it meets all requirements, is secure, and is performant.
\ No newline at end of file
You are an expert programming assistant that primarily focus on producing clear, readable Next.JS + Tailwind + Typescript code.
You always use pnpm as package manager.
You always use latest version of Next.JS, and you are familiar with the latest features and best practices of Next.JS, TypeScript and Tailwind. Remember the API uses javascript, not typescript.
You are familiar with latest features of prima and how to integrate with Next.js application.
For styling, you use Tailwind CSS. Use appropriate and most used colors for light and dark mode.
You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning.
- Follow user's requirements carefully & to the letter.
- First think step-by-step - describe your plan for what to build in pseudocode, written out in great detail.
- Confirm, then write the code!
- Always write correct, up to date, bug free, fully functional and working, secure, performant and efficient code.
- Focus on readability over performant.
- Fully implement all requested functionality.
- Leave NO Todo's, placeholders and missing pieces.
- Be sure to reference filenames.
- Be concise. Minimize any other prose.
- If you think there might not be a correct answer, you say so. If you don't know the answer, say so instead of guessing.
- Do not assume anything, ask the user for clarification if you are not sure about the requirements.
- Do not modify any other unrelated code logic
{
"path": "cz-conventional-changelog"
}
/node_modules
/build
/.git
/.next
README.md
Dockerfile
*.log
*.log*
.vscode
.DS_Store
.gitignore
.editorconfig
.env
.env.local
.gitlab-ci.yml
.eslintrc.js
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
\ No newline at end of file
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=6LfKHP8qAAAAACTpTp8SYhHCfExIJKkAa-VB3RRD
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=
APP_RECAPTCHA_SECRET=
APP_APIGEE_USERNAME=
APP_APIGEE_PASSWORD=
{
"extends": [
"next/core-web-vitals",
"plugin:storybook/recommended"
]
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel
# yarn
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
stages:
- build
- deploy
variables:
app_name: maf-egypt-business-park
app_image_tag: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
image_tag: $CI_BUILD_REF_NAME
image: $CI_REGISTRY_IMAGE
registry_pass: $CI_BUILD_TOKEN
registry_user: gitlab-ci-token
registry: $CI_REGISTRY
slack_channel: mafegypt-businesspark
ecs_definition: config/ecs-task-definition.json
ecs_entrypoint: app:3000
docker_build_staging:
tags:
- docker
- eu
stage: build
variables:
app_env: staging
app_url: https://maf-egypt-business-park-staging.eu-staging.kacdn.net
script:
- env
- docker login -u $registry_user -p $registry_pass $registry
- docker build -t $app_image_tag
--build-arg APP_ENV=$app_env
--build-arg NEXT_PUBLIC_RECAPTCHA_SITE_KEY=$app_recaptcha_site_key
--build-arg NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=$app_google_maps_api_key .
- docker push $app_image_tag
only:
- master
deploy_staging:
image: registry.git.int.krds.com/tools/deploy:edge
tags:
- deploy
- eu
stage: deploy
variables:
app_env: staging
script:
- deploy-ecs eu-staging
only:
- master
{
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS --extends @commitlint/config-conventional",
"pre-commit": "pretty-quick --staged"
}
}
public-hoist-pattern[]=*@heroui/*
{
"jsxBracketSameLine": true,
"singleQuote": true,
"jsxSingleQuote": false,
"trailingComma": "none"
}
import type { StorybookConfig } from '@storybook/nextjs';
import path from 'path';
const config: StorybookConfig = {
stories: [
'../components/**/*.stories.@(ts|tsx|js|jsx|mdx)',
'../theme/**/*.stories.@(ts|tsx|js|jsx|mdx)'
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
'storybook-dark-mode'
],
webpackFinal: async (config) => {
if (config.resolve) {
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '../')
};
}
return config;
},
framework: {
name: '@storybook/nextjs',
options: {}
},
docs: {
autodocs: 'tag'
}
};
export default config;
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
rel="stylesheet"
/>
import React from 'react';
import { themes } from '@storybook/theming';
import { HeroUIProvider } from '@heroui/react';
import { ParallaxProvider } from 'react-scroll-parallax';
import './style.css';
import '@/styles/globals.css';
import type { Preview } from '@storybook/react';
const decorators: Preview['decorators'] = [
(Story, { globals: { locale, disableAnimation } }) => {
const direction =
// @ts-ignore
locale && new Intl.Locale(locale)?.textInfo?.direction === 'rtl'
? 'rtl'
: undefined;
return (
<HeroUIProvider locale={locale} disableAnimation={disableAnimation}>
<ParallaxProvider>
{' '}
<div className="bg-dark" lang={locale} dir={direction}>
<Story />
</div>
</ParallaxProvider>
</HeroUIProvider>
);
}
];
const parameters: Preview['parameters'] = {
actions: { argTypesRegex: '^on[A-Z].*' },
options: {
storySort: {
method: 'alphabetical',
order: ['Foundations']
}
},
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i
}
},
darkMode: {
current: 'dark',
stylePreview: true,
darkClass: 'dark',
lightClass: 'light',
classTarget: 'html',
dark: {
...themes.dark,
appBg: '#161616',
barBg: 'black',
background: 'black',
appContentBg: 'black',
appBorderRadius: 14
},
light: {
...themes.light
}
}
};
const globalTypes: Preview['globalTypes'] = {
locale: {
toolbar: {
icon: 'globe',
items: ['en', 'ar'].map((locale) => ({
value: locale,
title: new Intl.DisplayNames(undefined, { type: 'language' }).of(
locale
),
right:
// @ts-ignore
new Intl.Locale(locale)?.textInfo?.direction === 'rtl'
? 'Right to Left'
: undefined
}))
}
},
disableAnimation: {
name: 'Disable Animation',
description: 'Disable all animations in the stories',
toolbar: {
icon: 'photodrag',
items: [
{ value: true, title: 'True' },
{ value: false, title: 'False' }
]
}
}
};
const preview: Preview = {
decorators,
parameters,
globalTypes
};
export default preview;
@tailwind base;
@tailwind components;
@tailwind utilities;
h1 {
@apply text-4xl font-bold text-foreground;
}
h2 {
@apply text-2xl font-bold text-foreground border-none;
}
h3 {
@apply text-xl font-bold text-neutral-600;
}
.dark .sbdocs-wrapper,
.dark .sbdocs-preview {
background-color: #000000;
color: #fff;
}
.dark .sbdocs-preview {
border: 1px solid #292929;
}
.dark .docblock-code-toggle {
background: transparent;
color: #d4d4d4;
}
.dark div:has(.docblock-code-toggle) {
background: transparent;
}
.dark .os-theme-dark {
background: #161616;
color: #fff;
}
.dark .sbdocs-title {
color: #fff;
}
.dark .docblock-argstable-head {
background: #161616;
}
.dark .docblock-argstable-head th {
color: #bcbcbc;
border-bottom: 1px solid #292929 !important;
}
.dark .docblock-argstable-head th span {
color: #bcbcbc;
}
.dark #docs-root tbody td {
background: #161616 !important;
color: #bcbcbc !important;
}
.dark #docs-root tbody tr:first-child td:first-child {
border-top-left-radius: 0 !important;
}
.dark #docs-root tbody tr:first-child td:last-child {
border-top-right-radius: 0 !important;
}
.dark #docs-root tbody tr:not(:first-child) {
border-top: 1px solid #292929 !important;
}
{
"cSpell.words": [
"dignissimos"
]
}
FROM node:18-alpine AS base
ARG APP_ENV
ARG NEXT_PUBLIC_RECAPTCHA_SITE_KEY
ARG NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
ENV NEXT_TELEMETRY_DISABLED 1
# Install corepack for pnpm
RUN corepack enable pnpm
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --production --shamefully-hoist
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build the application
RUN pnpm build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# SET appropriate robots.txt for the environment
RUN if [ "$APP_ENV" = "staging" ]; then \
mv ./public/robots.staging.txt ./public/robots.txt; \
else \
mv ./public/robots.production.txt ./public/robots.txt; \
fi
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
# MAF EGYPT BUSINESS PARK
## Tools Configured
- Next.js
- React Storybook
- Typescript
- Tailwind CSS
- Hero UI
- pnpm
- Commitizen
- Editorconfig
- Eslint
- Prettier
- Husky (to lint commit messages)
## Important Notes
- Enable nodejs corepack `corepack enable`
- Install pnpm using `corepack prepare pnpm@latest --activate`
- Install dependencies using `pnpm install`
- Install commitizen globally `npm install -g commitizen`
- Then, use `git cz` or `cz` to commit changes
- Commit messages must follow [angular conventional commit
standards](https://github.com/conventional-changelog/commitlint)
- Install prettier extension in editor. Enable "Format on save" option.
- Install editorconfig extension in editor.
- All files will be formatted using prettier before commit
### Development Server
```bash
pnpm dev
```
### Build Task
```bash
pnpm build
```
### Production Server
```bash
pnpm start
```
### Run Storybook
```bash
pnpm storybook
```
### Build Static Storybook
```bash
pnpm build-storybook
```
/** @module api/fetcher
* @param {string} url - The url to fetch
* @param {RequestInit} options - The fetch options
* @returns {Promise<T>} - The fetched data
* @throws {string} - The error message
* Fetches the data from the given url with the given options *
* @hidden
*/
// import { headers } from "next/headers";
export default async function fetcher<T>(
url: string,
options?: RequestInit,
showStrapiMetadata?: boolean
): Promise<T> {
const isSSR = typeof window === 'undefined';
const reqUrl = isSSR ? `${process.env.NEXT_PUBLIC_API_URL}${url}` : `/api/${url}`;
const printResponseInConsole =
false && process.env.NODE_ENV === 'development';
try {
const headers = options?.headers || {};
const response = await fetch(reqUrl, {
next: { revalidate: false },
...options,
headers: {
Authorization: `Bearer ${process.env.NEXT_API_TOKEN}`,
...headers
}
});
const json = await response.json();
if (response.ok) {
const response = showStrapiMetadata
? (json as Promise<T>)
: (json.data as Promise<T>);
if (printResponseInConsole) {
print.success(reqUrl, response);
} else {
print.success(reqUrl);
}
return response;
} else {
throw json;
}
} catch (error) {
console.log('3')
print.error(reqUrl, error);
throw 'Error fetching data from API';
}
}
const print = {
error: (url: string, error: any) => {
console.log('============================');
console.log(`\x1b[31mAPI Error:\x1b[0m ${url}\n`, error);
},
success: (url: string, data?: any) => {
console.log('============================');
console.log(`\x1b[32mReceived:\x1b[0m ${url}`);
if (data) {
console.log(data);
}
},
info: (url: string) => {
console.log('============================');
console.log(`\x1b[34mRequesting:\x1b[0m ${url}`);
}
};
import fetcher from "./fetcher";
export const getContact = async (): Promise<IPageRenderer> => {
const query = `/pages?filters[slug]=contact&populate[components][on][contact.contact][populate]=*`;
const response = await fetcher< IPageRenderer[]>(query);
return response[0];
};
import fetcher from "./fetcher";
export default async function getHeader(): Promise<IHeader> {
const response = await fetcher<IHeader>('/header?populate=*');
return response;
}
import fetcher from "./fetcher";
export default async function getLabels(): Promise<IFormLabels> {
const response = await fetcher<{ data: IFormLabels }>('/label?populate=*');
const formData = response.data;
console.log('formData', formData);
return formData
}
import fetcher from './fetcher';
interface Params {
slug: string;
}
export const getPage = async (): Promise<IPageRenderer> => {
const query = `/pages?filters[slug]=home&populate[components][on][banner.banner][populate][specifications][populate]=*&populate[components][on][banner.banner][populate][image][populate]=*&populate[components][on][image-carousel.image-carousel][populate][slides][populate]=*&populate[components][on][amenities.amenities][populate][image][populate]=*&populate[components][on][gallery.gallery][populate][gallery][populate]=*&populate[components][on][address-map.address-map][populate]=*`;
const response = await fetcher<IPageRenderer[]>(query);
return response[0];
};
import fetcher from "./fetcher";
interface ITermsAndConditionsResponse extends Object {
termsAndConditions: IMarkdown;
}
export const getTermsAndConditions = async (): Promise<ITermsAndConditionsResponse> => {
const query = `/terms-and-conditions?populate=*`;
const response = await fetcher<IApiResponse<ITermsAndConditionsResponse>>(query);
const item = response.data[0];
return { termsAndConditions: item.termsAndConditions };
};
'use server';
import { IContactFormValues } from '@/components/form/ContactForm/ContactForm';
import { verifyRecaptcha } from './utils/verifyRecaptcha';
import fetcher from './fetcher';
const submitForm = async (values: IContactFormValues): Promise<IResponse> => {
try {
const captchaToken = await verifyRecaptcha(values.recaptchaToken);
if (!captchaToken) {
throw new Error('Invalid captcha token');
}
const payload = {
title: values.title,
firstName: values.firstName,
lastName: values.lastName,
middleName: '',
countryCode: values.dialCode,
mobileNumber: values.mobileNumber,
email: values.email,
source: 'WebToLead',
channelType: 'WebToLead',
channelName: '',
countryOfResidence: values.residence,
propertyType: values.unitType,
unitSize: values.unitSize,
budget: values.budget,
buyingPurpose: values.purpose,
project: 'JN',
companyName: '',
formName: ''
};
await fetcher(`/contacts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: payload })
});
return { success: true };
} catch (error: any) {
console.error('=> Error submitting lead', error);
return { success: false, code: error?.message };
}
};
export default submitForm;
export const verifyRecaptcha = async (token: string): Promise<boolean> => {
console.log('token', token);
const response = await fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.APP_RECAPTCHA_SECRET}&response=${token}`
);
const json = await response.json();
console.log('json',json);
if (json.success) {
console.log('=> ReCaptcha verified');
return true;
}
console.error('=> ReCaptcha verification failed', json);
throw new Error(json['error-codes']);
};
import { getPage } from '@/api/getPage';
import { notFound } from 'next/navigation';
import { Suspense } from 'react';
import PageRenderer from '@/components/layout/PageRenderer';
export default async function AsyncPage() {
const page = await getPage();
return <PageRenderer components={page.components} prefix="home" />;
}
import { getContact } from '@/api/getContact';
import PageRenderer from '@/components/layout/PageRenderer';
export default async function ContactPage() {
const page = await getContact();
return <PageRenderer components={page.components} prefix="contact" />;
}
import type { Metadata } from 'next';
import Providers from '@/components/layout/Providers';
import '@/styles/globals.css';
import AsyncHeader from '@/components/layout/Header/AsyncHeader';
interface LayoutProps {
params: Promise<IParams>;
children: React.ReactNode;
}
export const metadata: Metadata = {
title: 'MAF Egypt Business Park',
description: 'MAF Egypt Business Park'
};
export default async function RootLayout({ params, children }: LayoutProps) {
const { locale } = await params;
return (
<html lang={locale}>
<head>
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="icon" href="/favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin=""
/>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
rel="stylesheet"
/>
{/* eslint-disable-next-line @next/next/next-script-for-ga */}
<script
dangerouslySetInnerHTML={{
__html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-5SZXVTJC');
`
}}
/>
</head>
<body>
{/* eslint-disable-next-line @next/next/next-script-for-ga */}
<noscript>
<iframe
src="https://www.googletagmanager.com/ns.html?id=GTM-5SZXVTJC"
height="0"
width="0"
style={{ display: 'none', visibility: 'hidden' }}></iframe>
</noscript>
<Providers>
<div className="flex flex-col min-h-screen">
<main className="grow [&>*:last-child:not(:only-child)]:mb-0">
<AsyncHeader />
{children}
</main>
</div>
</Providers>
</body>
</html>
);
}
import { Spinner } from '@heroui/react';
export default function Loading() {
return <h1>Loading...</h1>;
}
// import { getPage } from '@/api/getPageBySlug';
// import { notFound } from 'next/navigation';
// import AsyncPage from './AsyncPage';
// import { metaDataFactory } from '@/lib/metaDataFactory';
// interface Params {
// params: {
// slug: string;
// };
// }
// // export const generateMetadata = metaDataFactory({
// // apiMethod: getPageBySlug
// // });
// export default async function Page({ params }: Params) {
// try {
// await getPageBySlug({ slug: params.slug });
// } catch {
// return notFound();
// }
// return <AsyncPage slug={params.slug} />;
// }
import { getPage } from '@/api/getPage';
import { notFound } from 'next/navigation';
import { Suspense } from 'react';
import AsyncPage from './AsyncPage';
// interface Params {
// params: Promise<{ slug: string }>;
// }
export default async function Page() {
try {
await getPage();
} catch {
return notFound();
}
return <AsyncPage />;
}
export const metadata = {
title: 'Next.js',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
import Container from '@/components/layout/Container';
import RenderMarkdown from '@/components/shared/RenderMarkdown';
import { getTermsAndConditions } from '@/api/getTermsAndConditions';
export default async function TermsAndConditions() {
const { termsAndConditions } = await getTermsAndConditions();
return (
<Container as="section" className="my-16">
<RenderMarkdown
components={{
h1: ({ children }) => (
<h1 className="text-inherit text-2xl font-serif mb-4 md:text-4xl">
{children}
</h1>
),
p: ({ children }) => <p className="mb-3">{children}</p>,
ul: ({ children }) => <ul className="list-disc ps-6">{children}</ul>
}}>
{termsAndConditions}
</RenderMarkdown>
</Container>
);
}
import type { Meta, StoryObj } from '@storybook/react';
import Button from './Button';
import type { ButtonProps } from '@heroui/button';
const meta: Meta<typeof Button> = {
title: 'Base/Button',
component: Button,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
type TemplateProps = {
color: ButtonProps['color'];
};
const Template = ({ color }: TemplateProps) => {
return (
<div>
<h6 className="mb-2 font-semibold">Size</h6>
<div className="flex gap-5 mb-4 flex-wrap items-center">
<Button color={color} size="sm">
Small button
</Button>
<Button color={color} size="md">
Medium button
</Button>
<Button color={color} size="lg">
Large button
</Button>
<Button color={color} size="sm" variant="ghost">
Small Outline
</Button>
<Button color={color} size="md" variant="ghost">
Medium Outline
</Button>
<Button color={color} size="lg" variant="ghost">
Large Outline
</Button>
</div>
<h6 className="mb-2 font-semibold">Loading</h6>
<div className="flex gap-5 mb-4 flex-wrap items-center">
<Button color={color} size="sm" isLoading>
Small button
</Button>
<Button color={color} size="md" isLoading>
Medium button
</Button>
<Button color={color} size="lg" isLoading>
Large button
</Button>
<Button color={color} size="sm" variant="ghost" isLoading>
Small Outline
</Button>
<Button color={color} size="md" variant="ghost" isLoading>
Medium Outline
</Button>
<Button color={color} size="lg" variant="ghost" isLoading>
Large Outline
</Button>
</div>
<h6 className="mb-2 font-semibold">Disabled</h6>
<div className="flex gap-5 mb-4 flex-wrap items-center">
<Button color={color} size="sm" isDisabled>
Small button
</Button>
<Button color={color} size="md" isDisabled>
Medium button
</Button>
<Button color={color} size="lg" isDisabled>
Large button
</Button>
<Button color={color} size="sm" variant="ghost" isDisabled>
Small Outline
</Button>
<Button color={color} size="md" variant="ghost" isDisabled>
Medium Outline
</Button>
<Button color={color} size="lg" variant="ghost" isDisabled>
Large Outline
</Button>
</div>
<h6 className="mb-2 font-semibold">Full Width</h6>
<div className="flex flex-col gap-5">
<Button color={color} size="sm" fullWidth>
Small button
</Button>
<Button color={color} size="md" fullWidth>
Medium button
</Button>
<Button color={color} size="lg" fullWidth>
Large button
</Button>
<Button color={color} size="sm" variant="ghost" fullWidth>
Small Outline
</Button>
<Button color={color} size="md" variant="ghost" fullWidth>
Medium Outline
</Button>
<Button color={color} size="lg" variant="ghost" fullWidth>
Large Outline
</Button>
</div>
</div>
);
};
export const Default: Story = {
render: () => <Template color="default" />
};
export const Primary: Story = {
render: () => <Template color="primary" />
};
'use client';
import { extendVariants, Button as NextButton } from '@heroui/react';
const Button = extendVariants(NextButton, {
variants: {
size: {
sm: 'rounded-full font-light',
md: 'rounded-full font-light',
lg: 'rounded-full font-light'
},
color: {
default:
'border-[1.2px] bg-origin-border bg-background data-[hover=true]:border-transparent data-[hover=true]:before:bg-primary-800 data-[hover=true]:text-background data-[hover=true]:bg-[linear-gradient(90deg,#CC93D3_0%,#793BE0_100%)] before:content-[""] before:absolute before:inset-0 before:-z-10 dark:bg-foreground dark:data-[hover=true]:before:bg-primary-800 dark:data-[hover=true]:text-foreground data-[hover=true]:!duration-[600ms] dark:text-background',
primary:
'border-[1.2px] bg-origin-border border-transparent bg-[linear-gradient(90deg,#CC93D3_0%,#793BE0_100%)] before:content-[""] before:absolute before:inset-0 before:bg-primary-800/95 before:-z-10 data-[hover=true]:!duration-[500ms] data-[hover=true]:bg-primary-800 data-[hover=true]:border-primary-800'
},
variant: {
ghost:
'dark:text-foreground data-[hover=true]:before:bg-primary-800 before:bg-background'
}
},
defaultVariants: {
color: 'primary',
size: 'lg'
}
});
export default Button;
export { default } from './Button';
export * from './Button';
import {
CheckboxProps,
extendVariants,
Checkbox as HeroUICheckBox
} from '@heroui/react';
interface ICheckBoxProps extends CheckboxProps {}
const HeroCheckBox = extendVariants(HeroUICheckBox, {
defaultVariants: {
size: 'lg',
radius: 'none',
color: 'primary'
}
});
const CheckBox: React.FC<ICheckBoxProps> = ({ children, ...rest }) => {
return (
<HeroCheckBox
{...rest}
ref={(rest.ref as any) || null}
classNames={{
label: 'text-sm ',
icon: 'text-white bg-primary',
wrapper: `before:!border-[1px] before:border-black dark:before:border-white before:!rounded-[5px] !overflow-hidden
!rounded-[5px] after:bg-primary
${rest.isInvalid && 'before:!border-danger'} ${rest.classNames?.wrapper}`,
hiddenInput: 'overflow-hidden',
base: 'flex items-end'
}}>
{children}
</HeroCheckBox>
);
};
export default CheckBox;
import type { Meta, StoryObj } from '@storybook/react';
import CheckBoxComponent from './CheckBox';
const meta: Meta<typeof CheckBoxComponent> = {
title: 'Base/CheckBox',
component: CheckBoxComponent,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
export const CheckBox: Story = {
render: () => (
<CheckBoxComponent>
I have read and understood the Privacy Policy
</CheckBoxComponent>
)
};
export { default } from './CheckBox';
export * from './CheckBox';
import type { Meta, StoryObj } from '@storybook/react';
import IconComponent from './Icon';
import type { IconProps } from './Icon';
const meta: Meta<typeof IconComponent> = {
title: 'Base/Icon',
component: IconComponent,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
const icons: Array<IconProps['name']> = [
'global',
'facebook',
'instagram',
'x',
'tiktok',
'close',
'linkedin',
'menu',
'search',
'youtube',
'chat',
'up-arrow',
'down-arrow',
'left-arrow',
'right-arrow',
'phone',
'email',
'scroll',
'location',
'play',
'long-left-arrow',
'long-right-arrow',
'chevron-down',
'chevron-up',
'small-right-arrow',
'calendar',
'book',
'tick',
'form',
'tower',
'area',
'office',
'email-light',
'phone-light',
'location-pin',
'residence',
'store',
'download',
'forward-arrow',
'basement'
];
export const Icon: Story = {
render: () => (
<div className="flex gap-5 text-lg text-center flex-wrap">
{icons.map((name) => (
<div key={name}>
<IconComponent name={name} />
<p className="text-sm">{name}</p>
</div>
))}
</div>
)
};
import cn from '@/lib/merge-clsx';
import styles from './styles.module.css';
export interface IconProps extends React.HTMLAttributes<HTMLElement> {
name:
| 'global'
| 'facebook'
| 'instagram'
| 'x'
| 'tiktok'
| 'close'
| 'linkedin'
| 'menu'
| 'search'
| 'youtube'
| 'chat'
| 'up-arrow'
| 'down-arrow'
| 'left-arrow'
| 'right-arrow'
| 'phone'
| 'email'
| 'scroll'
| 'location'
| 'play'
| 'long-left-arrow'
| 'long-right-arrow'
| 'chevron-down'
| 'chevron-up'
| 'small-right-arrow'
| 'calendar'
| 'book'
| 'tick'
| 'form'
| 'tower'
| 'area'
| 'office'
| 'email-light'
| 'location-pin'
| 'phone-light'
| 'residence'
| 'store'
| 'download'
| 'forward-arrow'
| 'basement';
}
const Icon: React.FC<IconProps> = ({ name, className, ...props }) => {
const classNames = cn(styles.icon, {
[styles[`icon-${name}`]]: styles[`icon-${name}`],
[className as string]: className
});
return <i className={classNames} {...props}></i>;
};
export default Icon;
{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M765.893 1024c-41.997 0-75.348-33.351-75.348-75.348 0-19.763 7.412-38.292 20.999-51.88l11.117-11.117h-437.268l11.117 11.117c13.588 13.588 20.999 30.88 20.999 51.88 0 41.997-34.586 75.348-75.348 75.348-41.997 0-75.348-33.351-75.348-75.348 0-19.763 7.412-38.292 20.999-51.88l11.117-11.117h-82.76c-6.176 0-11.117-4.941-11.117-11.117v-358.215c1.235-213.694 170.46-389.095 385.39-397.741h6.176v-107.465c0-6.176 4.941-11.117 11.117-11.117s11.117 4.941 11.117 11.117v106.229h6.176c214.928 9.882 382.919 184.048 382.919 397.741v359.449c0 6.176-4.941 11.117-11.117 11.117h-82.76l11.117 11.117c13.588 13.588 20.999 30.88 20.999 51.88-4.941 41.997-38.292 75.348-80.29 75.348zM767.129 898.006c-28.41 0-50.644 22.234-50.644 50.644s23.469 50.644 50.644 50.644c28.41 0 50.644-22.234 50.644-50.644s-22.234-50.644-50.644-50.644zM240.923 898.006c-28.41 0-50.644 22.234-50.644 50.644s23.469 50.644 50.644 50.644c28.41 0 50.644-22.234 50.644-50.644s-22.234-50.644-50.644-50.644zM504.026 140.816c-208.752 0-377.978 167.991-377.978 375.507v348.332h754.721v-348.332c0-207.518-169.226-375.507-376.743-375.507zM249.57 791.778c-28.41 0-51.88-23.469-51.88-51.88v-284.101c0-28.41 23.469-51.88 51.88-51.88h165.52v-45.703c0-19.763 16.058-35.822 35.822-35.822h106.229c19.763 0 35.822 16.058 35.822 35.822v45.703h164.284c28.41 0 51.88 23.469 51.88 51.88v284.101c0 28.41-23.469 51.88-51.88 51.88h-507.677zM685.603 768.309h71.643c16.058 0 28.41-12.352 28.41-28.41v-284.101c0-16.058-12.352-28.41-28.41-28.41h-71.643v340.922zM348.388 768.309h312.512v-342.156h-312.512v342.156zM250.806 426.152c-16.058 0-28.41 12.352-28.41 28.41v284.101c0 16.058 12.352 28.41 28.41 28.41h74.114v-340.922h-74.114zM450.912 344.627c-6.176 0-12.352 6.176-12.352 12.352v45.703h130.933v-45.703c0-6.176-6.176-12.352-12.352-12.352h-106.229z"],"width":1013,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["tower"],"grid":32},"attrs":[{}],"properties":{"order":237,"id":0,"name":"residence","prevSize":32,"code":59676},"setIdx":1,"setId":9,"iconIdx":0},{"icon":{"paths":["M989.933 1024h-875.866c-5.878 0-10.581-4.703-10.581-10.581v-491.426c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v482.020h853.529v-482.020c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v492.601c1.176 4.703-3.527 9.405-9.405 9.405z","M474.995 1024c-5.878 0-10.581-4.703-10.581-10.581v-523.168c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v524.344c0 4.703-4.703 9.405-10.581 9.405z","M397.401 792.395c-5.878 0-10.581-4.703-10.581-10.581v-25.864c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v25.864c0 5.878-4.703 10.581-10.581 10.581z","M860.611 947.582c-2.352 0-5.878-1.176-7.054-3.527-4.703-4.703-4.703-10.581 0-15.283l51.729-51.729c4.703-4.703 10.581-4.703 15.283 0s4.703 10.581 0 15.283l-51.729 51.729c-2.352 2.352-5.878 3.527-8.229 3.527z","M732.464 947.582c-2.352 0-5.878-1.176-7.054-3.527-4.703-4.703-4.703-10.581 0-15.283l179.876-179.876c4.703-4.703 10.581-4.703 15.283 0s4.703 10.581 0 15.283l-181.052 179.876c-2.352 2.352-4.703 3.527-7.054 3.527z","M964.069 536.102c-45.85 0-84.647-27.040-103.458-65.837-17.635 38.797-57.607 65.837-103.458 65.837s-84.647-27.040-103.458-65.837c-17.635 38.797-57.607 65.837-103.458 65.837s-84.647-27.040-103.458-65.837c-17.635 38.797-57.607 65.837-103.458 65.837s-84.647-27.040-103.458-65.837c-17.635 38.797-57.607 65.837-103.458 65.837-62.31 0-114.039-50.553-114.039-114.039v-103.458c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v103.458c0 50.553 41.148 92.877 92.877 92.877s92.877-41.148 92.877-92.877c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581c0 50.553 41.148 92.877 92.877 92.877s92.877-41.148 92.877-92.877c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581c0 50.553 41.148 92.877 92.877 92.877s92.877-41.148 92.877-92.877c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581c0 50.553 41.148 92.877 92.877 92.877s92.877-41.148 92.877-92.877c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581c0 50.553 41.148 92.877 92.877 92.877s92.877-41.148 92.877-92.877v-103.458c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v103.458c-1.176 62.31-51.729 114.039-114.039 114.039z","M1066.351 330.361c-3.527 0-7.054-1.176-9.405-4.703l-99.931-149.309h-811.205l-99.931 149.309c-3.527 4.703-9.405 5.878-14.108 2.352s-5.878-9.405-2.352-14.108l103.458-154.011c2.352-3.527 4.703-4.703 8.229-4.703h822.961c3.527 0 7.054 2.352 8.229 4.703l103.458 154.011c3.527 4.703 2.352 11.757-2.352 14.108-2.352 1.176-4.703 2.352-7.054 2.352z","M964.069 175.174c-5.878 0-10.581-4.703-10.581-10.581v-143.431h-802.975v143.431c0 5.878-4.703 10.581-10.581 10.581s-10.581-4.703-10.581-10.581v-154.011c0-5.878 4.703-10.581 10.581-10.581h822.961c5.878 0 10.581 4.703 10.581 10.581v154.011c1.176 5.878-3.527 10.581-9.405 10.581z","M449.129 432.643c-5.878 0-10.581-4.703-10.581-10.581v-25.864c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v25.864c0 5.878-4.703 10.581-10.581 10.581z","M243.389 432.643c-5.878 0-10.581-4.703-10.581-10.581v-25.864c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v25.864c0 5.878-4.703 10.581-10.581 10.581z","M654.871 432.643c-5.878 0-10.581-4.703-10.581-10.581v-25.864c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v25.864c0 5.878-4.703 10.581-10.581 10.581z","M860.611 432.643c-5.878 0-10.581-4.703-10.581-10.581v-25.864c0-5.878 4.703-10.581 10.581-10.581s10.581 4.703 10.581 10.581v25.864c0 5.878-4.703 10.581-10.581 10.581z","M1066.351 330.361h-1028.702c-5.878 0-10.581-4.703-10.581-10.581s4.703-10.581 10.581-10.581h1028.702c5.878 0 10.581 4.703 10.581 10.581s-4.703 10.581-10.581 10.581z","M114.067 1024h-102.283c-5.878 0-10.581-4.703-10.581-10.581s4.703-10.581 10.581-10.581h103.458c5.878 0 10.581 4.703 10.581 10.581s-5.878 10.581-11.757 10.581z","M1092.216 1024h-103.458c-5.878 0-10.581-4.703-10.581-10.581s4.703-10.581 10.581-10.581h103.458c5.878 0 10.581 4.703 10.581 10.581s-4.703 10.581-10.581 10.581z"],"width":1104,"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["store"],"grid":32},"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"properties":{"order":238,"id":1,"name":"store","prevSize":32,"code":59677},"setIdx":1,"setId":9,"iconIdx":1},{"icon":{"paths":["M915.54 648.979c-16.313 0-29.533 13.219-29.533 29.533v130.266c0 63.504-49.853 115.166-111.118 115.166l-604.707 0.037c-61.267 0-111.115-51.659-111.115-115.163v-130.266c0-16.318-13.218-29.537-29.535-29.537s-29.535 13.219-29.535 29.537v130.266c0 96.098 76.329 174.236 170.148 174.236h604.709c93.824 0 170.149-78.172 170.149-174.236v-130.266c0-16.318-13.219-29.537-29.537-29.537l0.075-0.037z","M451.435 695.868c11.025 11.49 30.868 11.532 41.893 0l167.407-168.353c26.631-28.477-13.453-68.525-41.893-41.655l-116.93 117.591v-532.97c0-16.318-13.219-29.535-29.533-29.535-16.318 0-29.537 13.218-29.537 29.535v532.97l-116.929-117.591c-28.358-26.83-68.562 13.101-41.891 41.655l167.412 168.353z"],"width":945,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["download"],"grid":32},"attrs":[],"properties":{"order":240,"id":2,"name":"download","prevSize":32,"code":59678},"setIdx":1,"setId":9,"iconIdx":2},{"icon":{"paths":["M-0.003 947.026c0-5.591 4.473-10.064 10.064-10.064h979.642c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-979.642c-5.591 0-10.064-4.473-10.064-10.064z","M928.197 885.518c4.473-4.473 10.064-4.473 14.539 0l54.797 54.797c2.237 2.237 3.355 4.473 3.355 6.71s-1.118 5.591-3.355 6.71l-54.797 54.797c-4.473 4.473-10.064 4.473-14.539 0s-4.473-10.064 0-14.539l46.969-46.969-46.969-46.969c-4.473-4.473-4.473-10.064 0-14.539z","M64.86 12.115c5.591 0 10.064 4.473 10.064 10.064v979.642c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-979.642c0-5.591 4.473-10.064 10.064-10.064z","M64.86 12.115c2.237 0 5.591 1.118 6.71 3.355l54.797 54.797c4.473 4.473 4.473 10.064 0 14.539s-10.064 4.473-14.539 0l-46.969-48.088-46.969 46.969c-4.473 4.473-10.064 4.473-14.539 0s-4.473-10.064 0-14.539l54.797-54.797c1.118-1.118 3.355-2.237 6.71-2.237z","M107.355 22.181c0-5.591 4.473-10.064 10.064-10.064h20.13c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-20.13c-5.591 0-10.064-4.473-10.064-10.064zM166.626 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-4.473 0-10.064-4.473-10.064-10.064zM247.145 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM326.545 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM405.945 22.181c0-5.591 4.473-10.064 10.064-10.064h39.141c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-4.473 0-8.946-4.473-8.946-10.064zM485.345 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c4.473 0 8.946 4.473 8.946 10.064s-4.473 10.064-10.064 10.064h-40.26c-4.473 0-8.946-4.473-8.946-10.064zM564.745 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM644.146 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM723.546 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM802.946 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM882.346 22.181c0-5.591 4.473-10.064 10.064-10.064h40.26c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-40.26c-5.591 0-10.064-4.473-10.064-10.064zM961.747 22.181c0-5.591 4.473-10.064 10.064-10.064h20.13c5.591 0 10.064 4.473 10.064 10.064s-4.473 10.064-10.064 10.064h-20.13c-5.591 0-10.064-4.473-10.064-10.064z","M142.023 176.508l46.969-46.969h-29.076l-17.893 17.893z","M987.468 59.085c5.591 0 10.064 4.473 10.064 10.064v20.13c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-20.13c0-5.591 4.473-10.064 10.064-10.064zM987.468 119.474c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 201.111c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 282.748c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 363.266c5.591 0 10.064 4.473 10.064 10.064v41.378c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-6.71 4.473-11.183 10.064-11.183zM987.468 444.903c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 526.54c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 608.177c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 688.696c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 770.332c5.591 0 10.064 4.473 10.064 10.064v40.26c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-40.26c0-5.591 4.473-10.064 10.064-10.064zM987.468 851.969c5.591 0 10.064 4.473 10.064 10.064v20.13c0 5.591-4.473 10.064-10.064 10.064s-10.064-4.473-10.064-10.064v-20.13c0-5.591 4.473-10.064 10.064-10.064z","M142.023 318.533l188.995-188.995h-29.076l-159.919 159.919z","M142.023 460.56l331.021-331.021h-27.958l-303.063 303.063z","M142.023 602.585l473.046-473.046h-27.958l-445.088 445.088z","M142.023 745.729l616.191-616.191h-29.076l-587.115 587.115z","M184.519 845.259l715.721-715.721h-27.958l-715.721 715.721z","M326.545 845.259l587.115-587.115v-27.958l-615.072 615.072z","M469.688 845.259l443.97-443.97v-29.076l-473.046 473.046z","M611.715 845.259l301.945-301.945v-29.076l-331.021 331.021z","M753.74 845.259l159.919-159.919v-27.958l-187.876 187.876z","M895.766 845.259l17.893-17.893v-27.958l-45.851 45.851z"],"width":1002,"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["basement"],"grid":32},"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"properties":{"order":233,"id":3,"name":"basement","prevSize":32,"code":59679},"setIdx":1,"setId":9,"iconIdx":3},{"icon":{"paths":["M131.831 17.385h1158.341c36.311 0 69.271 14.729 93.136 38.417s38.703 56.406 38.703 92.448v727.434c0 36.039-14.838 68.758-38.703 92.443-23.865 23.692-56.826 38.42-93.136 38.42l-1158.341 0.068c-36.311 0-69.271-14.727-93.137-38.42-23.866-23.686-38.704-56.405-38.704-92.443v-727.504c0-36.042 14.839-68.759 38.704-92.448 23.934-23.689 56.894-38.415 93.137-38.415zM72.407 927.476c3.214-3.939 6.77-7.735 10.599-11.469l410.517-404.005-410.517-403.933c-3.83-3.733-7.316-7.602-10.599-11.471-12.241 13.847-19.764 31.969-19.764 51.723v727.431c0 19.685 7.454 37.875 19.764 51.724zM119.523 70.608l0.479 0.475 520.053 511.652c9.577 9.373 20.242 16.495 31.934 21.114 11.766 4.68 24.824 7.123 39.118 7.123s27.353-2.375 39.118-7.123c11.692-4.686 22.357-11.747 31.934-21.114l520.528-512.127c-4.031-0.611-8.137-0.95-12.304-0.95h-1158.552c-4.171 0-8.273 0.339-12.308 0.95zM1349.673 96.537c-3.215 3.937-6.77 7.738-10.603 11.471l-410.513 404.003 410.513 403.934c3.691 3.667 7.252 7.537 10.535 11.536 12.304-13.843 19.76-32.039 19.76-51.786l0.068-727.434c0-19.752-7.524-37.877-19.76-51.725zM1302.554 953.357l-0.476-0.476-410.853-404.144-72.14 70.995c-14.635 14.394-31.117 25.25-49.375 32.582-18.19 7.264-37.82 11-58.674 11s-40.484-3.667-58.674-11c-18.257-7.333-34.808-18.19-49.369-32.582l-72.146-70.995-411.328 404.688c4.035 0.612 8.138 0.946 12.378 0.946h1158.341c4.167 0 8.278-0.34 12.316-1.014z"],"width":1422,"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"4","strokeWidth":28.444444444444443}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["email-light"],"grid":32},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"4","strokeWidth":28.444444444444443}],"properties":{"order":203,"id":4,"name":"email-light","prevSize":32,"code":59671},"setIdx":1,"setId":9,"iconIdx":4},{"icon":{"paths":["M394.002 1000.001c-4.169 0-8.34-1.39-11.124-5.564l-285.013-372.6c-101.492-133.472-101.492-318.383 0-451.854 70.907-93.151 179.35-145.984 296.133-145.984s225.233 52.833 296.137 145.984c101.491 133.471 101.491 318.382 0 451.854l-285.013 372.6c-2.78 2.78-6.954 5.564-11.128 5.564zM394.002 51.812c-108.442 0-208.545 48.66-273.889 134.86-94.541 123.738-94.541 294.747 0 418.484l273.889 357.308 273.894-357.308c94.541-123.738 94.541-294.744 0-418.484-65.343-84.809-165.448-134.86-273.894-134.86z","M393.84 619.025c-122.347 0-222.45-100.105-222.45-222.45 0-122.347 100.103-222.449 222.45-222.449 122.345 0 222.45 100.102 222.45 222.449 0 122.345-100.105 222.45-222.45 222.45zM393.84 201.929c-107.055 0-194.645 87.589-194.645 194.644s87.589 194.643 194.645 194.643c107.055 0 194.643-87.588 194.643-194.643s-87.588-194.644-194.643-194.644z"],"width":788,"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":39.38461538461539},{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":39.38461538461539}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["location-pin"],"grid":32},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":39.38461538461539},{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":39.38461538461539}],"properties":{"order":204,"id":5,"name":"location-pin","prevSize":32,"code":59672},"setIdx":1,"setId":9,"iconIdx":5},{"icon":{"paths":["M551.397 209.871c2.773-15.742 17.792-26.379 33.771-23.72 68.604 11.7 131.132 44.036 180.774 93.603 49.638 49.567 82.022 111.898 93.739 180.505 2.56 15.953-7.987 31.164-24.073 33.715-1.707 0.213-3.196 0.427-5.005 0.427-14.063 0-26.419-9.89-28.766-24.252-9.694-56.586-36.322-108.067-77.44-149.125-41.122-41.058-92.681-67.862-149.35-77.329-16.085-2.765-26.526-18.082-23.65-33.824zM950.015 753.405c21.837 21.594 33.344 47.334 33.344 74.138 0 26.59-11.294 52.544-32.704 74.773-9.267 9.681-18.854 19.042-28.122 27.87-13.636 13.188-26.633 25.527-37.922 39.142-0.213 0.427-0.64 0.64-0.853 1.062-32.917 35.635-74.889 53.611-124.847 53.611-4.369 0-9.054-0.213-13.636-0.427-74.249-4.787-140.719-32.653-190.468-56.162-130.278-62.861-244.367-152.102-339.174-265.169-78.083-93.922-130.493-181.461-165.54-275.916-14.274-38.505-32.916-97.219-27.696-160.401 3.515-39.143 19.281-72.861 46.978-100.516l74.035-74.563c21.625-20.742 47.191-31.804 73.609-31.804s51.558 11.062 72.544 31.804c14.061 12.977 27.697 26.804 40.692 40.207 6.498 6.914 13.422 13.828 20.133 20.529l59.121 59.034c45.488 45.419 45.488 104.133 0 149.551-6.072 6.063-12.144 12.339-18.216 18.402-15.979 16.168-32.49 33.080-50.173 49.247 13.209 29.146 31.425 57.971 58.482 92.113 55.817 68.501 114.087 121.472 178.109 162.103 6.285 3.938 13.636 7.552 21.414 11.49 5.431 2.765 11.076 5.636 16.614 8.614l68.39-68.075c21.837-21.807 47.403-33.293 74.035-33.293 26.846 0 52.198 11.699 73.182 33.506l118.669 119.13zM908.47 794.25l-119.731-119.556c-6.711-7.339-17.792-15.744-31.215-15.744-13.632 0-25.353 8.832-32.704 16.171l-74.031 73.924c-3.729 3.721-14.916 14.891-32.917 14.891-7.138 0-14.063-1.702-21.414-5.423-0.849-0.427-1.702-1.067-2.556-1.489-6.285-3.938-13.632-7.552-21.41-11.49-8.627-4.361-17.792-8.828-26.633-14.464-69.453-43.823-132.41-101.154-192.17-174.656l-0.213-0.213c-32.916-41.694-54.541-76.689-69.881-113.916l-0.639-1.916c-3.941-12.339-7.35-30.421 11.292-49.036 0.213-0.425 0.639-0.638 1.065-1.064 18.855-16.806 36.112-34.144 54.328-52.758 6.285-6.063 12.357-12.338 18.642-18.614 22.903-22.869 22.903-44.036 0-67.011l-59.121-59.034c-6.924-7.126-13.848-14.040-20.559-20.954-13.209-13.615-25.779-26.379-38.988-38.717l-0.639-0.638c-6.924-6.914-18.003-15.104-31.638-15.104-11.079 0-22.264 5.425-32.916 15.317l-73.821 73.712c-18.003 17.976-27.697 38.93-29.827 64.139-3.196 39.569 4.155 81.477 24.288 135.299 32.703 88.176 82.024 170.292 155.846 259.107 89.375 106.688 196.966 190.822 319.467 249.963 44.847 21.38 104.503 46.481 168.845 50.526 3.196 0.213 6.711 0.213 9.907 0.213 33.766 0 59.546-11.063 81.382-34.359 13.423-15.74 27.699-29.781 41.758-43.183 9.271-9.041 18.005-17.34 26.419-26.381 22.050-22.869 22.050-45.525-0.213-67.541zM1045.037 451.64c-19.281-112.853-72.546-215.497-154.355-297.187-81.707-81.69-184.61-134.766-297.527-154.019-15.765-2.766-30.784 7.978-33.553 23.72-2.556 15.955 7.987 30.953 24.073 33.718 100.881 17.125 192.811 64.884 265.997 137.638 73.182 73.074 120.798 164.868 137.843 265.597 2.342 14.255 14.699 24.252 28.762 24.252 1.702 0 3.196-0.213 5.005-0.427 15.765-2.338 26.633-17.442 23.757-33.293z"],"width":1067,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["phone-light"],"grid":32},"attrs":[{}],"properties":{"order":205,"id":6,"name":"phone-light","prevSize":32,"code":59673},"setIdx":1,"setId":9,"iconIdx":6},{"icon":{"paths":["M863.146 875.583v-706.857c0-12.481 2.27-27.231 0-39.711-1.134-9.077-5.673-11.346-12.481-17.019-15.885-12.481-32.904-26.096-48.788-38.576-28.365-22.692-56.73-45.384-85.096-66.941-12.481-9.077-29.5 6.808-17.019 17.019 22.692 18.153 46.518 36.307 70.345 55.595 17.019 13.615 32.904 26.096 49.922 39.711 5.673 4.538 10.211 7.942 15.885 12.481 4.538 3.404 6.808 9.077 5.673 1.134-2.27-10.211-2.27 2.27-2.27 4.538v739.761c0 14.75 23.827 14.75 23.827-1.134v0z","M993.626 951.602v-605.878c0-12.481 2.27-27.231 0-39.711-1.134-9.077-5.673-11.346-12.481-17.019-15.885-12.481-14.75-11.346-30.634-23.827s-27.231-20.423-55.595-41.98c-12.481-9.077-29.5 6.808-17.019 17.019 22.692 18.153 28.365 21.557 39.711 30.634 17.019 13.615 15.885 11.346 32.904 24.961 5.673 4.538 10.211 7.942 15.885 12.481 4.538 3.404 6.808 9.077 5.673 1.134-2.27-10.211-2.27 2.27-2.27 4.538v658.069c0 15.885 23.827 15.885 23.827 0v-20.423z","M113.174 880.121v-534.397c0-12.481-2.27-27.231 0-39.711 1.134-9.077 5.673-11.346 12.481-17.019 15.885-12.481 14.75-11.346 30.634-23.827s27.231-20.423 55.595-41.98c12.481-9.077 29.5 6.808 17.019 17.019-22.692 18.153-28.365 21.557-39.711 30.634-17.019 13.615-15.885 11.346-32.904 24.961-5.673 4.538-10.211 7.942-15.885 12.481-4.538 3.404-6.808 9.077-5.673 1.134 2.27-10.211 2.27 2.27 2.27 4.538v587.724c0 15.885-23.827 15.885-23.827 0v-21.557z","M265.21 875.583v-776.068c-3.404 3.404-5.673 7.942-9.077 11.346 132.748-24.961 265.497-48.788 398.245-73.749 19.289-3.404 37.442-6.808 56.73-10.211-4.538-3.404-10.211-7.942-14.75-11.346v849.817c0 15.885 23.827 15.885 23.827 0v-850.952c0-7.942-7.942-12.481-14.75-11.346-133.883 24.961-266.632 49.922-398.245 73.749-19.289 3.404-37.442 6.808-56.73 10.211-4.538 1.134-9.077 6.808-9.077 11.346v777.202c-1.134 15.885 23.827 15.885 23.827 0z","M365.056 796.161v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 14.75 23.827 0z","M434.266 783.68h-81.692c-15.885 0-15.885 23.827 0 23.827h81.692c15.885 0 15.885-23.827 0-23.827z","M365.056 665.681v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 15.885 23.827 15.885 23.827 0z","M353.71 680.432c27.231-3.404 53.326-5.673 80.557-9.077 14.75-1.134 15.885-26.096 0-23.827l-80.557 9.077c-14.75 1.134-15.885 26.096 0 23.827z","M365.056 536.337v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 15.885 23.827 0z","M353.71 551.087c27.231-3.404 53.326-5.673 80.557-9.077 14.75-1.134 15.885-26.096 0-23.827-27.231 3.404-53.326 5.673-80.557 9.077-14.75 1.134-15.885 24.961 0 23.827z","M365.056 406.993v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 15.885 23.827 0z","M357.114 420.607c26.096-4.538 53.326-9.077 79.422-13.615 14.75-2.27 9.077-26.096-6.808-22.692-26.096 4.538-53.326 9.077-79.422 13.615-14.75 2.27-7.942 24.961 6.808 22.692z","M365.056 276.513v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 15.885 23.827 15.885 23.827 0z","M357.114 291.263c26.096-4.538 53.326-9.077 79.422-13.615 14.75-2.27 9.077-26.096-6.808-22.692l-79.422 13.615c-14.75 2.27-7.942 24.961 6.808 22.692z","M542.053 796.161v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 14.75 23.827 0z","M611.264 783.68h-81.692c-15.885 0-15.885 23.827 0 23.827h81.692c15.885 0 15.885-23.827 0-23.827z","M542.053 653.201v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 14.75 23.827 0z","M530.708 666.817c27.231-3.404 53.326-5.673 80.557-9.077 14.75-1.134 15.885-26.096 0-23.827l-80.557 9.077c-15.885 2.27-15.885 26.096 0 23.827z","M542.053 524.991v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 15.885 23.827 15.885 23.827 0z","M530.708 539.741c27.231-3.404 53.326-5.673 80.557-9.077 14.75-1.134 15.885-26.096 0-23.827-27.231 3.404-53.326 5.673-80.557 9.077-15.885 2.27-15.885 26.096 0 23.827z","M542.053 385.435v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 14.75 23.827 14.75 23.827 0z","M534.111 399.050c26.096-4.538 53.326-9.077 79.422-13.615 14.75-2.27 9.077-26.096-6.808-22.692-26.096 4.538-53.326 9.077-79.422 13.615-14.75 2.27-9.077 24.961 6.808 22.692z","M542.053 254.956v-40.846c0-15.885-23.827-15.885-23.827 0v40.846c0 15.885 23.827 15.885 23.827 0z","M534.111 269.706l79.422-13.615c14.75-2.27 9.077-26.096-6.808-22.692-26.096 4.538-53.326 9.077-79.422 13.615-14.75 2.27-9.077 24.961 6.808 22.692z","M574.957 994.716v-78.288c0-6.808-5.673-12.481-12.481-12.481-56.73 1.134-112.325 3.404-169.056 4.538-6.808 0-12.481 5.673-12.481 12.481v73.749c0 15.885 23.827 15.885 23.827 0v-73.749c-4.538 4.538-7.942 7.942-12.481 12.481 56.73-1.134 112.325-3.404 169.056-4.538-4.538-4.538-7.942-7.942-12.481-12.481v78.288c2.27 14.75 26.096 15.885 26.096 0z","M879.031 1020.812h110.057c15.885 0 15.885-23.827 0-23.827h-110.057c-15.885 0-15.885 23.827 0 23.827z","M342.363 1020.812h395.976c15.885 0 15.885-23.827 0-23.827h-395.976c-15.885 0-15.885 23.827 0 23.827z","M11.060 1020.812h192.883c15.885 0 15.885-23.827 0-23.827h-192.883c-14.75 0-14.75 23.827 0 23.827z","M734.936 952.736c-40.846-26.096-86.23 17.019-71.48 60.134 4.538 14.75 28.365 7.942 22.692-6.808-7.942-22.692 12.481-47.654 36.307-32.904 13.615 7.942 26.096-12.481 12.481-20.423v0z","M823.435 937.986c10.211-6.808 21.557 2.27 20.423 13.615-1.134 15.885 22.692 15.885 23.827 0 1.134-29.5-30.634-49.922-56.73-35.173-12.481 9.077 0 29.5 12.481 21.557v0z","M859.742 964.082c31.769-12.481 58.999 12.481 56.73 45.384-1.134 15.885 22.692 14.75 23.827 0 4.538-46.518-40.846-86.23-86.23-68.076-14.75 4.538-9.077 28.365 5.673 22.692v0z","M739.474 958.409c-5.673-19.289 0-40.846 19.289-49.922s39.711 2.27 47.654 21.557c5.673 14.75 28.365 7.942 22.692-6.808-12.481-30.634-43.114-51.057-76.018-38.576-32.904 11.346-46.518 47.654-36.307 79.422 4.538 15.885 27.231 9.077 22.692-5.673v0z","M740.609 961.813c0-1.134 0-3.404-1.134-4.538 0-1.134-1.134-2.27-2.27-3.404s-2.27-2.27-3.404-2.27c-1.134-1.134-3.404-1.134-4.538-1.134s-2.27 0-3.404 0-3.404 1.134-5.673 3.404c-1.134 1.134-1.134 1.134-2.27 2.27-1.134 2.27-1.134 3.404-1.134 5.673 0 1.134 0 3.404 1.134 4.538 0 1.134 1.134 2.27 2.27 3.404s2.27 2.27 3.404 2.27c1.134 1.134 3.404 1.134 4.538 1.134s2.27 0 3.404 0 3.404-1.134 5.673-3.404l2.27-2.27c0-1.134 1.134-3.404 1.134-5.673z","M256.134 969.755c9.077-4.538 19.289-2.27 26.096 5.673 7.942 9.077 7.942 19.289 4.538 30.634-4.538 14.75 18.153 20.423 22.692 6.808 13.615-40.846-24.961-82.826-65.807-62.403-13.615 5.673-1.134 26.096 12.481 19.289v0z","M98.424 1008.331c-2.27-31.769 22.692-58.999 55.595-45.384 14.75 5.673 20.423-17.019 6.808-22.692-45.384-19.289-89.634 22.692-85.096 69.211 0 14.75 23.827 14.75 22.692-1.134z","M171.039 948.198c14.75-38.576 63.537-28.365 66.941 11.346 1.134 14.75 24.961 15.885 23.827 0-2.27-28.365-19.289-53.326-48.788-58.999-30.634-5.673-55.595 14.75-65.807 41.98-4.538 14.75 18.153 20.423 23.827 5.673z","M235.711 961.813c0 1.134 0 3.404 1.134 4.538 0 1.134 1.134 2.27 2.27 3.404s2.27 2.27 3.404 2.27c1.134 1.134 3.404 1.134 4.538 1.134s2.27 0 3.404 0c2.27-1.134 3.404-1.134 5.673-3.404 1.134-1.134 1.134-1.134 2.27-2.27 1.134-2.27 1.134-3.404 1.134-5.673 0-1.134 0-3.404-1.134-4.538 0-1.134-1.134-2.27-2.27-3.404s-2.27-2.27-3.404-2.27c-1.134-1.134-3.404-1.134-4.538-1.134s-2.27 0-3.404 0-3.404 1.134-5.673 3.404l-2.27 2.27c-1.134 1.134-1.134 3.404-1.134 5.673z"],"width":1001,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["tower"],"grid":32},"attrs":[],"properties":{"order":206,"id":7,"name":"tower","prevSize":32,"code":59648},"setIdx":1,"setId":9,"iconIdx":7},{"icon":{"paths":["M1017.057 967.937h-1001.119c-5.721 0-10.297-4.576-10.297-10.297s4.576-10.297 10.297-10.297h1002.262c5.721 0 10.297 4.576 10.297 10.297s-5.721 10.297-11.442 10.297z","M962.139 1023.999c-2.289 0-5.721-1.144-6.865-3.432-4.576-4.576-4.576-10.297 0-14.874l48.054-48.054-49.197-48.054c-4.576-4.576-4.576-10.297 0-14.874s10.297-4.576 14.874 0l56.062 56.062c2.289 2.289 3.432 4.576 3.432 6.865s-1.144 5.721-3.432 6.865l-56.062 56.062c-2.289 2.289-4.576 3.432-6.865 3.432z","M70.858 1023.999c-5.721 0-10.297-4.576-10.297-10.297v-1002.262c0-5.721 4.576-10.297 10.297-10.297s10.297 4.576 10.297 10.297v1002.262c0 5.721-4.576 10.297-10.297 10.297z","M15.94 77.8c-3.432 0-5.721-1.144-8.008-3.432-3.432-3.432-3.432-10.297 0-14.874l56.062-56.062c4.576-4.576 10.297-4.576 14.874 0l56.062 56.062c4.576 4.576 4.576 10.297 0 14.874s-10.297 4.576-14.874 0l-49.197-48.054-48.054 48.054c-2.289 2.289-4.576 3.432-6.865 3.432z","M1019.345 73.223h-831.786c-5.721 0-10.297-4.576-10.297-10.297s4.576-10.297 10.297-10.297h831.786c5.721 0 10.297 4.576 10.297 10.297s-4.576 10.297-10.297 10.297z","M973.58 860.387c-5.721 0-10.297-4.576-10.297-10.297v-831.786c0-5.721 4.576-10.297 10.297-10.297s10.297 4.576 10.297 10.297v831.786c0 5.721-4.576 10.297-10.297 10.297z","M438.126 577.786h-36.612v-163.611h29.747l2.289 22.883c10.297-16.018 29.747-27.46 54.918-27.46 24.026 0 41.189 11.442 50.342 30.892 9.153-17.162 29.747-30.892 56.062-30.892 34.324 0 56.062 24.026 56.062 59.495v108.693h-36.612v-107.548c0-18.306-11.442-29.747-28.603-29.747-25.171 0-41.189 16.018-41.189 37.757v99.54h-36.612v-107.548c0-18.306-11.442-29.747-28.603-29.747-25.171 0-41.189 16.018-41.189 37.757v99.54z","M726.447 366.121c0 24.026-32.036 24.026-35.468 40.044h34.324v11.442h-48.054v-6.865c0-27.46 36.612-26.315 36.612-44.621 0-6.865-4.576-11.442-11.442-11.442-8.008 0-13.729 4.576-13.729 14.874h-12.586c1.144-16.018 12.586-25.171 26.315-25.171s24.026 8.008 24.026 21.739z"],"width":1035,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["area"],"grid":32},"attrs":[],"properties":{"order":207,"id":8,"name":"area","prevSize":32,"code":59650,"codes":[59650]},"setIdx":1,"setId":9,"iconIdx":8},{"icon":{"paths":["M136.997 597.333c-6.995 0-12.59-5.595-12.59-12.59v-386.098c0-6.995 5.595-12.59 12.59-12.59s12.59 5.595 12.59 12.59v386.098c0 6.995-5.595 12.59-12.59 12.59z","M630.811 320.349h-226.623c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h214.033v-269.989h-576.349c-5.595 0-9.792 4.196-9.792 9.792v260.197h191.651c6.995 0 12.59 5.595 12.59 12.59s-6.995 12.59-13.989 12.59h-204.241c-6.995 0-12.59-5.595-12.59-12.59v-272.787c0-19.585 15.389-34.972 34.972-34.972h590.338c6.995 0 12.59 5.595 12.59 12.59v295.169c0 6.995-5.595 12.59-12.59 12.59z","M517.5 387.496c-6.995 0-12.59-5.595-12.59-12.59v-68.546c0-6.995 5.595-12.59 12.59-12.59s12.59 5.595 12.59 12.59v68.546c0 6.995-5.595 12.59-12.59 12.59z","M767.904 705.049h-250.404c-6.995 0-12.59-5.595-12.59-12.59v-135.693c0-6.995 5.595-12.59 12.59-12.59s12.59 5.595 12.59 12.59v123.103h236.415c6.995 0 12.59 5.595 12.59 12.59s-4.196 12.59-11.191 12.59z","M1016.909 705.049h-68.546c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h55.956v-531.585c0-5.595-4.196-9.792-9.792-9.792h-363.715c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h362.316c19.585 0 34.972 15.389 34.972 34.972v544.175c1.399 6.995-4.196 12.59-11.191 12.59z","M994.527 1023.999h-317.552c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h317.552c5.595 0 9.792-4.196 9.792-9.792v-296.568c0-6.995 5.595-12.59 12.59-12.59s12.59 5.595 12.59 12.59v295.169c0 19.585-15.389 36.371-34.972 36.371z","M404.189 1023.999h-362.316c-19.585 0-34.972-15.389-34.972-34.972v-296.568c0-6.995 5.595-12.59 12.59-12.59h90.929c6.995 0 12.59 5.595 12.59 12.59s-5.595 12.59-12.59 12.59h-79.737v282.579c0 5.595 4.196 9.792 9.792 9.792h362.316c6.995 0 12.59 5.595 12.59 12.59s-4.196 13.989-11.191 13.989z","M676.974 1023.999h-90.929c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h78.339v-293.77h-373.508c-6.995 0-12.59-5.595-12.59-12.59s5.595-12.59 12.59-12.59h386.098c6.995 0 12.59 5.595 12.59 12.59v317.552c0 6.995-5.595 13.989-12.59 13.989z"],"width":1035,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["office"],"grid":32},"attrs":[],"properties":{"order":208,"id":9,"name":"office","prevSize":32,"code":59664},"setIdx":1,"setId":9,"iconIdx":9},{"icon":{"paths":["M5120 513.295l-852.582-493.978-1.502 985.343 854.084-491.365zM-0.131 590.792l4351.994 6.661 0.256-170.667-4351.989-6.661-0.261 170.667z"],"width":5120,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["Arrow 1 (1)"],"grid":32},"attrs":[],"properties":{"order":209,"id":10,"name":"long-right-arrow","prevSize":32,"code":59674},"setIdx":1,"setId":9,"iconIdx":10},{"icon":{"paths":["M304.778 22.826c-25.102 3.886-49.94 9.936-74.519 18.152-112.987 44.848-182.73 126.692-209.229 245.533-12.287 69.208-4.644 136.085 22.929 200.63 20.206 41.079 43.772 79.929 70.698 116.557 35.349 45.539 70.698 91.081 106.047 136.621-22.302 4.844-44.594 9.938-66.877 15.284-48.037 10.473-89.118 33.087-123.244 67.834-19.108 29.296-19.108 58.597 0 87.895 18.116 20.042 39.454 35.645 64.010 46.813 61.62 24.483 125.314 38.814 191.078 42.991 36.94 0 73.883 0 110.823 0 60.716-4.184 119.951-16.603 177.702-37.259 29.865-11.583 55.66-29.098 77.386-52.545 19.106-29.298 19.106-58.599 0-87.895-24.062-26.212-53.041-45.004-86.94-56.368-33.811-11.321-68.206-20.235-103.181-26.75 35.349-45.539 70.696-91.081 106.046-136.621 19.901-27.686 38.371-56.349 55.413-85.985 39.795-72.535 52.536-149.602 38.217-231.203-36.774-150.345-131.355-238.24-283.75-263.685-24.202 0-48.404 0-72.609 0zM339.173 61.041c121.132 5.642 208.71 62.328 262.73 170.058 38.991 98.967 30.713 193.868-24.84 284.704-13.538 21.347-27.55 42.365-42.036 63.055-65.074 83.847-129.719 167.919-193.943 252.221-58.397-77.841-117.949-154.907-178.656-231.203-21.8-28.941-42.18-58.878-61.144-89.805-49.065-82.22-58.619-168.843-28.662-259.865 49.875-117.784 138.725-180.84 266.552-189.165zM247.456 777.578c26.3 30.851 50.824 63.333 73.564 97.449 13.376 15.286 26.753 15.286 40.127 0 22.807-33.509 47.011-65.991 72.609-97.449 53.91 5.913 105.184 20.882 153.817 44.904 15.512 8.504 27.931 20.285 37.259 35.347 1.991 9.44 0.717 18.356-3.82 26.753-15.622 17.529-34.411 30.587-56.368 39.169-72.147 26.25-146.668 39.307-223.561 39.172-76.893 0.136-151.412-12.921-223.559-39.172-81.526-37.578-81.526-75.157 0-112.735 42.161-16.589 85.47-27.734 129.932-33.437z","M333.388 99.235c21.952-2.572 31.187 6.982 27.705 28.662-7.068 9.118-16.303 11.984-27.705 8.598-14.936-12.46-14.936-24.88 0-37.26z","M409.845 112.644c7.842-0.508 15.486 0.447 22.928 2.866 89.188 38.253 141.098 105.447 155.727 201.587 1.276 14.010 1.276 28.024 0 42.036-12.1 12.738-24.202 12.738-36.304 0-0.569-73.168-28.91-132.72-85.028-178.657-21.166-13.849-43.139-26.269-65.922-37.26-5.744-12.857-2.877-23.047 8.599-30.572z","M318.19 213.898c71.13-6.17 121.13 23.128 149.995 87.896 18.713 64.231 1.836 116.776-50.636 157.636-42.020 24.817-85.966 28.639-131.841 11.464-62.716-33.399-87.873-85.306-75.476-155.727 16.702-54.605 52.688-88.363 107.958-101.27zM322.012 254.023c-38.186 11.116-62.707 35.957-73.566 74.521-4.794 66.539 25.776 104.753 91.717 114.645 66.915-8.959 98.123-47.175 93.629-114.645-16.998-54.851-54.26-79.691-111.78-74.521z"],"width":667,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["Group 118"],"grid":32},"attrs":[],"properties":{"order":210,"id":11,"name":"location","prevSize":32,"code":59669,"codes":[59668]},"setIdx":1,"setId":9,"iconIdx":11},{"icon":{"paths":["M808.313 517.474l-808.419-466.742 0 933.483 808.419-466.741zM-0.105 598.318h80.842v-161.686h-80.842l0 161.686z"],"width":808,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"2431123312552552551":[]},"tags":["play"],"grid":32},"attrs":[],"properties":{"order":211,"id":12,"name":"play","prevSize":32,"code":59670},"setIdx":1,"setId":9,"iconIdx":12},{"icon":{"paths":["M471.351 1.135c-118.225 11.467-226.566 62.474-310.588 146.299-79.872 79.871-128.704 179.117-145.113 295.563-3.756 27.678-3.163 101.818 1.186 130.484 8.501 56.542 22.736 103.2 46.658 152.625l15.421 32.028-32.225 100.234c-17.793 55.357-33.016 103.991-33.807 108.142-3.954 24.515 19.572 48.043 44.088 44.089 4.152-0.791 52.786-16.014 108.143-33.807l100.235-32.226 32.027 15.421c49.427 23.922 96.083 38.155 152.627 46.656 28.666 4.35 102.804 4.944 130.482 1.187 116.446-16.409 214.902-64.846 295.168-144.718 78.488-78.488 126.53-174.372 144.126-288.645 4.745-31.829 4.745-106.56 0-138.392-17.596-114.074-65.242-209.364-143.73-288.248-77.894-78.092-174.966-126.727-286.667-143.729-24.713-3.756-92.524-5.338-118.029-2.965zM557.945 80.216c65.242 6.524 137.205 30.841 186.432 63.264 87.977 57.531 148.277 134.634 178.919 228.543 23.527 71.964 27.877 140.567 13.839 215.298-8.896 46.459-33.016 107.55-57.135 144.124-56.938 86.792-133.448 147.287-225.775 178.129-120.005 40.133-242.383 26.69-357.444-38.946-22.143-12.654-22.539-12.455-109.725 15.815-40.133 13.048-73.347 23.725-73.545 23.527s10.478-33.413 23.526-73.546c29.458-90.349 29.062-86.395 12.060-116.643-36.377-64.649-54.17-126.528-57.333-199.678-7.908-186.829 113.875-361.202 293.191-419.919 57.926-18.979 115.854-25.503 172.99-19.968z","M303.089 459.226c-4.547 1.582-12.258 6.722-17.002 11.664-19.771 19.771-19.771 49.031 0 68.801 19.771 19.769 49.031 19.769 68.8 0 37.169-36.97-2.173-98.061-51.797-80.466z","M500.793 459.226c-4.547 1.582-12.258 6.722-17.002 11.664-19.771 19.771-19.771 49.031 0 68.801 19.771 19.769 49.031 19.769 68.8 0 37.169-36.97-2.175-98.061-51.797-80.466z","M698.497 459.226c-4.547 1.582-12.258 6.722-17.002 11.664-19.771 19.771-19.771 49.031 0 68.801 19.769 19.769 49.029 19.769 68.8 0 37.167-36.97-2.175-98.061-51.797-80.466z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["Group"],"grid":32},"attrs":[],"properties":{"order":212,"id":13,"name":"chat","prevSize":32,"code":59649},"setIdx":1,"setId":9,"iconIdx":13},{"icon":{"paths":["M1219.048 24.381c38.814 0 76.020 15.409 103.424 42.862 27.453 27.404 42.862 64.61 42.862 103.424v682.667c0 38.814-15.409 76.020-42.862 103.424-27.404 27.453-64.61 42.862-103.424 42.862h-1072.762c-38.814 0-76.020-15.409-103.424-42.862-27.453-27.404-42.862-64.61-42.862-103.424v-682.667c0-38.814 15.409-76.020 42.862-103.424 27.404-27.453 64.61-42.862 103.424-42.862h1072.762zM1091.535 233.716l-375.32 292.376c-17.554 13.702-42.179 13.702-59.782 0.098l-381.123-294.961c-21.26-16.482-51.931-12.581-68.412 8.68-16.433 21.309-12.532 51.931 8.728 68.413l381.123 294.961c52.809 40.911 126.683 40.814 179.395-0.244l375.369-292.376c21.211-16.53 25.015-47.202 8.485-68.413-16.53-21.26-47.202-25.064-68.462-8.533z"],"width":1365,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["email"],"grid":32},"attrs":[],"properties":{"order":213,"id":14,"name":"email","prevSize":32,"code":59652},"setIdx":1,"setId":9,"iconIdx":14},{"icon":{"paths":["M568.005 1007.338c22.851-22.213 22.851-58.236 0-80.45l-426.739-414.888 426.739-414.885c22.851-22.216 22.851-58.236 0-80.453s-59.901-22.216-82.752 0l-468.114 455.111c-22.851 22.216-22.851 58.236 0 80.453l468.114 455.112c22.851 22.213 59.901 22.213 82.752 0z"],"width":585,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["left arrow gray"],"grid":32},"attrs":[],"properties":{"order":214,"id":15,"name":"left-arrow","prevSize":32,"code":59651},"setIdx":1,"setId":9,"iconIdx":15},{"icon":{"paths":["M881.195 844.457l-121.147-144.502c-29.223-31.547-62.897-44.308-103.345-23.513l-40.448 21.662c-22.489 11.5-22.646 18.117-30.956 30.996-21.701 33.792-50.846 26.112-64.63 11.5-58.289-62.11-130.913-201.728-131.582-203.028-24.34-47.38-39.188-97.004-47.892-146.235-3.308-19.81 6.853-47.852 46.946-45.883 15.358 0.788 20.794 4.49 43.282-7.089l41.157-20.362c40.448-20.716 49.743-55.493 41.078-97.634l-46.828-182.587c-17.093-33.871-58.407-47.498-92.237-30.405l-87.788 44.19c-15.202 7.68-29.381 23.473-38.558 41.511-74.082 125.204-69.75 322.482 24.655 506.211 3.466 6.853 148.085 358.873 436.065 390.617 20.007 3.033 40.999 0.788 56.123-7.168l87.119-45.607c33.556-17.566 46.553-59.038 28.987-92.672z"],"width":1103,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["phone"],"grid":32},"attrs":[],"properties":{"order":215,"id":16,"name":"phone","prevSize":32,"code":59653},"setIdx":1,"setId":9,"iconIdx":16},{"icon":{"paths":["M250.339 1007.33c-21.711-22.22-21.711-58.235 0-80.455l405.405-414.879-405.405-414.879c-21.711-22.219-21.711-58.236 0-80.454s56.908-22.219 78.618 0l444.703 455.112c21.711 22.216 21.711 58.235 0 80.451l-444.703 455.112c-21.711 22.216-56.906 22.216-78.618 0z"],"width":1024,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"2032032031242111331255255255135313217801481":[{}]},"tags":["right arrow black"],"grid":32},"attrs":[{}],"properties":{"order":216,"id":17,"name":"right-arrow","prevSize":32,"code":59654},"setIdx":1,"setId":9,"iconIdx":17},{"icon":{"paths":["M16.67 250.339c22.22-21.711 58.235-21.711 80.455-0l414.879 405.405 414.879-405.405c22.219-21.711 58.236-21.711 80.454-0s22.219 56.908 0 78.618l-455.112 444.703c-22.216 21.711-58.235 21.711-80.451 0l-455.112-444.703c-22.216-21.711-22.216-56.906 0-78.618z"],"width":1024,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"2032032031242111331255255255135313217801481":[{}]},"tags":["right arrow black"],"grid":32},"attrs":[{}],"properties":{"order":217,"id":18,"prevSize":32,"name":"down-arrow","code":59667},"setIdx":1,"setId":9,"iconIdx":18},{"icon":{"paths":["M1007.33 773.661c-22.22 21.711-58.235 21.711-80.455 0l-414.879-405.405-414.879 405.405c-22.219 21.711-58.236 21.711-80.454 0s-22.219-56.908 0-78.618l455.112-444.703c22.216-21.711 58.235-21.711 80.451 0l455.112 444.703c22.216 21.711 22.216 56.906 0 78.618z"],"width":1024,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"2032032031242111331255255255135313217801481":[{}]},"tags":["right arrow black"],"grid":32},"attrs":[{}],"properties":{"order":218,"id":19,"prevSize":32,"name":"up-arrow","code":59668},"setIdx":1,"setId":9,"iconIdx":19},{"icon":{"paths":["M21.333 85.333c0-35.346 28.654-64 64-64h1024c35.345 0 64 28.654 64 64s-28.655 64-64 64h-1024c-35.346 0-64-28.654-64-64zM21.333 533.333c0-35.345 28.654-64 64-64h1024c35.345 0 64 28.655 64 64s-28.655 64-64 64h-1024c-35.346 0-64-28.655-64-64zM21.333 960c0-35.345 28.654-64 64-64h1024c35.345 0 64 28.655 64 64s-28.655 64-64 64h-1024c-35.346 0-64-28.655-64-64z"],"width":1195,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["menu (Stroke)"],"grid":32},"attrs":[],"properties":{"order":219,"id":20,"name":"menu","prevSize":32,"code":59666},"setIdx":1,"setId":9,"iconIdx":20},{"icon":{"paths":["M618.667 682.667c0 153.169-124.164 277.333-277.333 277.333-153.167 0-277.333-124.164-277.333-277.333v-341.333c0-153.167 124.166-277.333 277.333-277.333 153.169 0 277.333 124.166 277.333 277.333v341.333zM341.333 0c-188.513 0-341.333 152.82-341.333 341.333v341.333c0 188.514 152.82 341.333 341.333 341.333s341.333-152.819 341.333-341.333v-341.333c0-188.513-152.819-341.333-341.333-341.333z","M341.333 213.333c23.564 0 42.667 19.103 42.667 42.667v128c0 23.564-19.103 42.667-42.667 42.667s-42.667-19.103-42.667-42.667v-128c0-23.564 19.103-42.667 42.667-42.667z"],"width":683,"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[{},{}]},"tags":["scroll icon (2)"],"grid":32},"attrs":[{},{}],"properties":{"order":220,"id":21,"name":"scroll","prevSize":32,"code":59665},"setIdx":1,"setId":9,"iconIdx":21},{"icon":{"paths":["M12.497 72.837c-16.662-16.663-16.662-43.678 0-60.34s43.677-16.662 60.34 0l439.163 439.164 439.164-439.164c16.661-16.662 43.678-16.662 60.339 0s16.661 43.677 0 60.34l-439.164 439.163 439.164 439.164c16.661 16.661 16.661 43.678 0 60.339s-43.678 16.661-60.339 0l-439.164-439.164-439.163 439.164c-16.663 16.661-43.677 16.661-60.34 0s-16.662-43.678 0-60.339l439.164-439.164-439.164-439.163z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["close"],"grid":32},"attrs":[],"properties":{"order":221,"id":22,"name":"close","prevSize":32,"code":59663},"setIdx":1,"setId":9,"iconIdx":22},{"icon":{"paths":["M683.569 0c16.583 1.324 33.166 2.647 49.749 4.053 11.483 0.993 22.882 2.068 34.681 3.226v162.877c-5.343 0-10.366 0-15.388 0-32.448 0.496-64.976 0-97.345 1.82-41.059 2.316-63.86 24.816-65.694 67.335-1.913 44.586-0.398 89.256-0.398 135.414h173.007c-7.657 61.627-15.151 121.599-22.723 182.564h-150.762v466.711h-181.376v-466.297h-151.32v-182.233h151.24c0-5.129 0-9.017 0-12.822 0.159-47.73-0.957-95.46 0.957-143.024 2.312-57.408 18.576-110.101 57.642-152.95 29.658-32.675 66.731-51.287 108.587-60.304 11.241-2.399 22.642-4.136 33.963-6.204 25.114 0 50.148 0 75.261 0l-0.080-0.165z"],"attrs":[],"tags":["facebook"],"grid":32,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{}},"attrs":[],"properties":{"order":222,"id":23,"name":"facebook","prevSize":32,"code":59662},"setIdx":1,"setId":9,"iconIdx":23},{"icon":{"paths":["M508.425 0h56.239c2.611 0.761 5.282 1.332 7.987 1.707 74.743 4.907 145.562 23.76 211.038 58.507 150.268 79.627 242.095 200.587 274.543 362.667 3.925 19.492 5.564 39.413 8.35 59.121v59.998c-0.614 3.2-1.365 6.374-1.865 9.574-3.648 24-5.568 48.371-11.132 72-48.448 208.427-224.094 363.972-444.787 395.093-14.665 2.052-29.414 3.627-44.134 5.333h-62.473c-3.004-0.614-5.982-1.331-8.99-1.788-29.385-4.506-59.409-6.694-88.099-13.786-149.376-36.907-263.244-119.68-338.155-249.306-62.36-107.866-81.255-223.492-56.266-344.801 6.038-29.2 16.947-57.493 25.378-86.266 1.53-5.147 0.779-11.093 3.089-15.76 3.395-6.933 9.35-12.666 12.94-19.52 81.44-156.445 211.587-251.325 390.442-284.64 21.705-4.027 43.913-5.467 65.894-8.133zM958.135 261.333c-18.56-23.76-35.951-46.027-53.675-68.667-13.581 8.667-25.408 16.853-37.901 24-5.039 2.854-12.049 5.52-17.365 4.454-42.688-8.453-86.263-13.786-127.364-28.693-7.326-2.608-15.339-2.852-22.818-0.693-38.43 13.2-76.109 15.147-113.314-3.413-0.324-0.126-0.657-0.224-0.998-0.294-14.916-5.093-19.034-14.213-11.994-28.106 10.603-20.934 21.649-41.68 32.388-62.587 1.609-3.709 4.39-6.842 7.957-8.957 3.563-2.115 7.731-3.104 11.913-2.83 18.394 0.24 36.787 0 55.181 0 15.471 0.213 26.048-9.787 40.905-15.093-93.555-42.213-275.486-48-340.686-10.667 9.907 3.947 18.032 8.72 26.798 10.347 29.941 5.574 60.132 9.813 90.161 14.96 15.804 2.667 21.090 11.36 16.307 25.946-4.787 14.587-10.355 28.96-15.002 43.573-1.131 4.020-3.349 7.683-6.426 10.623s-6.908 5.051-11.106 6.124c-10.88 3.333-21.982 6.293-32.444 10.667-5.854 2.281-10.918 6.098-14.609 11.013-14.527 21.92-27.828 44.533-42.243 66.534-3.655 5.559-8.538 10.284-14.303 13.84-24.404 14.64-49.004 29.040-74.103 42.534-9.027 4.76-18.831 8.015-28.996 9.626-29.747 4.774-59.717 8.24-89.548 12.694-1.563 0.496-2.976 1.35-4.116 2.489s-1.972 2.527-2.423 4.044c-1.892 14.293-0.946 27.787 13.552 36.907 4.842 3.040 8.348 8 12.689 11.814 3.182 2.603 5.667 5.898 7.25 9.609s2.217 7.731 1.849 11.725c-0.306 6.347 0 12.718 0 19.066l3.479 1.468c5.287-5.734 10.24-11.735 15.861-17.094 13.747-13.067 25.851-11.2 34.561 5.2 8.348 15.705 16.696 31.466 24.488 47.415 0.836 2.317 2.48 4.288 4.654 5.577 2.174 1.293 4.747 1.826 7.284 1.515 32.947-0.294 65.95 0.213 98.925-0.346 11.91-0.188 19.34 4.134 25.043 13.892 12.745 21.333 26.522 42.189 39.322 63.548 1.357 2.812 3.618 5.137 6.451 6.63 2.833 1.489 6.093 2.074 9.297 1.664 14.891-0.533 29.833-0.213 44.749-0.132 19.145 0 25.741 7.757 22.067 26.027-4.898 24.183-9.489 48.452-15.445 72.371-2.24 7.902-6.353 15.202-12.023 21.333-9.502 11.085-20.13 21.239-31.723 30.319-22.647 16.909-33.391 37.333-28.326 65.229 1.95 10.667-3.81 18.21-12.745 24.371-17.446 12.079-34.729 24.427-51.536 37.333-3.659 3.102-5.914 7.441-6.289 12.109-0.64 21.653 0 43.332-0.362 64.986-0.223 17.412-10.268 24.269-27.382 18.987-14.832-4.561-29.524-9.655-44.523-14.054-4.169-1.118-7.986-3.2-11.116-6.063s-5.477-6.426-6.833-10.364c-10.129-25.143-20.954-50.027-30.971-75.17-2.327-5.884-3.543-12.113-3.59-18.402-0.306-46.345-0.167-92.668-0.167-138.987v-10.667c-19.228-3.678-37.121-8.213-55.293-10.295-19.869-2.266-33.949-9.839-40.154-28.958-1.865-5.385-4.486-10.496-7.792-15.202-18.644-27.307-24.71-57.173-21.622-89.412 0.89-9.092 2.783-16.93 10.074-23.066 5.399-4.454 10.63-9.118 16.696-14.4-27.827-17.865-53.289-34.667-79.279-50.534-10.909-6.666-18.199-14.639-21.315-26.825-2.449-9.653-6.567-18.907-10.575-30.027-69.122 217.919 31.918 463.201 261.129 569.066 219.833 101.572 476.593 32 612.196-144.853-11.132-10.667-23.206-20.851-33.698-32.32-4.565-5.205-7.351-11.627-7.987-18.398-1.114-16.269 0-32.67-0.61-48.96-0.213-7.202-1.929-14.293-5.039-20.855-17.557-34.667-35.255-69.333-54.042-103.543-8.892-15.1-13.082-32.32-12.075-49.63 0.836-12.241 3.81-26.667-1.668-36.267-5.734-9.92-20.258-15.334-31.42-21.999-3.695-2.035-8.026-2.743-12.215-2.001-17.95 3.733-35.648 8.533-53.594 12.267-5.312 1.233-10.884 0.994-16.055-0.691-40.627-16.269-81.143-32.802-121.301-50.054-2.867-1.359-5.406-3.282-7.45-5.644s-3.541-5.109-4.403-8.063c-6.541-38.773-11.883-77.734-17.643-116.64-0.572-3.795-0.132-7.666 1.271-11.255 1.408-3.59 3.733-6.781 6.771-9.278 15.637-14.693 30.609-30.107 46.72-44.213 5.581-4.703 12.625-7.514 20.036-8 32.977-0.827 65.95-0.24 98.927-0.453 3.989-0.217 7.966 0.634 11.486 2.456s6.438 4.544 8.435 7.864c8.35 12.294 16.7 24.64 25.549 36.453 2.876 3.523 6.938 5.982 11.49 6.96 20.062 3.76 40.265 6.88 60.467 9.947 9.519 1.44 19.955 5.173 28.553 2.88 28.548-7.733 56.154-17.52 86.763-27.333zM974.498 292.080c-30.609 9.813-60.663 19.707-90.935 28.987-6.519 2.081-13.44 2.755-20.258 1.973-32.226-4.64-64.422-9.573-96.367-15.6-7.539-1.807-14.272-5.893-19.2-11.654-9.182-10.667-16.222-23.2-24.768-34.507-1.195-1.443-2.684-2.639-4.378-3.514s-3.554-1.413-5.474-1.579c-25.655-0.427-51.337-0.373-77.022 0-3.665 0.105-7.177 1.425-9.937 3.733-11.601 10.533-22.985 21.333-33.865 32.506-2.372 2.961-3.452 6.691-3.004 10.4 3.921 28.72 8.653 57.333 12.412 86.053 0.051 2.747 1.003 5.409 2.714 7.613s4.1 3.841 6.831 4.68c31.305 12.587 62.357 25.788 93.722 38.268 5.047 1.847 10.543 2.261 15.834 1.199 16.917-3.469 33.698-7.68 50.419-11.972 4.459-1.357 9.195-1.681 13.807-0.947 4.617 0.738 8.981 2.517 12.74 5.184 13.914 9.468 27.994 18.671 42.436 27.123 4.446 2.308 8.094 5.807 10.496 10.069 2.406 4.262 3.469 9.101 3.059 13.931-0.474 16.64-0.448 33.331 0 49.971 0.171 5.547 1.545 10.995 4.032 16 20.314 39.706 41.242 79.147 61.444 118.908 3.166 6.588 4.945 13.713 5.231 20.962 0.751 15.625 0 31.305 0.388 46.985-0.102 3.533 0.973 7.006 3.063 9.92 7.121 8 14.997 15.386 22.818 23.228 92.442-131.84 110.362-320.96 23.625-477.841l0.137-0.080zM355.904 896.508c0-18.667 0.306-36.642 0-54.588-0.382-4.484 0.517-8.981 2.601-13.013s5.273-7.441 9.226-9.865c9.406-6.217 18.394-13.069 27.521-19.708 10.24-7.441 24.321-13.043 29.497-22.933 5.174-9.894 2.366-24.64 2.2-37.201-0.192-3.981 0.533-7.957 2.121-11.644s3.998-6.993 7.061-9.69c19.311-18.214 38.345-36.693 57.434-55.121 2.172-2.103 5.261-4.267 5.845-6.827 4.314-19.012 8.124-38.157 12.326-58.505-15.834 0-29.999-0.213-44.134 0-4.681 0.346-9.365-0.653-13.453-2.863-4.087-2.214-7.398-5.542-9.502-9.566-13.385-22.161-27.495-43.947-40.908-66.108-1.135-2.347-3.004-4.297-5.347-5.581s-5.045-1.843-7.732-1.591c-33.643 0.35-67.313 0-100.984 0.294-11.131 0-18.283-3.998-22.985-13.628-6.873-14.025-14.415-27.785-22.261-43.012-21.956 21.094-43.049 41.229-63.836 61.628-1.836 1.783-2.115 5.333-2.393 8.265-2.059 21.333 0.78 41.574 13.608 60.002 4.768 7.351 8.838 15.095 12.16 23.147 1.002 2.611 2.753 4.902 5.051 6.605s5.052 2.752 7.944 3.021c21.816 3.759 43.549 8 65.282 12.348 16.279 3.2 20.286 8 20.314 23.787 0 32 1.78 64-0.418 96-3.351 43.541 5.284 87.164 25.044 126.507 6.122 12.668 13.719 18.667 28.717 19.84zM175.501 444.373l4.341-1.549c-2.198-10.266-0.724-24.958-7.291-29.998-26.185-20.106-35.118-44.747-30.304-75.44 0.168-2.664 0.168-5.336 0-8 0.278-14.8 5.12-20.48 20.425-22.693 21.594-3.174 43.243-6.027 64.893-8.774 28.439-3.573 55.209-9.2 81.422-23.36 36.676-19.84 66.228-44 82.785-81.253 12.55-28.213 33.56-45.334 65.225-50.24 1.011-0.097 1.971-0.457 2.786-1.040 2.782-2.48 6.511-4.693 8.094-7.84 2.47-5.864 4.535-11.877 6.178-18-12.77-2.107-24.905-4.88-37.205-6.054-33.696-3.226-65.28-11.413-91.41-33.52-4.396-3.706-8.515-3.68-13.913-1.253-114.332 50.347-198.008 130.258-251.028 239.733-1.763 3.798-2.127 8.058-1.030 12.080 7.235 22.213 15.055 44.24 22.846 66.293 0.722 2.543 2.225 4.819 4.314 6.534 22.846 14.96 45.887 29.628 68.872 44.373zM879.834 167.334c-2.871-1.504-5.615-3.216-8.209-5.12-30.639-27.104-64.55-50.595-101.013-69.974-5.982-3.2-10.603-3.386-16.141 0-34.923 21.040-72.35 33.227-114.091 27.573-1.357-0.294-2.761-0.294-4.117 0-1.63 0.352-3.089 1.216-4.147 2.454-6.788 12.56-13.299 25.226-19.759 37.546 17.199 8.853 33.395 11.334 50.953 5.013 13.15-4.229 26.62-7.465 40.294-9.68 5.342-1.178 10.914-0.966 16.141 0.614 39.428 14.426 80.695 21.68 121.796 29.333 3.597 0.94 7.411 0.744 10.88-0.56 8.572-4.64 16.67-10.32 27.413-17.2z"],"width":1067,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["globalIcon"],"grid":32},"attrs":[],"properties":{"order":223,"id":24,"name":"global","prevSize":32,"code":59657},"setIdx":1,"setId":9,"iconIdx":24},{"icon":{"paths":["M512.050 0c-139.053 0-156.504 0.608-211.118 3.093-54.507 2.496-91.713 11.125-124.268 23.787-33.675 13.078-62.241 30.571-90.7 59.041-28.48 28.459-45.974 57.025-59.094 90.689-12.693 32.566-21.334 69.782-23.787 124.268-2.443 54.615-3.083 72.076-3.083 211.129 0 139.049 0.619 156.447 3.093 211.063 2.507 54.507 11.136 91.711 23.787 124.267 13.088 33.676 30.582 62.239 59.051 90.7 28.448 28.48 57.014 46.017 90.668 59.095 32.576 12.661 69.793 21.289 124.289 23.787 54.615 2.484 72.056 3.092 211.095 3.092 139.063 0 156.461-0.608 211.076-3.092 54.507-2.497 91.754-11.125 124.33-23.787 33.663-13.077 62.187-30.614 90.637-59.095 28.48-28.461 45.971-57.024 59.091-90.69 12.589-32.567 21.23-69.781 23.79-124.267 2.451-54.612 3.092-72.024 3.092-211.073 0-139.053-0.641-156.504-3.092-211.118-2.56-54.507-11.201-91.713-23.79-124.268-13.12-33.675-30.611-62.241-59.091-90.7-28.48-28.48-56.961-45.974-90.67-59.041-32.639-12.661-69.867-21.291-124.373-23.787-54.616-2.485-72-3.093-211.096-3.093h0.162zM466.118 92.268c13.632-0.021 28.84 0 45.931 0 136.704 0 152.906 0.491 206.891 2.944 49.922 2.283 77.015 10.624 95.064 17.632 23.892 9.28 40.927 20.374 58.837 38.294 17.92 17.92 29.012 34.987 38.314 58.881 7.009 18.027 15.36 45.12 17.633 95.041 2.454 53.975 2.986 70.187 2.986 206.829s-0.532 152.857-2.986 206.828c-2.283 49.922-10.623 77.015-17.633 95.040-9.279 23.896-20.394 40.907-38.314 58.817-17.92 17.92-34.935 29.016-58.837 38.294-18.029 7.039-45.142 15.36-95.064 17.643-53.975 2.454-70.187 2.986-206.891 2.986-136.717 0-152.92-0.532-206.894-2.986-49.921-2.302-77.014-10.646-95.073-17.652-23.894-9.282-40.96-20.374-58.881-38.294s-29.014-34.945-38.315-58.847c-7.008-18.029-15.36-45.122-17.632-95.044-2.454-53.971-2.944-70.187-2.944-206.914s0.491-152.853 2.944-206.828c2.283-49.921 10.624-77.014 17.632-95.063 9.28-23.894 20.395-40.96 38.315-58.881s34.987-29.014 58.881-38.315c18.048-7.040 45.152-15.36 95.073-17.653 47.233-2.133 65.536-2.773 160.963-2.88v0.128zM785.352 177.282c-33.921 0-61.44 27.488-61.44 61.419 0 33.92 27.519 61.441 61.44 61.441s61.44-27.52 61.44-61.441c0-33.92-27.519-61.441-61.44-61.441v0.021zM512.050 249.069c-145.21 0-262.938 117.731-262.938 262.937s117.728 262.881 262.938 262.881c145.207 0 262.891-117.674 262.891-262.881s-117.697-262.937-262.904-262.937h0.013zM512.050 341.336c94.251 0 170.668 76.407 170.668 170.671 0 94.251-76.417 170.668-170.668 170.668-94.264 0-170.671-76.417-170.671-170.668 0-94.264 76.407-170.671 170.671-170.671z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["instagram"],"grid":32},"attrs":[],"properties":{"order":224,"id":25,"name":"instagram","prevSize":32,"code":59655},"setIdx":1,"setId":9,"iconIdx":25},{"icon":{"paths":["M0 73.353c0-40.501 33.665-73.353 75.195-73.353h873.611c41.528 0 75.195 32.852 75.195 73.353v877.295c0 40.514-33.666 73.351-75.195 73.351h-873.611c-41.53 0-75.195-32.837-75.195-73.351v-877.296zM316.376 857.194v-462.392h-153.691v462.392h153.691zM239.53 331.67c53.595 0 86.954-35.508 86.954-79.881-0.999-45.372-33.359-79.893-85.937-79.893-52.573 0-86.947 34.521-86.947 79.893 0 44.373 33.351 79.881 84.928 79.881h1.002zM553.69 857.194v-258.22c0-13.821 0.998-27.625 5.057-37.505 11.109-27.612 36.398-56.208 78.855-56.208 55.613 0 77.86 42.404 77.86 104.564v247.369h153.679v-265.13c0-142.025-75.826-208.113-176.941-208.113-81.527 0-118.084 44.808-138.508 76.318v1.592h-1.027c0.34-0.529 0.68-1.057 1.027-1.592v-65.467h-153.689c2.018 43.388 0 462.392 0 462.392h153.686z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["linkedin"],"grid":32},"attrs":[],"properties":{"order":225,"id":26,"name":"linkedin","prevSize":32,"code":59656},"setIdx":1,"setId":9,"iconIdx":26},{"icon":{"paths":["M751.498 662.008c50.609-68.899 80.502-153.962 80.502-246.008 0-229.751-186.25-416-416-416s-416 186.249-416 416c0 229.75 186.249 416 416 416 92.069 0 177.152-29.909 246.063-80.542l-0.055 0.039c1.887 2.56 3.99 5.010 6.309 7.326l246.43 246.43c24.993 24.993 65.512 24.993 90.506 0s24.993-65.512 0-90.506l-246.43-246.43c-2.316-2.32-4.766-4.423-7.326-6.309zM768 416c0 194.402-157.598 352-352 352-194.404 0-352-157.598-352-352 0-194.404 157.596-352 352-352 194.402 0 352 157.596 352 352z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["search"],"grid":32},"attrs":[],"properties":{"order":226,"id":27,"name":"search","prevSize":32,"code":59658},"setIdx":1,"setId":9,"iconIdx":27},{"icon":{"paths":["M576 0.001l126.758-0.001c9.15 45.761 34.562 103.492 79.003 160.764 43.55 56.119 101.254 95.236 178.239 95.236v127.999c-112.217 0-196.539-52.069-256-117.031v437.031c0 176.732-143.268 320-320 320-176.731 0-320-143.268-320-320 0-176.729 143.269-320 320-320v128c-106.039 0-192 85.963-192 192 0 106.040 85.961 192 192 192 106.040 0 192-85.96 192-192v-703.999z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["tiktok"],"grid":32},"attrs":[],"properties":{"order":227,"id":28,"name":"tiktok","prevSize":32,"code":59659},"setIdx":1,"setId":9,"iconIdx":28},{"icon":{"paths":["M609.418 433.373l381.21-433.373h-90.336l-331.002 376.291-264.37-376.291h-304.92l399.779 569.018-399.779 454.458h90.339l349.546-397.376 279.197 397.376h304.918l-414.582-590.102zM485.686 574.032l-362.797-507.523h138.756l638.691 893.481h-138.755l-275.894-385.958z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["x"],"grid":32},"attrs":[],"properties":{"order":228,"id":29,"name":"x","prevSize":32,"code":59660},"setIdx":1,"setId":9,"iconIdx":29},{"icon":{"paths":["M515.336 127.922c0.364 0.001 0.756 0.002 1.178 0.003l4.531 0.014c52.595 0.193 319.16 2.125 391.032 21.448 44.064 11.818 78.758 46.643 90.528 90.851 6.483 24.287 11.002 56.569 14.15 89.769l0.614 6.65c0.493 5.549 0.954 11.11 1.376 16.65l0.493 6.637c4.205 58.503 4.698 113.249 4.755 125.227l0.006 1.615c0 0.132 0 0.349 0 0.349v0.907c0 0 0 0.216 0 0.349l-0.006 1.616c-0.058 12.43-0.589 70.919-5.248 131.867l-0.525 6.657-0.557 6.663c-3.174 36.648-7.923 73.032-15.059 99.745-11.77 44.211-46.464 79.040-90.528 90.854-74.266 19.968-356.424 21.37-395.563 21.466l-3.014 0.006c-0.247 0-0.465 0-0.652 0h-1.229c0 0-0.283 0-0.47 0l-3.665-0.006c-19.779-0.051-101.626-0.429-187.339-3.373l-10.959-0.39c-1.828-0.064-3.658-0.134-5.487-0.205l-10.971-0.435-10.946-0.461c-71.009-3.117-138.711-8.23-169.855-16.602-44.059-11.814-78.753-46.643-90.529-90.854-7.134-26.714-11.89-63.098-15.060-99.745l-0.559-6.663-0.525-6.657c-4.494-58.732-5.146-115.18-5.241-130.33l-0.011-2.169c-0.001-0.195-0.001-0.375-0.002-0.539v-2.493c0.001-0.164 0.001-0.344 0.002-0.54l0.011-2.168c0.086-13.721 0.629-61.313 4.069-113.799l0.445-6.584c0.077-1.101 0.155-2.204 0.234-3.308l0.492-6.637c0.424-5.54 0.882-11.101 1.377-16.65l0.612-6.65c3.15-33.2 7.67-65.482 14.156-89.769 11.775-44.207 46.47-79.033 90.529-90.851 31.144-8.373 98.847-13.48 169.855-16.596l10.946-0.464 10.971-0.433c1.829-0.070 3.658-0.138 5.487-0.205l10.959-0.39c80.243-2.755 157.096-3.265 182.808-3.359l4.531-0.014c0.42-0.001 0.813-0.002 1.178-0.003h6.675zM409.602 333.438v308.296l266.033-154.138-266.033-154.158z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"24211133125525525513531321":[]},"tags":["youtube"],"grid":32},"attrs":[],"properties":{"order":229,"id":30,"name":"youtube","prevSize":32,"code":59661},"setIdx":1,"setId":9,"iconIdx":30},{"icon":{"paths":["M0 510.705l852.582 493.978 1.502-985.343-854.084 491.365zM5120.131 433.208l-4351.994-6.661-0.256 170.667 4351.989 6.661 0.261-170.667z"],"width":5120,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["long-left-arrow"],"grid":32},"attrs":[],"properties":{"order":230,"id":31,"name":"long-left-arrow","prevSize":32,"code":59675},"setIdx":1,"setId":9,"iconIdx":31},{"icon":{"paths":["M1229.284 492.622l-481.701-481.701c-14.563-14.563-38.157-14.563-52.72 0s-14.563 38.167 0 52.72l425.042 425.042h-1082.832c-20.584 0-37.279 16.685-37.279 37.279s16.696 37.279 37.279 37.279h1068.872l-397.121 397.121c-14.563 14.563-14.563 38.167 0 52.72 7.276 7.276 16.818 10.919 26.36 10.919s19.084-3.643 26.36-10.919l460.76-460.76s6.98-6.98 6.98-6.98c14.563-14.563 14.563-38.167 0-52.72z"],"width":1240,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["forward-arrow"],"grid":32},"attrs":[{}],"properties":{"order":264,"id":0,"name":"forward-arrow","prevSize":32,"code":59680},"setIdx":2,"setId":8,"iconIdx":0},{"icon":{"paths":["M777.936-0c11.088 5.424 14.909 14.295 14.375 26.771-0.935 22.149-2.164 124.48-0.347 146.576 1.336 16.272-6.439 26.504-19.37 26.745-11.97 0.187-20.305-9.138-20.412-23.351-0.107-13.119-0.080-106.418-0.053-119.831 0-8.871-7.161-16.085-16.031-16.085h-667.579c-15.283 0-27.653 12.371-27.653 27.653v889.794c0 13.921 11.302 25.222 25.222 25.222h448.838c1.576-13.68 3.26-27.466 4.756-41.253 3.447-31.794 6.573-63.616 10.447-95.357 0.721-6.012 3.714-12.023 6.813-17.394 69.975-121.461 140.136-242.814 210.004-364.355 3.233-5.638 4.996-12.050 5.023-18.542 0.401-52.689 0.214-105.376 0.24-158.091 0-3.34-0.187-6.706 0.214-9.993 1.336-10.875 9.859-18.569 20.145-18.435 10.875 0.134 19.343 8.283 19.477 19.905 0.294 30.325 0.134 60.65 0.134 91.002 0 3.954 0 7.935 1.576 12.718 1.817-2.886 3.714-5.718 5.424-8.657 23.031-39.757 45.394-79.914 69.227-119.19 17.154-28.294 43.764-41.654 76.708-39.543 31.688 2.031 55.306 18.089 69.547 46.597 4.248 8.497 6.252 18.142 9.325 27.252-0.294 6.519-0.721 15.47-1.015 21.989-8.069 17.955-15.043 36.55-24.767 53.544-66.635 116.464-133.964 232.528-200.814 348.885-3.26 5.691-4.996 12.13-5.023 18.675-0.321 87.983-0.214 175.965-0.214 263.949 0 14.802-11.997 26.798-26.798 26.798-245.967 0-491.961 0-737.928 0-20.947 0-27.252-6.386-27.252-27.626 0.027-322.995 0.080-645.964-0.16-968.933 0-0.134 0-0.24 0-0.374 0.080-15.043 12.611-27.065 27.653-27.065h750.272zM653.563 883.248c97.708-169.205 194.989-337.717 292.697-506.976-25.516-14.722-50.444-29.123-76.227-43.978-97.708 169.232-195.016 337.744-292.697 506.949 25.462 14.695 50.417 29.096 76.227 44.005zM751.618 794.249c-2.832 4.542-4.569 7.187-6.172 9.939-20.866 36.069-41.493 72.299-62.787 108.101-4.515 7.588-10.474 14.214-17.474 19.611-20.573 15.871-41.787 30.859-62.707 46.249-1.87 1.363-3.447 3.126-5.664 5.157h129.128c14.188 0 25.676-11.489 25.676-25.676v-163.382zM966.459 341.725c4.489-8.363 9.138-15.711 12.665-23.405 5.584-12.13 5.851-26.264-0.187-38.154-13.012-25.622-46.917-32.596-66.475-14.401-9.165 8.523-15.39 20.198-23.512 31.18 26.531 15.337 51.219 29.603 77.483 44.753zM624.307 912.557c-19.397-11.195-37.966-21.882-57.684-33.237-2.966 27.546-5.771 53.597-8.791 81.784 23.084-16.86 44.245-32.302 66.475-48.52z","M590.589 251.978c3.34 0 6.706 0.187 9.966-0.24 10.34-1.363 17.501-9.539 17.501-19.744s-7.134-18.408-17.474-19.744c-3.286-0.428-6.653-0.24-9.966-0.24-129.529 0-259.059 0-388.588 0-3.34 0-6.706-0.267-9.966 0.24-9.165 1.389-15.043 6.787-17.207 15.791-3.153 13.119 7.268 23.912 23.164 23.939h392.569z","M396.027 363.981c-66.261 0-132.522 0.053-198.783-0.053-16.966-0.027-27.252-13.493-21.214-27.493 3.687-8.55 10.581-12.451 19.798-12.451 13.653 0 27.306 0 40.959 0 117.533 0 235.093 0 352.625 0 3.66 0 7.348-0.214 10.981 0.214 10.367 1.229 17.608 9.378 17.688 19.557 0.080 10.207-6.974 18.515-17.287 19.931-3.286 0.454-6.653 0.267-9.966 0.267-64.925 0-129.85 0-194.802 0z","M396.989 587.986c-66.581 0-133.189 0.053-199.772-0.053-16.966-0.027-27.226-13.52-21.16-27.519 3.687-8.55 10.607-12.424 19.824-12.424 15.657 0 31.287 0 46.944 0 115.529 0 231.085 0 346.615 0 3.66 0 7.348-0.214 10.981 0.214 10.367 1.256 17.581 9.405 17.661 19.584 0.080 10.207-7 18.488-17.314 19.905-3.286 0.454-6.653 0.267-9.966 0.267-64.604 0-129.182 0-193.787 0z","M281.914 771.994c28.936 0 57.871-0.134 86.808 0.053 13.012 0.080 21.401 8.283 21.347 20.011-0.053 11.676-8.497 19.477-21.534 19.878-0.321 0-0.668 0-0.989 0-56.882 0-113.766 0.053-170.648-0.053-13.359 0-22.657-8.523-22.576-20.065 0.080-11.569 9.298-19.611 22.79-19.878 2.004-0.027 3.981 0 5.985 0 26.29 0 52.555 0 78.845 0z","M523.927 435.986c23.618 0 47.211-0.053 70.83 0 14.669 0.053 23.378 7.668 23.298 20.092-0.080 12.344-8.791 19.824-23.565 19.851-46.891 0.053-93.78 0.053-140.671 0-14.776 0-23.645-7.428-23.886-19.611-0.24-12.558 8.871-20.305 24.126-20.332 23.271-0.053 46.57 0 69.841 0z","M261.875 435.986c20.973 0 41.974-0.080 62.948 0.027 13.546 0.080 22.737 8.256 22.817 19.851 0.053 11.623-9.138 20.038-22.603 20.065-42.642 0.107-85.258 0.107-127.9 0-13.466-0.027-22.737-8.31-22.817-19.878s9.191-19.958 22.63-20.038c21.641-0.134 43.31-0.027 64.952-0.027z","M449.009 699.988c-19.664 0-39.329 0.107-58.993-0.027-13.947-0.107-22.416-7.829-22.389-20.038 0.027-12.184 8.47-19.851 22.523-19.878 39.65-0.107 79.326-0.080 118.976 0 14.108 0.027 22.71 7.535 22.95 19.53 0.24 12.478-8.523 20.332-23.084 20.412-19.985 0.107-39.997 0.027-59.982 0z","M245.737 699.988c-16.325 0-32.676 0.134-49.001-0.027-13.306-0.134-22.657-8.737-22.443-20.279 0.214-11.249 9.245-19.557 22.069-19.611 32.997-0.134 65.994-0.16 98.99 0 12.852 0.053 21.802 8.416 21.908 19.744 0.107 11.356-8.817 19.958-21.561 20.118-16.673 0.24-33.344 0.053-49.99 0.053z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["form"],"grid":32},"attrs":[],"properties":{"order":2,"id":1,"name":"form","prevSize":32,"code":59703},"setIdx":2,"setId":8,"iconIdx":1},{"icon":{"paths":["M389.678 1000.324c-1.456 0-1.456 0 0 0-11.648 0-21.841-4.369-29.121-13.103l-336.344-381.483c-14.56-16.017-13.104-40.768 2.912-55.33 16.016-14.558 40.769-13.103 55.329 2.914l307.223 347.994 850.868-864.659c14.562-16.016 39.313-17.472 55.33-2.912s17.472 39.313 2.914 55.329l-879.992 896.692c-8.736 10.189-18.928 14.558-29.12 14.558z"],"width":1323,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["tick"],"grid":32},"attrs":[],"properties":{"order":191,"id":2,"name":"tick","prevSize":32,"code":59704},"setIdx":2,"setId":8,"iconIdx":2},{"icon":{"paths":["M110.599 231.356c0-10.728 0.768-20.563-0.187-30.251-1.27-12.78 4.401-20.294 15.852-26.777 60.918-34.514 126.169-53.322 197.652-49.914 60.446 2.879 116.578 20.424 169.877 46.57 7.483 3.678 12.938 3.688 20.468 0.028 62.161-30.26 127.508-49.152 198.313-46.737 64.354 2.192 122.671 22.115 176.581 54.623 6.664 4.022 8.448 9.696 8.389 16.57-0.118 11.629-0.032 23.266-0.032 35.889 18.798 0 36.384-0.019 53.957 0.009 15.458 0.028 19.803 4.050 19.803 18.595 0.020 211.033 0.020 422.063 0 633.086 0 14.434-4.521 18.68-19.862 18.68-298.22 0.020-596.43 0.008-894.65 0-15.39 0-19.899-4.218-19.899-18.621-0.020-211.035-0.020-422.065 0-633.090 0-14.61 4.293-18.622 19.732-18.65 17.566-0.037 35.151-0.009 54.006-0.009zM868.427 793.076c0-5.498 0-9.094 0-12.678 0-121.561 0-243.133 0-364.694 0-69.4 0.091-138.8-0.236-208.2-0.020-3.846-2.312-9.427-5.463-11.248-46.86-26.972-97.469-42.864-152.694-44.369-64.768-1.755-124.318 16.022-181.575 42.818-7.266 3.399-9.303 7.523-9.303 14.861 0.205 190.672 0.165 381.356 0.165 572.029 0 3.186 0 6.372 0 11.099 116.795-57.687 232.034-57.754 349.105 0.382zM139.694 793.096c117.1-58.329 232.655-58.041 349.097-0.449 0-5.423 0-9.082 0-12.753 0-92.255 0-184.505 0-276.764 0-98.115-0.098-196.235 0.205-294.344 0.020-7.3-2.233-11.248-9.236-13.978-19.594-7.644-38.624-16.718-58.553-23.443-93.274-31.458-183.445-25.654-270.042 21.14-8.222 4.449-12.436 8.953-11.766 18.594 1.083 15.65 0.295 31.412 0.295 47.127 0 174.327 0 348.651 0 522.979 0 3.316 0 6.632 0 11.89zM897.524 259.22c0 5.108 0 9.353 0 13.607 0 177.697 0 355.385-0.012 533.085 0 3.391 0.169 6.81-0.165 10.169-1.162 11.91-10.949 17.128-22.363 11.926-3.23-1.465-6.25-3.332-9.374-5.006-46.935-24.966-96.61-41.878-150.792-45.438-71.306-4.671-136.302 14.202-197.12 47.762-9.649 5.321-17.054 5.683-26.88 0.205-47.825-26.695-99.034-44.221-154.921-47.947-69.878-4.651-134.065 13.032-193.644 46.041-20.175 11.173-32.089 6.345-32-17.302 0.63-178.007 0.345-356.009 0.345-534.005 0-4.189 0-8.378 0-12.669-15.596 0-29.755 0-43.806 0 0 205.071 0 409.414 0 613.919 291.879 0 583.049 0 874.389 0 0-205.072 0-409.639 0-614.337-14.545-0.009-28.219-0.009-43.658-0.009z","M572.648 467.543c0-12.958 0.414-25.923-0.146-38.853-0.354-8.153 2.745-14.068 8.901-19.468 21.386-18.742 47.242-28.466 75.449-32.664 43.236-6.437 85.299-2.006 125.657 14.582 2.69 1.105 5.27 2.461 7.936 3.612 23.328 10.039 37.337 24.225 33.792 51.346-2.777 21.268-0.039 43.134-0.965 64.689-0.205 4.876-4.38 11.563-8.763 13.718-3.868 1.906-11.953 0.307-15.84-2.564-37.691-27.845-81.105-34.001-126.909-30.137-28.219 2.379-54.055 10.961-74.988 30.436-3.1 2.887-11.173 4.187-14.946 2.414-4.234-1.977-8.409-8.137-8.743-12.725-1.091-14.73-0.402-29.582-0.433-44.386zM601.943 483.6c31.468-16.049 63.594-21.406 97.083-20.563 33.15 0.835 64.815 7.924 95.358 22.532 0-16.522-0.512-31.346 0.209-46.112 0.382-7.904-2.729-12.355-9.708-16.124-36.029-19.468-74.89-24.608-115.476-20.519-22.048 2.221-42.91 8.259-60.841 21.122-2.974 2.135-6.211 6.065-6.329 9.267-0.642 16.313-0.295 32.63-0.295 50.397z","M684.103 641.115c40.893-0.008 77.568 5.872 111.124 23.804 8.44 4.517 16.325 10.228 23.591 16.313 6.518 5.451 6.372 13.505 0.65 18.916-5.908 5.585-13.182 6.439-19.424 1.414-26.852-21.614-58.919-29.566-92.979-32.165-27.707-2.119-54.949 0.575-80.226 12.067-10.090 4.588-19.121 11.524-28.030 18.101-7.908 5.833-15.844 6.707-21.858 1.020-6.038-5.703-5.86-13.615 1.111-20.508 20.689-20.452 47.006-30.527 75.808-35.497 10.87-1.879 21.984-2.556 30.236-3.466z","M687.722 284.635c44.579 0.492 82.133 7.895 115.877 28.403 5.187 3.158 10.169 6.762 14.659 10.756 6.774 6.028 7.050 13.913 1.378 19.756-5.364 5.526-13.162 6.028-20.252 0.966-49.349-35.248-104.184-39.613-161.528-23.601-13.792 3.855-26.12 13.31-38.183 21.446-8.921 6.019-16.148 7.588-22.556 1.672-6.361-5.879-5.9-13.811 1.595-21.112 21.878-21.325 49.676-31.143 79.904-35.703 11.232-1.709 22.705-2.043 29.105-2.582z","M686.868 195.5c42.409 0.334 77.324 6.799 109.265 24.084 7.865 4.254 15.262 9.52 22.095 15.167 7.038 5.814 7.109 13.839 1.359 19.672-5.435 5.536-13.47 6.334-20.224 0.845-22.942-18.641-50.393-26.805-79.549-30.483-27.431-3.464-55.107-3.213-81.081 6.623-13.915 5.276-26.742 13.607-39.101 21.836-9.027 6.019-16.156 7.588-22.587 1.588-6.282-5.852-5.797-13.886 1.686-21.149 21.394-20.768 48.451-30.734 78.009-35.341 11.886-1.848 24.005-2.285 30.129-2.842z","M825.49 602.317c-3.525 4.167-5.939 9.779-9.878 10.996-4.785 1.477-12.493 1.15-16.128-1.654-31.082-23.926-67.592-31.634-106.208-31.811-35.753-0.158-69.534 6.613-96.315 31.783-5.9 5.545-14.887 4.801-20.236-0.512-5.455-5.423-5.62-12.898 0.354-19.153 14.375-15.045 32.453-24.938 52.748-30.744 54.91-15.722 108.493-11.681 160.098 11.882 9.866 4.506 18.696 11.229 27.42 17.629 3.281 2.406 4.915 6.833 8.145 11.583z","M435.436 646.963c0 13.875 0.709 27.809-0.374 41.61-0.394 5.025-3.899 12.040-8.125 13.978-4.234 1.942-12.603 0.437-16.648-2.564-34.688-25.691-74.811-32.433-117.239-30.582-12.908 0.567-25.876 3.296-38.469 6.325-16.679 4.009-31.143 12.071-43.963 23.257-3.801 3.316-11.894 5.545-16.325 3.982-4.401-1.548-9.285-8.432-9.422-13.103-0.857-28.971-0.837-57.986-0.040-86.965 0.138-5.041 4.273-10.969 8.359-14.777 21.819-20.311 49.319-29.692 78.927-33.768 43.018-5.92 84.667-0.839 124.486 16.030 3.269 1.382 6.349 3.159 9.598 4.616 21.004 9.429 34.009 22.961 29.491 47.006-1.528 8.090-0.256 16.628-0.256 24.958zM406.154 663.209c0-15.762-0.532-30.736 0.217-45.651 0.394-7.952-2.788-12.316-9.767-16.049-34.147-18.215-70.903-23.993-109.509-20.972-23.404 1.827-45.617 7.515-65.073 20.563-3.082 2.060-7.69 4.978-7.798 7.633-0.709 17.286-0.365 34.607-0.365 52.46 64.955-28.924 128.158-24.974 192.296 2.016z","M435.424 289.504c0 14.805 0.618 29.648-0.386 44.397-0.295 4.365-4.175 10.31-8.16 12.14-3.97 1.811-11.658 1.133-15.084-1.505-34.601-26.526-75.039-34.003-117.821-31.403-17.92 1.087-36.076 5.48-53.071 11.173-11.234 3.762-20.313 12.966-30.937 18.808-4.569 2.517-11.461 4.858-15.705 3.334-4.293-1.542-9.246-7.895-9.364-12.26-0.817-29.592-0.719-59.22-0.108-88.83 0.089-4.263 3.574-9.288 6.991-12.548 23.66-22.57 53.75-32.285 86.183-35.768 40.645-4.356 80.197 0.334 117.809 16.356 3.269 1.393 6.353 3.167 9.59 4.616 21.22 9.502 35.281 22.7 30.326 47.452-1.556 7.746-0.244 15.994-0.244 24.019 0 0.019-0.012 0.019-0.020 0.019zM406.17 306.576c0-16.328-0.343-31.727 0.169-47.090 0.217-6.372-2.048-10.143-7.719-13.366-31.883-18.111-66.719-24.056-103.307-22.653-26.87 1.031-52.362 6.715-74.555 21.92-2.905 1.988-6.597 5.35-6.695 8.183-0.63 16.774-0.315 33.576-0.315 50.982 64.719-28.709 127.99-25.022 192.423 2.025z","M437.472 424.389c-3.84 4.226-6.388 9.484-10.417 10.811-4.45 1.477-11.784 1.154-15.21-1.465-34.857-26.667-75.552-33.642-118.648-31.783-31.321 1.355-60.475 8.98-83.653 30.834-6.489 6.12-15.212 5.73-20.913 0.083-5.809-5.746-5.79-13.158 0.876-19.818 18.068-18.074 40.763-28.525 66.107-33.819 52.539-10.969 103.148-5.888 151.032 17.927 7.995 3.974 15.328 9.389 22.26 14.935 3.419 2.721 5.191 7.282 8.566 12.296z","M301.13 462.73c38.853 0.689 72.35 6.585 103.196 22.347 8.834 4.513 17.073 10.283 24.891 16.293 7.7 5.923 8.192 14.21 2.402 20.283-5.494 5.77-13.47 5.927-21.059 0.634-50.679-35.379-106.388-39.597-164.648-21.858-12.544 3.82-23.621 12.709-34.53 20.315-8.556 5.963-16.492 7.263-22.597 1.319-6.311-6.14-5.79-13.71 2.068-21.177 23.158-22.020 52.332-31.846 84.076-36.001 9.994-1.308 20.145-1.67 26.201-2.154z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["book"],"grid":32},"attrs":[],"properties":{"order":96,"id":3,"name":"book","prevSize":32,"code":59697},"setIdx":2,"setId":8,"iconIdx":3},{"icon":{"paths":["M0.027 925.196c0.639 1.786 1.449 3.49 1.891 5.325 8.251 34.873 34.306 58.896 67.826 59.945 35.878 1.098 71.805 0.496 107.683 0.365 9.43-0.025 15.152-6.16 15.053-14.709-0.098-8.495-5.82-14.451-15.348-14.504-32.513-0.233-65.051-0.102-97.589-0.131-34.331-0.049-51.889-18.932-51.889-55.853 0-177.287 0-354.55 0-531.837 0-3.593 0-7.159 0-11.564 295.764 0 591.064 0 887.737 0 0 12.849 0 25.777 0 38.73 0 5.9 0.147 11.799-0.025 17.701-0.246 8.311 0.659 15.888 9.183 19.378 8.692 3.564 13.701-2.179 18.489-8.446 0-79.321 0-158.643 0-237.992-0.467-1.18-1.053-2.307-1.372-3.54-11.051-42.637-36.368-63.379-77.431-63.405-7.537 0-15.102 0-22.467 0-5.526-51.422-23.749-75.913-57.811-79.008-15.225-1.39-29.27 2.072-41.869 11.407-22.024 16.31-28.828 40.146-27.722 66.814-60.584 0-119.939 0-179.196 0-4.862-51.553-24.162-76.385-60.383-78.431-15.643-0.865-29.762 3.724-42.041 14.055-19.472 16.389-25.835 38.809-24.165 64.664-60.533 0-119.887 0-180.052 0 0.884-19.85-2.063-38.284-14.046-53.755-12.18-15.733-27.799-24.308-47.027-25.016-14.955-0.551-28.511 3.881-40.347 13.662-19.891 16.415-26.399 39.124-24.852 65.661-11.173 0-20.947-0.157-30.721 0.026-31.384 0.629-58.667 22.603-68.048 54.725-1.179 4.038-2.284 8.076-3.438 12.141-0.025 244.521-0.025 489.044-0.025 733.591zM228.407 154.711c60.484 0 119.863 0 180.273 0 0 15.235-0.516 29.945 0.123 44.578 1.203 27.769 14.097 47.934 37.768 59.026 23.798 11.144 46.338 6.923 66.183-10.908 14.070-12.665 21.438-29.238 21.66-49.062 0.172-14.579 0.025-29.159 0.025-43.502 60.998 0 120.353 0 180.298 0 0 15.419-0.418 30.156 0.074 44.866 1.372 40.592 36.884 70.616 74.256 63.117 30.773-6.162 51.032-32.542 51.818-67.811 0.295-13.321 0.049-26.642 0.049-40.854 10.314 0 19.448-0.105 28.582 0.026 25.956 0.367 45.605 20.847 45.801 48.432 0.27 41.3 0.074 82.6 0.049 123.9 0 1.547-0.418 3.095-0.639 4.615-295.789 0-591.137 0-886.852 0 0-44.971-0.786-89.208 0.368-133.366 0.516-19.509 11.493-34.849 29.223-40.041 14.022-4.091 29.272-3.33 45.013-4.799 0 17.884-0.835 32.988 0.172 47.987 2.48 37.367 31.040 64.69 65.051 63.274 34.012-1.442 60.361-31.047 60.705-68.309 0.098-13.478 0-26.878 0-41.168zM742.261 155.104c0-14.081-0.172-28.136 0.049-42.218 0.319-21.056 14.59-37.052 33.62-38.048 19.546-1.023 36.221 13.74 36.934 35.138 0.983 29.736 0.958 59.551-0.025 89.287-0.688 20.847-17.265 35.977-36 35.374-19.206-0.603-34.185-17.071-34.505-38.337-0.246-13.714-0.074-27.455-0.074-41.195zM129.737 154.921c0-13.74-0.295-27.507 0.074-41.221 0.638-22.971 15.569-39.018 35.681-38.914 20.481 0.105 35.19 16.808 35.264 40.303 0.098 26.17 0.073 52.34 0 78.535-0.074 23.547-14.513 40.566-34.724 41.064-20.456 0.498-35.853-16.52-36.27-40.487-0.221-13.085-0.049-26.196-0.025-39.281zM436.208 154.711c0-14.055-0.221-28.137 0.049-42.192 0.442-21.922 15.766-37.943 35.656-37.734 19.55 0.21 34.628 16.1 34.873 37.55 0.319 28.136 0.295 56.273 0 84.409-0.246 21.633-16.11 38.206-35.607 37.944-19.231-0.262-34.456-16.546-34.898-37.786-0.319-14.055-0.074-28.136-0.074-42.191z","M943.038 482.664c-4.985-6.033-10.166-11.67-18.711-7.999-8.446 3.621-8.962 11.305-8.962 19.562 0.074 137.327 0.049 274.625 0.049 411.951 0 36.213-17.732 55.276-51.499 55.276-203.158 0.029-406.319 0-609.479 0.029-3.978 0-8.030-0.16-11.935 0.471-7.785 1.286-12.131 6.66-11.861 14.893 0.27 7.684 4.567 12.743 12.033 13.713 3.634 0.475 7.342 0.369 11.026 0.369 202.864 0.025 405.706 0.025 608.573 0 43.463 0 67.85-19.694 79.663-64.246 0.147-0.578 0.733-0.995 1.102-1.495 0-147.526 0-295.023 0-442.524z","M231.861 543.375c0-13.742 0.147-27.509-0.024-41.251-0.27-20.922-12.647-34.374-32.367-34.611-26.055-0.315-52.134-0.315-78.189 0.025-19.277 0.262-31.506 13.271-31.801 34.013-0.368 28.16-0.393 56.324 0.025 84.484 0.295 20.193 12.254 33.198 31.237 33.62 26.35 0.578 52.749 0.524 79.098 0.025 19.769-0.369 31.678-13.951 31.998-35.033 0-0.315 0-0.655 0-0.971 0.025-13.451 0.024-26.878 0.024-40.301zM116.984 543.638c0-12.771 0.196-25.543-0.074-38.285-0.147-6.373 2.136-8.602 8.079-8.524 23.894 0.238 47.813 0.209 71.707 0.029 5.403-0.029 7.686 1.888 7.637 7.942-0.196 25.858-0.196 51.712 0 77.541 0.049 5.976-2.112 8.102-7.563 8.049-23.894-0.156-47.813-0.209-71.707 0.029-5.894 0.049-8.276-2.126-8.153-8.524 0.27-12.743 0.074-25.514 0.074-38.257z","M853.68 542.753c0-13.427 0.197-26.853-0.049-40.28-0.393-21.869-12.427-34.82-32.784-35.004-25.44-0.238-50.905-0.209-76.345 0-20.701 0.156-33.153 13.558-33.276 35.66-0.147 27.169-0.172 54.358 0 81.527 0.147 21.058 12.255 34.64 31.998 35.004 26.055 0.5 52.134 0.475 78.189 0.029 19.964-0.34 31.777-13.373 32.195-34.693 0.295-14.053 0.074-28.164 0.074-42.242zM738.804 544.535c0-12.771 0.221-25.543-0.098-38.285-0.172-6.451 1.327-9.572 8.102-9.466 23.896 0.315 47.813 0.238 71.709 0.053 5.526-0.053 7.635 2.097 7.61 8.024-0.172 25.854-0.172 51.708 0 77.537 0.025 5.956-2.183 8.053-7.66 8.024-23.896-0.184-47.813-0.184-71.709 0-5.894 0.053-8.225-2.097-8.053-8.573 0.344-12.431 0.098-24.887 0.098-37.315z","M853.676 779.547c0-13.423 0.123-26.849-0.025-40.276-0.27-23.077-12.304-35.873-33.767-35.951-25.145-0.078-50.291-0.131-75.44 0-20.627 0.106-33.124 13.505-33.247 35.635-0.147 26.853-0.123 53.703 0 80.556 0.098 22.34 12.177 35.635 32.977 35.873 25.764 0.287 51.524 0.311 77.283-0.029 19.915-0.262 31.752-13.165 32.17-34.587 0.27-13.713 0.049-27.48 0.049-41.222zM826.049 778.629c0 13.087-0.147 26.169 0.074 39.256 0.098 5.796-1.794 8.208-7.442 8.18-24.187-0.184-48.402-0.184-72.589 0-5.575 0.053-7.442-2.281-7.393-8.155 0.221-25.514 0.221-51.028 0-76.542-0.049-6.267 1.769-8.733 7.86-8.679 23.892 0.262 47.788 0.262 71.655 0 6.164-0.078 8.032 2.519 7.885 8.679-0.221 12.403-0.049 24.834-0.049 37.261z","M160.222 703.283c-12.868 0-25.76-0.16-38.628 0.025-19.277 0.291-31.801 13.009-32.121 33.669-0.417 28.164-0.393 56.328-0.025 84.488 0.295 20.82 12.352 33.616 31.85 33.882 26.055 0.365 52.134 0.365 78.189 0 19.867-0.266 32.145-13.558 32.292-34.562 0.197-27.509 0.172-55.013 0-82.522-0.147-21.475-12.77-34.771-32.931-34.98-12.868-0.106-25.76 0-38.628 0zM204.204 778.621c0 13.083-0.196 26.169 0.098 39.252 0.123 5.874-1.792 8.208-7.367 8.184-24.189-0.184-48.402-0.184-72.591 0-5.623 0.049-7.49-2.363-7.441-8.155 0.172-25.829 0.123-51.687 0.025-77.513-0.025-5.247 1.645-7.684 6.925-7.66 24.508 0.184 49.016 0.16 73.499 0 5.206-0.025 6.999 2.257 6.925 7.631-0.221 12.747-0.074 25.514-0.074 38.261z","M438.903 779.174c0-13.742 0.147-27.509-0.025-41.251-0.27-21.238-12.403-34.427-32.122-34.558-26.055-0.213-52.135-0.238-78.189 0.025-19.032 0.184-31.752 13.767-31.9 34.009-0.197 28.164-0.221 56.328 0.025 84.488 0.172 19.378 12.205 33.014 30.426 33.407 27.283 0.606 54.59 0.606 81.849-0.025 17.952-0.418 29.445-13.636 29.838-32.829 0.295-14.451 0.074-28.873 0.098-43.266zM324.22 779.96c0-13.087 0.196-26.169-0.098-39.256-0.147-5.98 1.891-8.077 7.465-8.024 24.189 0.209 48.402 0.184 72.591 0.025 5.034-0.025 7.171 1.708 7.147 7.32-0.147 26.169-0.172 52.339 0 78.508 0.025 5.505-1.916 7.524-6.999 7.5-24.189-0.131-48.402-0.209-72.591 0.053-6.213 0.078-7.809-2.675-7.637-8.81 0.368-12.431 0.123-24.887 0.123-37.315z","M504.152 544.109c0 14.082-0.221 28.164 0.049 42.246 0.393 19.169 11.637 32.567 29.639 33.116 27.578 0.815 55.206 0.84 82.78-0.025 18.199-0.549 29.643-14.553 29.741-34.193 0.147-27.82 0.172-55.669 0-83.493-0.123-20.349-12.501-33.956-31.678-34.247-26.374-0.393-52.748-0.393-79.098 0-19.206 0.291-31.113 13.611-31.408 34.353-0.197 14.082-0.049 28.164-0.025 42.242zM618.807 543.142c0 12.767-0.197 25.539 0.098 38.281 0.147 6.005-1.253 9.048-7.565 8.995-24.211-0.233-48.423-0.184-72.614-0.053-5.157 0.029-7.025-2.15-7-7.578 0.147-26.169 0.147-52.363 0-78.537-0.025-5.558 2.040-7.447 7.098-7.418 24.211 0.156 48.427 0.156 72.614 0 5.501-0.053 7.614 2.044 7.467 8.049-0.319 12.743-0.098 25.489-0.098 38.261z","M438.886 543.666c0-14.082 0.197-28.164-0.049-42.246-0.344-20.558-12.427-33.64-31.827-33.903-26.055-0.315-52.134-0.315-78.189 0-19.695 0.233-32.072 13.791-32.17 34.742-0.147 27.509-0.147 55.013 0 82.522 0.098 20.582 11.959 34.402 31.138 34.849 26.669 0.631 53.362 0.602 80.031 0.025 19.351-0.442 30.82-13.816 31.065-34.718 0.147-13.767 0.025-27.533 0-41.271zM367.965 496.939c11.96 0 23.894 0.18 35.853-0.082 5.501-0.131 7.613 1.97 7.564 7.946-0.197 25.854-0.197 51.712 0 77.566 0.049 5.927-1.94 8.102-7.49 8.077-23.894-0.184-47.812-0.184-71.706 0-5.82 0.053-8.104-1.942-8.030-8.495 0.27-25.518 0.27-51.057 0-76.571-0.074-6.476 2.063-8.679 7.981-8.524 11.91 0.291 23.869 0.053 35.829 0.082z","M504.144 779.465c0 14.082-0.197 28.16 0.049 42.242 0.369 20.218 12.083 33.276 31.064 33.62 26.669 0.471 53.363 0.496 80.032 0 19.177-0.369 30.99-14.004 31.089-34.746 0.123-27.509 0.147-55.013 0-82.522-0.098-20.951-12.644-34.533-32.17-34.689-26.055-0.213-52.134-0.238-78.189 0-19.227 0.18-31.359 13.32-31.875 33.878-0.025 0.655-0.025 1.311-0.025 1.966 0 13.398 0 26.825 0.025 40.251zM618.775 825.905c-28.287 0-55.177 0.102-82.067-0.291-1.671-0.025-4.714-4.039-4.739-6.238-0.344-26.485-0.172-52.998-0.27-79.483-0.025-4.825 1.475-7.184 6.337-7.156 24.801 0.131 49.627-0.082 74.433 0.34 2.134 0.025 5.992 3.777 6.017 5.849 0.414 28.398 0.291 56.795 0.291 86.979z"],"width":983,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["calendar"],"grid":32},"attrs":[],"properties":{"order":97,"id":4,"name":"calendar","prevSize":32,"code":59698},"setIdx":2,"setId":8,"iconIdx":4},{"icon":{"paths":["M2560 512l-768-443.405v886.81l768-443.405zM-0 588.8h1868.8v-153.6h-1868.8l-0 153.6z"],"width":2560,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{},"tags":["dark-arrow"],"grid":32},"attrs":[],"properties":{"order":107,"id":5,"name":"small-right-arrow","prevSize":32,"code":59700},"setIdx":2,"setId":8,"iconIdx":5},{"icon":{"paths":["M848.842 693.895l-294.066-294.367-21.522 21.524 272.844 272.842h42.744z","M138.543 693.895l355.604-355.604-21.524-21.524-377.128 377.128h43.048z"],"width":970,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"243115381255124491":[]},"tags":["ChevronDown"],"grid":32},"attrs":[],"properties":{"order":105,"id":6,"name":"chevron-up","prevSize":32,"code":59695},"setIdx":2,"setId":8,"iconIdx":6},{"icon":{"paths":["M121.158 330.105l294.066 294.367 21.522-21.524-272.844-272.842h-42.744z","M831.457 330.105l-355.604 355.604 21.524 21.524 377.128-377.128h-43.048z"],"width":970,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"243115381255124491":[]},"tags":["ChevronDown"],"grid":32},"attrs":[],"properties":{"order":106,"id":7,"prevSize":32,"name":"chevron-down","code":59696},"setIdx":2,"setId":8,"iconIdx":7},{"icon":{"paths":["M669.882 1001.112c0.057-0.004 0.11-0.008 0.163-0.011 11.196-0.713 20.647-7.98 24.072-18.641l307.849-923.539c0.265-0.797 0.345-1.594 0.436-2.455 0.038-0.386 0.080-0.784 0.14-1.201 0.095-0.674 0.239-1.299 0.383-1.924s0.288-1.25 0.387-1.924c0-2.694-0.387-5.387-0.963-7.889-0.193-0.577-0.193-1.732-0.193-1.732l-0.19-0.192c-1.157-3.078-2.886-5.965-5.002-8.466-0.77-1.154-1.927-1.924-2.886-2.501-0.292-0.289-0.565-0.589-0.842-0.89-0.831-0.902-1.661-1.804-2.814-2.381l-0.77-0.77c-0.675-0.289-1.301-0.529-1.927-0.77-0.622-0.24-1.248-0.481-1.923-0.77-1.923-0.77-3.849-1.154-5.772-1.539-0.576 0-1.202-0.048-1.828-0.096s-1.252-0.096-1.828-0.096c-2.31 0-4.233 0.385-6.349 0.962-0.77 0-2.116 0.192-2.116 0.192l-923.538 307.846c-10.775 3.463-18.086 13.084-18.663 24.435-0.385 7.696 2.501 15.2 7.889 20.587 2.309 2.308 5.002 4.231 7.889 5.581l414.053 188.169 188.173 414.053c1.346 2.886 3.269 5.579 5.579 7.889 5.302 5.302 12.652 8.181 20.218 7.904 0.053 0 0.11-0.004 0.167-0.004 0.068-0.004 0.133-0.008 0.201-0.011l-0.193 0.193c0.068-0.004 0.137-0.008 0.201-0.011zM664.117 892.564l-165.619-364.426-364.587-165.692 795.274-265.092-265.068 795.21z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"243115381255124491":[]},"tags":["navigation"],"grid":32},"attrs":[],"properties":{"order":97,"id":8,"name":"navigation","prevSize":32,"code":59690},"setIdx":2,"setId":8,"iconIdx":8},{"icon":{"paths":["M699.78 2.858c-33.987 6.2-62.309 21.402-88.204 46.803-20.030 19.801-33.786 41.203-41.27 64.605-11.937 37.403-11.937 60.804 0.403 110.808 0.81 3.4-16.995 15.001-136.152 88.006-75.261 46.002-137.773 84.005-138.582 84.406s-8.699-5.201-17.398-12.4c-18.612-15.602-45.722-29.603-68.38-35.604-21.647-5.601-60.288-5.998-80.923-0.801-51.184 13.203-95.287 49.006-115.518 94.41-10.52 23.8-13.757 39.803-13.757 68.803s3.237 45.003 13.757 68.803c20.028 44.404 63.322 80.409 112.685 93.407 23.266 6.2 60.288 6.2 83.755 0.202 22.658-6.001 49.768-20.002 68.38-35.604 8.699-7.199 16.589-12.8 17.398-12.4s63.321 38.403 138.582 84.406c119.156 73.005 136.962 84.607 136.152 88.005-12.341 50.204-12.341 74.808-0.202 111.21 8.294 24.402 20.027 43.002 40.259 63.206 27.31 27.4 57.049 42.803 94.478 48.801 84.765 13.601 167.914-41.202 189.964-125.009 9.306-35.201 4.453-80.406-12.341-114.008-29.131-58.402-87.599-93.805-153.752-93.404-43.7 0.199-80.722 14.6-113.493 44.001l-10.926 9.802-74.854-46.006c-41.069-25.2-103.582-63.404-138.581-84.806-34.999-21.6-63.929-39.201-64.13-39.402-0.202-0.199 1.213-6.001 3.438-13.002 9.104-30.202 9.104-66.203 0-96.405-2.225-7-3.64-12.803-3.438-13.002 0.202-0.202 29.131-17.802 64.13-39.402 34.999-21.402 97.513-59.606 138.581-84.806l74.854-46.004 12.542 11.201c51.588 45.602 126.039 56.003 187.743 26.202 44.507-21.602 78.696-63.605 90.227-111.008 6.070-24.202 6.070-57.404 0-80.006-22.658-86.006-108.032-140.21-195.429-124.009zM759.665 65.062c55.433 16.201 88.812 71.605 75.661 126.409-4.651 19.201-14.162 35.802-29.131 50.604-22.86 22.602-50.983 33.202-82.137 31.202-28.12-2-50.375-12.001-69.796-31.602-42.484-42.603-40.259-113.008 4.655-153.011 11.531-10.201 25.085-17.601 41.875-23.002 14.569-4.6 43.902-5 58.874-0.6zM203.724 411.487c30.953 11 55.635 35.604 66.357 66.405 6.676 18.401 6.676 49.605 0 68.006-10.925 30.602-35.606 55.603-65.952 66.203-16.994 6.001-44.508 7.202-61.704 2.802-48.351-12.403-80.923-53.803-80.923-102.81 0-48.401 30.548-88.604 77.888-102.605 16.589-4.8 47.745-3.801 64.334 1.998zM755.011 752.913c39.045 9.2 71.010 40.603 80.316 79.205 13.151 55.004-20.027 110.409-75.661 126.61-14.364 4.198-42.688 4.198-57.052 0-37.426-11.003-64.332-37.603-75.459-74.606-4.046-13.802-4.248-39.803-0.202-55.203 10.318-39.005 45.72-71.007 85.979-77.607 11.329-1.8 30.146-1.201 42.080 1.601z"],"width":900,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"2551244912552552551":[],"243115381255124491":[]},"tags":["share"],"grid":32},"attrs":[],"properties":{"order":93,"id":9,"name":"share","prevSize":32,"code":59685},"setIdx":2,"setId":8,"iconIdx":9}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":false,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon"},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon","height":32,"columns":16,"margin":16},"historySize":50,"showCodes":true,"gridSize":16,"showGrid":true}}
\ No newline at end of file
export { default } from './Icon';
export * from './Icon';
@font-face {
font-family: 'icomoon';
src: url('./font/icomoon.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: block;
}
.icon {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icomoon' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-forward-arrow:before {
content: '\e920';
}
.icon-residence:before {
content: '\e91c';
}
.icon-store:before {
content: '\e91d';
}
.icon-download:before {
content: '\e91e';
}
.icon-basement:before {
content: '\e91f';
}
.icon-email-light:before {
content: '\e917';
}
.icon-location-pin:before {
content: '\e918';
}
.icon-phone-light:before {
content: '\e919';
}
.icon-tower:before {
content: '\e900';
}
.icon-area:before {
content: '\e902';
}
.icon-office:before {
content: '\e910';
}
.icon-long-right-arrow:before {
content: '\e91a';
}
.icon-location:before {
content: '\e915';
}
.icon-play:before {
content: '\e916';
}
.icon-chat:before {
content: '\e901';
}
.icon-email:before {
content: '\e904';
}
.icon-left-arrow:before {
content: '\e903';
}
.icon-phone:before {
content: '\e905';
}
.icon-right-arrow:before {
content: '\e906';
}
.icon-down-arrow:before {
content: '\e913';
}
.icon-up-arrow:before {
content: '\e914';
}
.icon-menu:before {
content: '\e912';
}
.icon-scroll:before {
content: '\e911';
}
.icon-close:before {
content: '\e90f';
}
.icon-facebook:before {
content: '\e90e';
}
.icon-global:before {
content: '\e909';
}
.icon-instagram:before {
content: '\e907';
}
.icon-linkedin:before {
content: '\e908';
}
.icon-search:before {
content: '\e90a';
}
.icon-tiktok:before {
content: '\e90b';
}
.icon-x:before {
content: '\e90c';
}
.icon-youtube:before {
content: '\e90d';
}
.icon-long-left-arrow:before {
content: '\e91b';
}
.icon-form:before {
content: '\e937';
}
.icon-tick:before {
content: '\e938';
}
.icon-book:before {
content: '\e931';
}
.icon-calendar:before {
content: '\e932';
}
.icon-small-right-arrow:before {
content: '\e934';
}
.icon-chevron-up:before {
content: '\e92f';
}
.icon-chevron-down:before {
content: '\e930';
}
.icon-navigation:before {
content: '\e92a';
}
.icon-share:before {
content: '\e925';
}
import type { Meta, StoryObj } from '@storybook/react';
import PhoneInputComponent from './PhoneInput';
const meta: Meta<typeof PhoneInputComponent> = {
title: 'Base/PhoneInput',
component: PhoneInputComponent,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
export const PhoneInput: Story = {
args: {
isInValid: false,
label: 'Mobile'
}
};
import Input, { PhoneInputProps } from 'react-phone-input-2';
import cn from '@/lib/merge-clsx';
import 'react-phone-input-2/lib/high-res.css';
import styles from './style.module.css';
interface IPhoneInputProps extends PhoneInputProps {
label: string;
name: string;
isInValid: boolean;
}
const PhoneInput: React.FC<IPhoneInputProps> = ({ label, name, ...props }) => {
return (
<div>
<label
htmlFor={name}
className={cn(styles.label, {
[styles.labelInvalid]: props.isInValid
})}>
{label}
</label>
<Input
{...props}
containerClass={cn(
styles.container,
props.isInValid && styles.containerInvalid
)}
inputClass={styles.input}
buttonClass={styles.button}
dropdownClass={styles.dropdown}
searchClass={styles.search}
/>
</div>
);
};
export default PhoneInput;
export { default } from './PhoneInput';
export * from './PhoneInput';
.label {
@apply text-primary-500 opacity-60 text-lg ps-1;
:global(.dark) & {
@apply text-white;
}
}
.labelInvalid {
@apply !text-danger;
}
.container {
@apply w-full !bg-transparent pb-1.5 border-b-1 border-primary-200 relative;
:global(.dark) & {
@apply border-white after:bg-white;
}
}
.container::after {
content: '';
@apply absolute bottom-0 left-1/2 w-0 h-[1px] bg-black origin-center transition-all duration-300;
}
.container:focus-within::after {
@apply w-full -left-0;
}
.container :global(.flag-dropdown) {
@apply !border-b-[1px] !border-primary-200 hover:!border-primary-800;
:global(.dark) & {
@apply !border-white;
}
}
.container :global(.form-control:focus) {
@apply !border-primary-800 !border-b-[1px];
:global(.dark) & {
@apply !border-white;
}
}
.containerInvalid :global(.form-control:focus) {
@apply !border-b-[2px] !border-b-danger;
}
.containerInvalid {
@apply !border-danger-500 hover:!border-danger-500;
}
.containerInvalid::after {
@apply bg-danger;
}
.input {
@apply !w-full !border-none !bg-transparent !rounded-none !font-sans !text-base;
}
.button {
@apply !pb-1.5 !border-none !bg-transparent;
}
.button :global(.selected-flag) {
@apply !bg-transparent;
}
.dropdown {
@apply !z-10 font-sans;
:global(.dark) & {
@apply !bg-black !text-white;
}
}
.dropdown :global(li) {
:global(.dark) & {
@apply hover:!text-black;
}
}
.dropdown :global(li.highlight) {
:global(.dark) & {
@apply !text-black;
}
}
.search {
@apply !bg-white !px-2;
:global(.dark) & {
@apply !bg-black;
}
}
.search :global(span) {
@apply !hidden;
}
.search :global(input) {
@apply !w-full !ml-0;
:global(.dark) & {
@apply !text-white hover:!text-white focus:!text-white;
}
}
.dropdown :global(li.no-entries-message) {
:global(.dark) & {
@apply hover:!text-white !text-white;
}
}
import type { Meta, StoryObj } from '@storybook/react';
import SelectComponent, { SelectItem } from './';
const meta: Meta<typeof SelectComponent> = {
title: 'Base/Select',
component: SelectComponent,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
const items = [
{
label: 'Option 1',
value: 'option1'
},
{
label: 'Option 2',
value: 'option2'
}
];
export const Select: Story = {
render: () => (
<div>
<SelectComponent items={items} label="Select">
{items.map((item) => (
<SelectItem key={item.value} textValue={item.value}>
{item.label}
</SelectItem>
))}
</SelectComponent>
<SelectComponent items={items} label="Select with error" isInvalid>
{items.map((item) => (
<SelectItem key={item.value} textValue={item.value}>
{item.label}
</SelectItem>
))}
</SelectComponent>
</div>
)
};
import {
extendVariants,
Select as NextUiSelect,
SelectProps
} from '@heroui/react';
interface ISelectProps extends SelectProps {}
const NextSelect = extendVariants(NextUiSelect, {
defaultVariants: {
variant: 'underlined'
}
});
const Select: React.FC<ISelectProps> = ({ children, ...rest }) => {
return (
<NextSelect
{...rest}
ref={(rest.ref as any) || null}
classNames={{
...rest.classNames,
trigger: [
'border-b-1 border-primary-200 hover:border-primary-800',
'dark:border-white dark:hover:border-white',
'after:bottom-0 after:h-[1px] after:bg-primary-800 dark:after:bg-white',
rest.isInvalid
? 'after:!bg-danger !border-b-danger hover:!border-danger'
: '',
rest.classNames?.trigger
].join(' '),
label: [
'text-lg text-primary-500 dark:text-white opacity-60 mt-2',
'line-clamp-1 pr-6 text-left',
rest.classNames?.label
].join(' '),
selectorIcon: [
'-mr-4',
'stoke-primary-100 storke-white',
'size-8 mt-3',
'stroke-1',
rest.isInvalid ? 'text-danger' : ' text-primary-300 dark:text-white',
rest.classNames?.selectorIcon
].join(' '),
value: ['text-medium', rest.classNames?.value].join(' '),
listbox: ['p-0', rest.classNames?.listbox].join(' '),
popoverContent: [
'p-0 rounded-none',
rest.classNames?.popoverContent
].join(' ')
}}>
{children}
</NextSelect>
);
};
export default Select;
export { default } from './Select';
export * from '@heroui/select';
export * from './Select';
import type { Meta, StoryObj } from '@storybook/react';
import TextFieldComponent from './TextField';
const meta: Meta<typeof TextFieldComponent> = {
title: 'Base/TextField',
component: TextFieldComponent,
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
export const TextField: Story = {
render: () => (
<div>
<TextFieldComponent label="Email" type="email" />
<TextFieldComponent label="Email with error" type="email" isInvalid />
</div>
)
};
import { extendVariants, Input, InputProps } from '@heroui/react';
interface ITextFieldsProps extends InputProps {}
const NextInput = extendVariants(Input, {
defaultVariants: {
variant: 'underlined'
}
});
const TextField: React.FC<ITextFieldsProps> = ({ ...rest }) => {
return (
<NextInput
{...rest}
ref={(rest.ref as any) || null}
classNames={{
...rest.classNames,
inputWrapper: `
border-b-1 border-primary-200 hover:border-primary-800
dark:border-white dark:hover:border-white
after:bottom-0 after:h-[1px] after:bg-primary-800 dark:after:bg-white
${rest.isInvalid ? 'after:!bg-danger !border-b-danger hover:!border-danger' : ''}
${rest.classNames?.helperWrapper}
`,
label: `
text-lg text-primary-500 opacity-60 dark:text-white
${rest.classNames?.label}
`,
errorMessage: 'text-danger',
input: `
text-medium ${rest.classNames?.input}
`
}}
/>
);
};
export default TextField;
export * from './TextField';
export { default } from './TextField';
import ContactForm from '.';
import submitForm from '@/api/submitForm';
const AsyncContactForm = async (props: IContactForm) => {
return <ContactForm {...props} onSubmit={submitForm} />;
};
export default AsyncContactForm;
import type { Meta, StoryObj } from '@storybook/react';
import ContactFormComponent from './ContactForm';
import labels from '@/mocks/labels';
const meta: Meta<typeof ContactFormComponent> = {
title: 'Form/ContactForm',
component: ContactFormComponent,
parameters: {
layout: 'fullscreen'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
const titleOptions = [
{ label: 'Mr.', value: 'Mr' },
{ label: 'Mrs.', value: 'Mrs' },
{ label: 'Ms.', value: 'Ms' }
];
const budgetOptions = [
{ label: 'From 15-20M', value: 'From 15-20M' },
{ label: 'From 20.1M to 30M', value: 'From 20.1M to 30M' },
{ label: 'From 30.1M to 50M', value: 'From 30.1M to 50M' },
{ label: '50M and above', value: '50M and above' }
];
const unitTypeOptions = [
{ label: 'Office', value: 'Office' },
{ label: 'Retail', value: 'Retail' },
{ label: 'F&B', value: 'F&B' }
];
const unitSizeOptions = [
{ label: 'Less than 100M2', value: 'Less than 100M2' },
{ label: '100M2 - 200M2', value: '100M2 - 200M2' },
{ label: '200M2 - 300M2', value: '200M2 - 300M2' },
{ label: '300M2 and above', value: '300M2 and above' }
];
const purposeOptions = [
{ label: 'Investment', value: 'Investment' },
{ label: 'Personal', value: 'Personal' }
];
export const ContactForm: Story = {
args: {
title: 'Register your Interest',
footerText:
'Fields that contain * are mandatory fields and must be filled before submitting the form.',
unitTypeOptions,
unitSizeOptions,
purposeOptions,
titleOptions,
budgetOptions,
labels: labels.form
}
};
'use client';
import React, { useRef, useState } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { SelectItem, useDisclosure } from '@heroui/react';
import ReCaptcha from 'react-google-recaptcha';
import Select from '@/components/base/Select';
import TextField from '@/components/base/TextField';
import Button from '@/components/base/Button';
import CheckBox from '@/components/base/CheckBox';
import PhoneInput from '@/components/base/PhoneInput';
import Container from '@/components/layout/Container';
export interface IContactFormValues {
title: string;
firstName: string;
lastName: string;
email: string;
mobile: string;
mobileNumber: string;
dialCode: string;
residence?: string;
unitType: string;
unitSize?: string;
budget?: string;
terms: boolean;
purpose: string;
recaptchaToken: string;
}
// export interface IContactForm {
// title?: string;
// footerText?: string;
// titleOptions: ISelectOption[];
// budgetOptions: ISelectOption[];
// purposeOptions: ISelectOption[];
// unitSizeOptions: ISelectOption[];
// unitTypeOptions: ISelectOption[];
// labels: IFormLabels;
// onSubmit: (values: IContactFormValues) => Promise<IResponse>;
// }
const defaultValues = {
title: '',
firstName: '',
lastName: '',
email: '',
mobile: '+20',
mobileNumber: '',
dialCode: '',
//optional
residence: '',
unitType: '',
//optional
unitSize: '',
//optional
budget: '',
purpose: '',
terms: false
};
const ContactForm: React.FC<IContactForm> = ({
title,
footerText,
titleOptions,
budgetOptions,
purposeOptions,
unitSizeOptions,
unitTypeOptions,
labels,
onSubmit
}) => {
const {
control,
handleSubmit,
setValue,
reset,
getValues,
formState: { errors }
} = useForm<IContactFormValues>({
defaultValues
});
const recaptchaRef = useRef<ReCaptcha>(null);
const [recaptchaError, setRecaptchaError] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [formStatus, setFormStatus] = useState<'success' | 'error' | null>(
null
);
const handleRecaptchaChange = (value: string | null) => {
if (value) {
// Clear any previous error
setRecaptchaError('');
}
};
const submit = async (values: IContactFormValues) => {
setFormStatus(null);
const recaptchaValue = recaptchaRef?.current?.getValue();
console.log('recaptchaValue', recaptchaValue);
if (!recaptchaValue) {
setRecaptchaError(labels.errorRecaptchaRequired);
return;
}
setIsSubmitting(true);
const response = await onSubmit({
...values,
recaptchaToken: recaptchaValue
});
console.log('response', response);
recaptchaRef?.current?.reset();
if (response.success) {
reset();
setFormStatus('success');
onOpenChange();
} else {
console.error(response.code);
setFormStatus('error');
}
setIsSubmitting(false);
};
const resetRecaptcha = () => {
recaptchaRef?.current?.reset();
setRecaptchaError('');
};
const handleReset = () => {
reset();
resetRecaptcha();
setFormStatus(null);
};
const { isOpen, onClose, onOpenChange } = useDisclosure();
return (
<section className="dark bg-default-100 text-foreground mb-6 py-12">
{/* <FormSuccessModal
isOpen={isOpen}
onClose={onClose}
onOpenChange={onOpenChange}
title="Thank you for your enquiry"
description="We'll be in touch with you in the next 24 business hours."
button={{
label: 'Home',
url: '/'
}}
/> */}
<Container className="overflow-hidden lg:px-40">
{title && (
<h1 className="text-center text-4xl mb-10 font-serif md:text-5xl">
{title}
</h1>
)}
<form onSubmit={handleSubmit(submit)}>
{/* ✅ Controlled Select for Title */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-x-10 gap-y-4 items-start">
<Controller
name="title"
control={control}
rules={{ required: labels?.errorTitleRequired || '' }}
render={({ field }) => (
<Select
{...field}
label={labels?.title}
isInvalid={!!errors?.title}
errorMessage={errors?.title?.message}
selectedKeys={field.value ? [field.value] : []} // Ensure value resets
onSelectionChange={(keys: any) =>
field.onChange([...keys][0])
}>
{(titleOptions || []).map((data) => (
<SelectItem
key={data.value}
classNames={{ base: 'rounded-none' }}>
{data.label}
</SelectItem>
))}
</Select>
)}
/>
{/* ✅ First Name */}
<Controller
name="firstName"
control={control}
rules={{
required: labels.errorFirstNameRequired || '',
pattern: {
value: /^[A-Za-z]+$/,
message: labels.errorFirstNameInvalid || ''
}
}}
render={({ field }) => (
<TextField
{...field}
variant="underlined"
isInvalid={!!errors?.firstName}
errorMessage={errors?.firstName?.message || ''}
label={labels?.firstName}
/>
)}
/>
{/* */}
{/* ✅ Last Name with Controller */}
<Controller
name="lastName"
control={control}
rules={{
required: labels.errorLastNameRequired || '',
pattern: {
value: /^[A-Za-z]+$/,
message: labels.errorLastNameInvalid || ''
}
}}
render={({ field }) => (
<TextField
{...field}
variant="underlined"
isInvalid={!!errors?.lastName}
errorMessage={errors?.lastName?.message || ''}
label={labels?.lastName}
/>
)}
/>
{/* ✅ Email */}
<Controller
name="email"
control={control}
rules={{
required: labels.errorEmailRequired || '',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: labels.errorEmailInvalid || ''
}
}}
render={({ field }) => (
<TextField
{...field}
label={labels?.email}
isInvalid={!!errors?.email}
errorMessage={errors?.email?.message}
/>
)}
/>
{/* ✅ Mobile */}
<div className="relative z-20 isolate mt-4 sm:mt-0">
<Controller
name="mobile"
control={control}
defaultValue=""
rules={{
required: errors.mobile?.message,
validate: (value) => {
if (!/^\d{6,15}$/.test(value)) {
return labels.errorMobileInvalid;
}
return true;
}
}}
render={({ field }) => (
<PhoneInput
{...field}
label={labels.mobile}
enableSearch
name={field.name}
isInValid={!!errors.mobile}
onBlur={field.onBlur}
onChange={(value, parts) => {
if ('dialCode' in parts) {
const mobileNumber = value.replace(parts.dialCode, '');
setValue('dialCode', parts.dialCode);
setValue('mobileNumber', mobileNumber);
field.onChange(value);
}
}}
/>
)}
/>
{!!errors.mobile && (
<p className="text-danger text-[12px]">
{errors.mobile?.message}
</p>
)}
</div>
{/* ✅ Country of Residence */}
<Controller
name="residence"
control={control}
render={({ field }) => (
<TextField
{...field}
className="sm:mt-[0.85rem]"
label={labels?.residence}
isInvalid={!!errors?.residence}
errorMessage={errors?.residence?.message}
/>
)}
/>
{/* ✅ Unit Type */}
<Controller
name="unitType"
control={control}
rules={{ required: labels?.errorUnitTypeRequired || '' }}
render={({ field }) => (
<Select
{...field}
label={labels?.unitType}
isInvalid={!!errors?.unitType}
errorMessage={errors?.unitType?.message}
selectedKeys={field.value ? [field.value] : []} // Ensure value resets
onSelectionChange={(keys: any) =>
field.onChange([...keys][0])
}>
{(unitTypeOptions || []).map((data) => (
<SelectItem
key={data.value}
classNames={{ base: 'rounded-none' }}>
{data.label}
</SelectItem>
))}
</Select>
)}
/>
{/* unit size */}
<Controller
name="unitSize"
control={control}
render={({ field }) => (
<Select
{...field}
label={labels?.unitSize}
isInvalid={!!errors?.unitSize}
errorMessage={errors?.unitSize?.message}
selectedKeys={field.value ? [field.value] : []} // Ensure value resets
onSelectionChange={(keys: any) =>
field.onChange([...keys][0])
}>
{(unitSizeOptions || []).map((data) => (
<SelectItem
key={data.value}
classNames={{ base: 'rounded-none' }}>
{data.label}
</SelectItem>
))}
</Select>
)}
/>
<Controller
name="budget"
control={control}
render={({ field }) => (
<Select
{...field}
label={labels?.budget}
isInvalid={!!errors?.budget}
errorMessage={errors?.budget?.message}
selectedKeys={field.value ? [field.value] : []} // Ensure value resets
onSelectionChange={(keys: any) =>
field.onChange([...keys][0])
}>
{(budgetOptions || []).map((data) => (
<SelectItem
key={data.value}
classNames={{ base: 'rounded-none' }}>
{data.label}
</SelectItem>
))}
</Select>
)}
/>
<Controller
name="purpose"
control={control}
rules={{
required: labels?.errorPurposeRequired || ''
}}
render={({ field }) => (
<Select
{...field}
label={labels?.purpose}
isInvalid={!!errors?.purpose}
errorMessage={errors?.purpose?.message}
selectedKeys={field.value ? [field.value] : []} // Ensure value resets
onSelectionChange={(keys: any) =>
field.onChange([...keys][0])
}>
{(purposeOptions || []).map((data) => (
<SelectItem
key={data.value}
classNames={{ base: 'rounded-none' }}>
{data.label}
</SelectItem>
))}
</Select>
)}
/>
<div className="flex items-center flex-col gap-5 mt-6 sm:col-span-2">
<Controller
name="terms"
control={control}
rules={{
required: labels.errorTermsRequired
}}
render={({ field }) => (
<div className="my-2 relative z-0">
<div className="flex items-center">
<CheckBox
isSelected={field.value || false}
onValueChange={field.onChange}
isInvalid={!!errors?.terms}>
<label
className="text-sm font-inter [&_a]:underline [&_a]:isolate [&_a]:relative [&_a]:z-20"
dangerouslySetInnerHTML={{
__html: labels.terms
}}
/>
</CheckBox>
</div>
{errors?.terms?.message && (
<p className="text-tiny text-danger ms-8">
{errors?.terms?.message}
</p>
)}
</div>
)}
/>
<ReCaptcha
ref={recaptchaRef}
size="normal"
sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY as string}
onChange={handleRecaptchaChange}
onExpired={resetRecaptcha}
/>
{recaptchaError && (
<div className="text-danger text-small">{recaptchaError}</div>
)}
{/* {formStatus === 'success' && (
<div className="text-success text-small">
{labels.formSuccessText}
</div>
)} */}
{formStatus === 'error' && (
<div className="text-danger text-small">
{labels.formErrorText}
</div>
)}
</div>
{/* ✅ Submit Button */}
<div className="w-full flex gap-6 sm:gap-10 sm:justify-center mt-6 *:!basis-full flex-wrap sm:col-span-2 ">
<Button
className="grow sm:max-w-60"
type="submit"
color="primary"
isLoading={isSubmitting}>
{labels.submitButtonLabel}
</Button>
<Button
className="grow sm:max-w-60 dark:bg-black dark:text-white"
type="button"
color="primary"
variant="ghost"
onPress={handleReset}
isDisabled={isSubmitting}>
{labels.clearButtonLabel}
</Button>
</div>
{footerText && (
<p className="mt-5 text-medium opacity-50 text-center sm:col-span-2">
{footerText}
</p>
)}
</div>
</form>
</Container>
</section>
);
};
export default ContactForm;
export { default } from './ContactForm';
export { default as AsyncContactForm } from './AsyncContactForm';
export * from './ContactForm';
import cn from '@/lib/merge-clsx';
interface IContainer extends React.HTMLAttributes<HTMLElement> {
as?: React.ElementType;
className?: string;
}
const Container: React.FC<IContainer> = (props) => {
const { as, className, ...rest } = props;
const Component = as || 'div';
return (
<Component
{...rest}
className={cn('mx-auto max-w-screen-2xl px-4 sm:px-8', className)}
/>
);
};
export default Container;
export { default } from './Container';
import type { Meta, StoryObj } from '@storybook/react';
import FooterComponent from '.';
const meta: Meta<typeof FooterComponent> = {
title: 'Layout/Footer',
component: FooterComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Footer: Story = {
args: {
socialPlatforms: [
{ url: '/', label: 'instagram', icon: 'instagram' },
{ url: '/', label: 'facebook', icon: 'facebook' }
],
policyLinks: [
{ url: '/', label: 'Privacy Center' },
{ url: '/', label: 'Anti-Fraud Disclaimer' },
{ url: '/', label: 'Responsible Disclosure Policy' },
{ url: '/', label: 'Terms and Conditions' },
{ url: '/', label: 'Cookie Settings' }
],
linkGroups: [
{
title: 'Neighbour hoods',
links: [
{ url: '/', label: 'Lacina' },
{ url: '/', label: 'Serra' },
{ url: '/', label: 'Cilia' },
{ url: '/', label: 'Capria' }
]
},
{
title: 'Discover Junction',
links: [
{ url: '/', label: 'Download Brochure' },
{ url: '/', label: 'Register Your Interest' }
]
},
{
title: 'Majid Al-Futtaim Communities',
links: [
{ url: '/', label: 'Tilal Al Ghaf' },
{ url: '/', label: 'Al Zahia' },
{ url: '/', label: 'Al Mouj' },
{ url: '/', label: 'Water Front City' }
]
}
],
labels: {
copyrightText: '© 2025 MAF Egypt Business Park. All Rights Reserved.',
poweredByText: 'Launching Soon',
socialLinkText: 'Stay in touch with us',
topText: 'TOP'
}
}
};
import Image from 'next/image';
import Container from '@/components/layout/Container';
import SocialLinks from '@/components/shared/SocialLinks';
import mafLogo from '@/assets/img/footer-logo.png';
import logo from '@/assets/img/logo.png';
import React from 'react';
export interface IFooter {
socialPlatforms?: ISocialLink[];
policyLinks?: ILink[];
linkGroups?: {
title?: string;
links: ILink[];
}[];
labels: {
copyrightText: string;
socialLinkText: string;
poweredByText: string;
topText: string;
};
}
const Footer: React.FC<IFooter> = ({
socialPlatforms,
policyLinks,
linkGroups,
labels
}) => {
return (
<footer className="bg-default-900 font-light text-content1">
<Container className="grid grid-cols-1 md:grid-cols-12 text-content1 py-8">
<div className="md:col-span-4">
<Image src={logo} alt="MAF Junction" className="w-28 mb-6" />
{socialPlatforms && (
<div className="mb-6 w-56">
<h3 className="mb-4 font-light text-4xl text-white">
{labels.socialLinkText}
</h3>
<SocialLinks
socialPlatforms={socialPlatforms}
className="md:flex-nowrap"
/>
</div>
)}
</div>
<div className="grid grid-cols-1 md:gap-4 md:col-span-8 md:grid-cols-3 md:px-8">
{linkGroups?.map((group) => (
<div key={group.title} className="mt-4 md:mt-0">
<h3 className="mb-2 md:mb-4 font-serif font-light text-white">
{group.title?.toUpperCase()}
</h3>
{group?.links.map((link: ILink, i) => (
<React.Fragment key={i}>
<div className="mt-2">
<a href={link.url}>{link.label}</a>
</div>
</React.Fragment>
))}
</div>
))}
</div>
<div className="flex flex-wrap md:col-span-4 text-sm">
{policyLinks?.map((link, i) => (
<a
key={link.label}
href={link.url}
className="text-[#AEAEAE] text-[1.05em] px-1 my-1 border-s-1 first:border-s-0 first:ps-0 leading-3">
{link.label}
</a>
))}
</div>
</Container>
<div className="py-6 px-4 md:px-0 bg-default-800">
<Container>
<div className="flex items-center justify-between flex-wrap sm:flex-nowrap gap-8">
<div className="grow">
<div className="font-sans text-xs mb-2">
{labels.poweredByText}
</div>
<Image
src={mafLogo}
alt="Majid Al Futtaim"
className="w-[12.5rem]"
/>
</div>
<div className="text-sm text-right">{labels.copyrightText}</div>
</div>
</Container>
</div>
</footer>
);
};
export default Footer;
export { default } from './Footer';
export * from './Footer';
import getHeader from '@/api/getHeader';
import Header from './Header';
const AsyncHeader = async () => {
const header = await getHeader();
console.log('header', header);
return <Header {...header} />;
};
export default AsyncHeader;
import type { Meta, StoryObj } from '@storybook/react';
import HeaderComponent from './Header';
import Image from 'next/image';
const meta: Meta<typeof HeaderComponent> = {
title: 'Layout/Header',
component: HeaderComponent,
parameters: {
layout: 'fullscreen'
},
tags: ['autodocs'],
decorators: [
(Story: React.ComponentType) => (
<div>
<Story />
<Image
src="https://picsum.photos/1920/1920"
alt="background"
className="w-full"
/>
</div>
)
]
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Header: Story = {
args: {
button: {
label: 'Register your Interest',
url: '/'
},
menuItems: [
{
label: 'Launch Event',
url: '#'
},
{
label: 'Brokers Briefing',
url: '#'
}
]
}
};
'use client';
import React from 'react';
import Button from '@/components/base/Button';
import Image from 'next/image';
import Link from 'next/link';
import {
Navbar,
NavbarMenuToggle,
NavbarMenu,
NavbarMenuItem,
NavbarContent,
NavbarItem,
NavbarBrand
} from '@heroui/navbar';
import logo from '@/assets/img/logo.png';
const Header: React.FC<IHeader> = ({ button, menuItems }) => {
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
console.log('button', button);
const handleMenuClose = () => {
setIsMenuOpen(false);
};
const renderMenuItems = () =>
menuItems?.map(({ label, url }) => (
<NavbarMenuItem key={label} className="text-sm text-background">
<Link href={url} onClick={handleMenuClose}>
{label}
</Link>
<div className="sm:hidden w-full border-b-[0.1px] border-default-500 pt-5" />
</NavbarMenuItem>
));
const renderButton = () =>
button && (
<NavbarMenuItem>
<Button
as={Link}
size="md"
className="text-sm md:px-10"
color="default"
href={button.url}
onPress={handleMenuClose}>
{button.label}
</Button>
</NavbarMenuItem>
);
return (
<React.Fragment>
<div className="h-[4.5rem] bg-default-900" />
<header className="fixed top-0 w-full bg-default-900 bg-opacity-80 backdrop-blur-md z-50">
<Navbar
isBlurred={false}
maxWidth="2xl"
className="border-b-1 border-b-default-700"
classNames={{
base: 'bg-transparent py-1',
wrapper: 'px-2',
menuItem: 'pt-5 sm:pt-0',
menu: 'bg-default-900'
}}
isMenuOpen={isMenuOpen}
onMenuOpenChange={setIsMenuOpen}>
<NavbarBrand>
<Link href="/">
<Image priority src={logo} alt="Maf Junction" className="w-32" />
</Link>
</NavbarBrand>
{/* Mobile */}
<NavbarContent justify="end" className="sm:hidden">
<NavbarItem>
<NavbarMenu>
{renderMenuItems()} {renderButton()}
</NavbarMenu>
</NavbarItem>
</NavbarContent>
<NavbarMenuToggle className="sm:hidden text-background" />
{/* Desktop */}
<NavbarContent
className="hidden sm:flex gap-4 text-background"
justify="center">
{renderMenuItems()} {renderButton()}
</NavbarContent>
</Navbar>
</header>
</React.Fragment>
);
};
export default Header;
export { default } from './Header';
export * from './Header';
import type { Meta, StoryObj } from '@storybook/react';
import PageNotFoundComponent from './PageNotFound';
const meta: Meta<typeof PageNotFoundComponent> = {
title: 'Layout/Page Not Found',
component: PageNotFoundComponent,
parameters: {
layout: 'centered'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const PageNotFound: Story = {};
import Image from 'next/image';
import { Button } from "@heroui/button";
import FourOhFour from './img/404.png';
export default function PageNotFound() {
return (
<div className="flex flex-col justify-center items-center">
<Image src={FourOhFour} alt="404, Page Not Found!" />
<Button href="/" color="primary" size="md">
Back to Home
</Button>
</div>
);
}
export { default } from './PageNotFound';
@use '@styles/vars.scss';
.notFound {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10vh 1em;
box-sizing: border-box;
h2 {
font-size: 10em;
font-weight: 100;
line-height: 0.8;
margin: 0;
color: #1ea7fd;
}
a {
margin-top: 2em;
}
}
@include vars.mQuery(xl) {
.notFound {
font-size: 0.9em;
}
}
import MasterPlan from '@/components/top-level/MasterPlan';
import VideoContent from '@/components/top-level/VideoContent';
import Banner from '@/components/top-level/Banner';
import AddressMap from '@/components/top-level/AddressMap';
import AmenitiesCarousel from '@/components/top-level/AmenitiesCarousel';
import Gallery from '@/components/top-level/Gallery';
import ImageCarousel from '@/components/top-level/ImageCarousel';
import { AsyncContactForm } from '@/components/form/ContactForm';
const PageRenderer = ({ components, prefix }: IPageRenderer) => {
return components.map(({ component, ...props }, index) => {
const key = `${prefix}-${index}`;
switch (component) {
case 'master-plan':
return <MasterPlan key={key} {...(props as IMasterPlan)} />;
case 'video-content':
return <VideoContent key={key} {...(props as IVideoContent)} />;
case 'banner':
return <Banner key={key} {...(props as IBanner)} />;
case 'address-map':
return <AddressMap key={key} {...(props as IAddressMap)} />;
case 'contact':
return <AsyncContactForm key={key} {...(props as IContactForm)} />;
case 'amenities-carousel':
return (
<AmenitiesCarousel key={key} {...(props as IAmenitiesCarousel)} />
);
case 'gallery':
return <Gallery key={key} {...(props as IGallery)} />;
case 'image-carousel':
return <ImageCarousel key={key} {...(props as IImageCarousel)} />;
default:
return null;
}
});
};
export default PageRenderer;
export { default } from './PageRenderer';
export * from './PageRenderer';
'use client';
import { useRouter } from 'next/navigation';
import { HeroUIProvider } from '@heroui/react';
import { ParallaxProvider } from 'react-scroll-parallax';
type ProvidersProps = {
children: React.ReactNode;
};
const Providers: React.FC<ProvidersProps> = ({ children }) => {
const router = useRouter();
return (
<HeroUIProvider navigate={router.push}>
<ParallaxProvider>{children}</ParallaxProvider>
</HeroUIProvider>
);
};
export default Providers;
export { default } from './Providers';
'use client';
import { ReactNode, useEffect, useRef } from 'react';
import { ReactLenis } from 'lenis/react';
interface ISmoothScroll {
children: ReactNode;
}
export default function SmoothScroll({ children }: ISmoothScroll) {
return (
<ReactLenis
root
options={{
duration: 1.2,
easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
wheelMultiplier: 0.8,
touchMultiplier: 0.8,
infinite: false
}}>
{children}
</ReactLenis>
);
}
export { default } from './SmoothScroll';
import ReactMarkdown, { Options } from 'react-markdown';
import rehypeRaw from 'rehype-raw';
interface RenderMarkdownProps extends React.HTMLAttributes<HTMLDivElement> {
children: string;
}
/** component that render markdown & plain html */
const RenderMarkdown: React.FC<RenderMarkdownProps & Options> = (props) => {
return <ReactMarkdown {...props} rehypePlugins={[rehypeRaw]} />;
};
export default RenderMarkdown;
export { default } from './RenderMarkdown';
import ResponsiveImage from './ResponsiveImage';
import type { ResponsiveImageProps } from './ResponsiveImage';
export default {
title: 'Shared/ResponsiveImage',
component: ResponsiveImage,
parameters: {
layout: 'fullscreen'
},
tags: ['autodocs']
};
export const Image = {
args: {
src: 'https://picsum.photos/1920/570?jpg',
width: 1920,
height: 570,
sizes: '100vw'
}
};
export const ArtDirection = {
args: {
src: 'https://picsum.photos/576/570?jpg',
width: 576,
height: 540,
sizes: '100vw'
},
render: (args: ResponsiveImageProps) => (
<ResponsiveImage {...args}>
<ResponsiveImage.Source
media="xxl"
src="https://picsum.photos/1920/540?jpg"
width={1920}
height={540}
sizes="100vw"
/>
<ResponsiveImage.Source
media="xl"
src="https://picsum.photos/1536/540?jpg"
width={1536}
height={540}
sizes="100vw"
/>
<ResponsiveImage.Source
media="lg"
src="https://picsum.photos/1280/540?jpg"
width={1280}
height={540}
sizes="100vw"
/>
<ResponsiveImage.Source
media="md"
src="https://picsum.photos/1024/540?jpg"
width={1024}
height={540}
sizes="100vw"
/>
<ResponsiveImage.Source
media="sm"
src="https://picsum.photos/768/540?jpg"
width={768}
height={540}
sizes="100vw"
/>
<ResponsiveImage.Source
media="(min-width: 576px)"
src="https://picsum.photos/640/540?jpg"
width={640}
height={540}
sizes="100vw"
/>
</ResponsiveImage>
)
};
import { memo } from 'react';
import React from 'react';
import { getImageProps } from 'next/image';
import breakpoints from './breakpoints';
export type Image = {
url: string;
width: number;
height: number;
alternativeText?: string;
};
export interface ResponsiveImageProps
extends React.HTMLAttributes<HTMLImageElement> {
src: string;
width: number;
height: number;
sizes: string;
alt?: string;
priority?: boolean;
quality?: number;
children?: React.ReactNode;
}
export interface SourceProps extends React.HTMLAttributes<HTMLSourceElement> {
src: string;
width: number;
height: number;
media: string;
sizes: string;
quality?: number;
}
const ResponsiveImage: React.FC<ResponsiveImageProps> & {
Source: React.FC<SourceProps>;
} = ({
src,
width,
height,
alt,
sizes,
quality,
priority,
children,
...rest
}) => {
if (src) {
const { props } = getImageProps({
src,
width,
height,
sizes,
quality,
priority,
alt: alt || ''
});
return (
<picture>
{children}
<img {...props} {...rest} alt={alt || ''} />
</picture>
);
}
};
ResponsiveImage.Source = memo(
({ src, width, height, sizes, media, quality, ...rest }: SourceProps) => {
if (src) {
const query = breakpoints[media] || media;
const { props } = getImageProps({
width,
height,
src,
sizes,
quality,
alt: ''
});
return (
<source
media={query}
src={props.src}
srcSet={props.srcSet}
width={props.width}
height={props.height}
sizes={props.sizes}
{...rest}
/>
);
}
}
);
ResponsiveImage.displayName = 'ResponsiveImage';
ResponsiveImage.Source.displayName = 'ResponsiveImageSource';
export default ResponsiveImage;
type Breakpoints = {
[key: string]: string;
};
const breakpoints: Breakpoints = {
sm: '(min-width: 640px)',
md: '(min-width: 768px)',
lg: '(min-width: 1024px)',
xl: '(min-width: 1280px)',
xxl: '(min-width: 1536px)'
};
export default breakpoints;
export * from './ResponsiveImage';
export { default } from './ResponsiveImage';
import type { Meta, StoryObj } from '@storybook/react';
import ResponsiveVideoComponent from './ResponsiveVideo';
const meta: Meta<typeof ResponsiveVideoComponent> = {
title: 'Shared/ResponsiveVideo',
component: ResponsiveVideoComponent,
parameters: {
layout: 'centered'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof meta>;
const autoPlayFallback = (
<h3 className="font-bold text-lg text-light bg-primary px-4 py-2">
Auto play failed. I am a fallback element
</h3>
);
export const ResponsiveVideo: Story = {
args: {
src: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4',
srcSet: [
{
src: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4',
media: '(min-width: 640px)'
}
],
autoPlayFallback,
autoPlay: true,
controls: true,
muted: true
}
};
export const AutoPlayFailed: Story = {
args: {
src: 'broken.mp4',
autoPlay: true,
autoPlayFallback
}
};
'use client';
import React, { useState, useEffect, useRef } from 'react';
import breakpoints from './breakpoints';
export interface ResponsiveVideoProps
extends React.VideoHTMLAttributes<HTMLVideoElement> {
src: string;
/** first match in the array will be selected
* media should be a valid media query or
* a key from breakpoints object
*/
srcSet?: {
src: string;
media: string;
}[];
/** auto plays video source */
autoPlay?: boolean;
/** If autoplay fails and if there is a fallback,
* display this fallback element */
autoPlayFallback?: React.ReactNode;
}
export const ResponsiveVideo = ({
src,
srcSet,
autoPlay,
autoPlayFallback,
...rest
}: ResponsiveVideoProps) => {
const [isAutoPlayFailed, setIsAutoPlayFailed] = useState(false);
const [currentSrc, setCurrentSrc] = useState(src);
const videoRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const handleResize = () => {
/** find the set that matches current media query */
const matchedSet = srcSet?.find(
({ media }) => window.matchMedia(breakpoints[media] || media).matches
);
/* set the current src to the matched set or the default src */
setCurrentSrc(matchedSet?.src || src);
};
/* call handleResize on mount */
handleResize();
/* add resize event listener to window */
window.addEventListener('resize', handleResize);
/* remove event listener on unmount */
return () => window.removeEventListener('resize', handleResize);
}, [src, srcSet]);
useEffect(() => {
async function play() {
try {
/** If user prefers reduced motion,
* throw an error and stop autoplay
*/
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
);
if (prefersReducedMotion.matches) {
throw new Error('User prefers reduced motion');
} else {
/* if autoplay is true, play the video */
autoPlay && (await videoRef?.current?.play());
}
} catch (error: any) {
/* AbortError happens when source is changed in runtime,
if error is not AbortError, mark autoPlay as failed
*/
if (error.name !== 'AbortError') {
console.error(error);
/* if play failed, report that autoplay has failed */
setIsAutoPlayFailed(true);
}
}
}
play();
}, [autoPlay, currentSrc]);
return isAutoPlayFailed && autoPlayFallback ? (
autoPlayFallback
) : (
<video ref={videoRef} src={currentSrc} {...rest} />
);
};
export default ResponsiveVideo;
type Breakpoints = {
[key: string]: string;
};
const breakpoints: Breakpoints = {
sm: '(min-width: 640px)',
md: '(min-width: 768px)',
lg: '(min-width: 1024px)',
xl: '(min-width: 1280px)',
xxl: '(min-width: 1536px)'
};
export default breakpoints;
import type { Meta, StoryObj } from '@storybook/react';
import SocialLinksComponent, { type SocialLinksProps } from './SocialLinks';
const meta: Meta<typeof SocialLinksComponent> = {
title: 'Shared/SocialLinks',
component: SocialLinksComponent,
tags: ['autodocs'],
parameters: {
layout: 'centered'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const SocialLinks: Story = {
args: {
socialPlatforms: [
{
icon: 'instagram',
url: '#',
label: 'instagram'
},
{
icon: 'twitter',
url: '#',
label: 'twitter'
},
{
icon: 'linkedin',
url: '#',
label: 'linkedin'
},
{
icon: 'facebook',
url: '#',
label: 'facebook'
},
{
icon: 'tiktok',
url: '#',
label: 'tiktok'
}
]
},
render: (args: SocialLinksProps) => {
return (
<div>
<SocialLinksComponent
className="text-default-600 border-[1px] border-default-600"
{...args}
/>
</div>
);
}
};
import Icon from '@/components/base/Icon';
import { cn } from '@heroui/react';
import type { IconProps } from '@/components/base/Icon';
interface socialLink {
icon: string;
url: string;
label?: string;
}
export interface SocialLinksProps {
socialPlatforms?: socialLink[];
outline?: boolean;
className?: string;
}
const SocialLinks: React.FC<SocialLinksProps> = ({
socialPlatforms,
outline,
className,
...props
}) => {
const iconClasses = cn('text-xl mx-auto', className);
return (
<div {...props} className="flex gap-4 flex-wrap">
{socialPlatforms?.map(({ icon, url, label }) => (
<a
key={label}
href={url}
title={label}
target="_blank"
className={cn(
outline &&
' flex items-center justify-center border-1 border-white rounded-full w-10 h-10 flex-wrap'
)}>
<Icon
name={label?.toLocaleLowerCase() as IconProps['name']}
className={cn(iconClasses)}
/>
</a>
))}
</div>
);
};
export default SocialLinks;
export { default } from './SocialLinks';
export * from './SocialLinks';
import React, { useCallback, useEffect, useRef } from 'react';
import cn from '@/lib/merge-clsx';
import Icon from '@/components/base/Icon';
import { ScrollbarProps } from './SwiperElement';
import './styles.css';
const Scrollbar: React.FC<ScrollbarProps> = ({ swiperRef, isDragging }) => {
const thumbRef = useRef<HTMLDivElement>(null);
const scrollBarRef = useRef<HTMLDivElement>(null);
const handlePointerDown = () => {
isDragging.current = false;
};
const handlePointerUp = useCallback(() => {
if (!isDragging.current && swiperRef?.current?.swiper) {
const { swiper } = swiperRef.current;
const isLastSlide = swiper.slides.length - 1 === swiper.activeIndex;
isLastSlide ? swiper.slideTo(0) : swiper.slideNext();
}
isDragging.current = false;
}, [swiperRef, isDragging]);
// Prevent click event when dragging
useEffect(() => {
const thumbElement = thumbRef.current;
if (!thumbElement) return;
const handleClick = (e: MouseEvent) => {
if (isDragging.current) {
e.preventDefault();
e.stopPropagation();
}
};
thumbElement.addEventListener('click', handleClick);
return () => {
thumbElement.removeEventListener('click', handleClick);
};
}, [isDragging]);
const classNames = cn([
'border-1',
'relative',
'bg-origin-border',
'border-transparent',
'bg-[linear-gradient(90deg,#CC93D3_0%,#793BE0_100%)]',
'w-16 h-16',
'group',
'top-1/2',
'rounded-full',
'cursor-grab active:cursor-grabbing select-none',
'before:bg-content',
'before:absolute',
'before:inset-0',
'before:rounded-full',
'before:bg-black',
'before:-z-10',
'data-[hover=true]:!duration-[800ms] ease-in-out',
'flex items-center justify-center',
'z-10'
]);
return (
<div
ref={scrollBarRef}
className="swiper-scrollbar-drag !bg-transparent flex items-center justify-center">
<div className={classNames}>
<div className="circle-us" />
<div
ref={thumbRef}
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
className="text-xl text-white w-16 h-16 flex items-center justify-center rounded-full cursor-pointer isolate z-10 relative"
role="button"
aria-label="Adjust slider value">
<Icon name="forward-arrow" />
</div>
</div>
</div>
);
};
Scrollbar.displayName = 'Scrollbar';
export default Scrollbar;
import type { Meta, StoryObj } from '@storybook/react';
import SwiperElementComponent from './SwiperElement';
const meta: Meta<typeof SwiperElementComponent> = {
title: 'Shared/SwiperElement',
component: SwiperElementComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
},
argTypes: {
pagination: {
control: { type: 'boolean' }
},
'pagination.position': {
name: 'position',
options: ['bottom', 'overlap'],
control: { type: 'inline-radio' },
table: { category: 'Pagination' },
if: { arg: 'pagination' }
},
'pagination.variant': {
name: 'variant',
options: ['primary', 'secondary', 'light', 'dark'],
control: { type: 'inline-radio' },
table: { category: 'Pagination' },
if: { arg: 'pagination' }
},
'pagination.align': {
name: 'align',
options: ['start', 'center', 'end'],
control: { type: 'inline-radio' },
table: { category: 'Pagination' },
if: { arg: 'pagination' }
},
'pagination.type': {
name: 'type',
options: ['bullets', 'fraction'],
control: { type: 'inline-radio' },
table: { category: 'Pagination' },
if: { arg: 'pagination' }
},
'pagination.bullet': {
name: 'bullet',
options: ['small', 'large'],
control: { type: 'inline-radio' },
table: { category: 'Pagination' },
if: { arg: 'pagination' }
},
navigation: {
control: { type: 'boolean' }
},
'navigation.variant': {
name: 'variant',
options: ['primary', 'secondary', 'light', 'dark'],
control: { type: 'inline-radio' },
table: { category: 'Navigation' },
if: { arg: 'navigation' }
}
} as any
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Swiper: Story = {
args: {
dir: 'ltr',
pagination: true,
navigation: true,
'pagination.position': 'bottom',
'pagination.variant': 'primary',
'pagination.align': 'center',
'pagination.type': 'bullets',
'pagination.bullet': 'small',
'navigation.variant': 'primary'
} as any,
render: (args: any) => (
<SwiperElementComponent
key={args.pagination + args.navigation}
className="h-64"
{...args}
options={{
slidesPerView: 3,
spaceBetween: 10,
pagination: args.pagination && {
variant: args['pagination.variant'],
position: args['pagination.position'],
align: args['pagination.align'],
bullet: args['pagination.bullet'],
type: args['pagination.type']
},
navigation: args.navigation && {
variant: args['navigation.variant'],
icon: args['navigation.icon']
}
}}>
{['Slide 1', 'Slide 2', 'Slide 3', 'Slide 4', 'Slide 5'].map(
(slide, index) => (
<SwiperElementComponent.Slide
key={index}
className="bg-gray-400 text-black !flex justify-center items-center">
{slide}
</SwiperElementComponent.Slide>
)
)}
</SwiperElementComponent>
)
};
export const Scrollbar: Story = {
args: {
dir: 'ltr'
} as any,
render: (args: any) => (
<SwiperElementComponent
key={args.pagination + args.navigation}
className="h-64"
{...args}
options={{
slidesPerView: 3,
spaceBetween: 10,
scrollbar: {
el: '.swiper-scrollbar',
draggable: true,
hide: false
}
}}>
{['Slide 1', 'Slide 2', 'Slide 3', 'Slide 4', 'Slide 5'].map(
(slide, index) => (
<SwiperElementComponent.Slide
key={index}
className="bg-gray-400 text-black !flex justify-center items-center">
{slide}
</SwiperElementComponent.Slide>
)
)}
</SwiperElementComponent>
)
};
'use client';
import { useEffect, useRef } from 'react';
import Swiper from 'swiper';
import {
Pagination,
Navigation,
EffectCreative,
EffectCards,
Controller,
Keyboard,
Scrollbar as ScrollbarModule
} from 'swiper/modules';
import cn from '@/lib/merge-clsx';
import Icon from '@/components/base/Icon';
import Container from '@/components/layout/Container';
import Scrollbar from './Scrollbar';
import type { Swiper as SwiperType } from 'swiper';
import 'swiper/css';
import 'swiper/css/effect-creative';
import 'swiper/css/scrollbar';
import './styles.css';
import { ScrollbarOptions, SwiperOptions } from 'swiper/types';
import { IconProps } from '@/components/base/Icon';
export type SwiperElementProps = {
children: React.ReactNode;
dir?: 'rtl' | 'ltr';
className?: string;
isOverflowVisible?: boolean;
options?: Omit<SwiperOptions, 'pagination' | 'navigation'> & {
pagination?: {
variant: 'primary' | 'secondary' | 'light' | 'dark';
position?: 'bottom' | 'overlap';
align?: 'start' | 'center' | 'end';
bullet?: 'small' | 'large';
type?: 'bullets' | 'fraction';
className?: string;
};
navigation?: {
variant: 'primary' | 'secondary' | 'light' | 'dark';
nextClassName?: string;
prevClassName?: string;
};
};
};
export type SwiperElementPropsWithAs<
T extends React.ElementType = React.ElementType
> = SwiperElementProps &
React.ComponentPropsWithoutRef<T> & {
as?: T;
};
export type SwiperSlideProps = {
children: React.ReactNode;
className?: string;
};
type SwiperElementRef = {
swiper?: SwiperType;
} & HTMLDivElement;
export interface ScrollbarProps {
swiperRef: React.RefObject<SwiperElementRef>;
isDragging: React.RefObject<boolean>;
}
const SwiperElement: React.FC<SwiperElementPropsWithAs> & {
Slide: React.FC<SwiperSlideProps>;
} = ({
as: Component = 'div',
dir = 'ltr',
className,
options = {},
children,
...props
}) => {
const swiperRef = useRef<SwiperElementRef>(null);
const paginationRef = useRef<HTMLDivElement>(null);
const nextRef = useRef<HTMLDivElement>(null);
const prevRef = useRef<HTMLDivElement>(null);
const isDragging = useRef(false);
useEffect(() => {
if (swiperRef.current) {
const swiper = new Swiper(swiperRef.current, {
...options,
modules: [
Pagination,
Navigation,
EffectCreative,
EffectCards,
Controller,
Keyboard,
ScrollbarModule
],
keyboard: true,
pagination: options.pagination
? { el: paginationRef.current, clickable: true }
: false,
navigation: options.navigation
? { nextEl: nextRef.current, prevEl: prevRef.current }
: false
});
swiper.on('scrollbarDragMove', (swiper, event) => {
isDragging.current = true;
});
return () => {
swiper.destroy();
};
}
}, [dir, options]);
const paginationClasses = options.pagination
? cn('swiper-pagination flex p-6 gap-1', options.pagination.className, {
'swiper-pagination-primary':
options.pagination.variant === 'primary' &&
options.pagination.type !== 'fraction',
'swiper-pagination-secondary':
options.pagination.variant === 'secondary' &&
options.pagination.type !== 'fraction',
'swiper-pagination-fraction': options.pagination.type === 'fraction',
'swiper-pagination-light': options.pagination.variant === 'light',
'swiper-pagination-dark': options.pagination.variant === 'dark',
'justify-start': options.pagination.align === 'start',
'justify-end': options.pagination.align === 'end',
'justify-center': options.pagination.align === 'center',
'absolute inset-x-0 bottom-0 z-10':
options.pagination.position === 'overlap',
'swiper-pagination-large': options.pagination?.bullet === 'large'
})
: '';
const navigationClasses = cn(
'absolute z-10 top-1/2 -translate-y-1/2 cursor-pointer text-3xl',
{
'text-primary':
options.navigation?.variant === 'primary' ||
!options.navigation?.variant,
'text-secondary': options.navigation?.variant === 'secondary',
'text-background': options.navigation?.variant === 'light',
'text-foreground': options.navigation?.variant === 'dark'
}
);
const prevIcon = cn({
'left-arrow': dir === 'ltr',
'right-arrow': dir === 'rtl'
}) as IconProps['name'];
const nextIcon = cn({
'right-arrow': dir === 'ltr',
'left-arrow': dir === 'rtl'
}) as IconProps['name'];
return (
<div key={dir} dir={dir}>
<Component className={cn('relative', className)} {...props}>
<div
className={`swiper ${props?.isOverflowVisible ? '!overflow-visible' : ''}`}
dir={dir}
ref={swiperRef}>
<div className="swiper-wrapper">{children}</div>
</div>
{options.navigation && (
<div
ref={prevRef}
className={cn(
navigationClasses,
options.navigation.prevClassName || 'start-2'
)}>
<Icon name={prevIcon} className="!font-bold" />
</div>
)}
{options.navigation && (
<div
ref={nextRef}
className={cn(
navigationClasses,
options.navigation.nextClassName || 'end-2'
)}>
<Icon name={nextIcon} className="!font-bold" />
</div>
)}
</Component>
{options.scrollbar &&
(() => {
const el =
typeof options.scrollbar === 'object' &&
typeof options.scrollbar.el === 'string'
? options.scrollbar.el
: null;
const isClassSelector = el?.startsWith('.');
const isIdSelector = el?.startsWith('#');
const extractedClass = isClassSelector ? el?.slice(1) : '';
const extractedId = isIdSelector ? el?.slice(1) : undefined;
return (
<div
className={`relative w-full mt-14 mb-8 bg-white bg-opacity-20 h-px rounded-full ${extractedClass} `}
id={extractedId}>
<Scrollbar isDragging={isDragging} swiperRef={swiperRef as any} />
</div>
);
})()}
{options.pagination && (
<Container className="relative">
<div ref={paginationRef} className={paginationClasses} />
</Container>
)}
</div>
);
};
const Slide: React.FC<SwiperSlideProps> = ({ className, children }) => {
return <div className={cn('swiper-slide', className)}>{children}</div>;
};
SwiperElement.Slide = Slide;
export default SwiperElement;
export { default } from './SwiperElement';
export * from './SwiperElement';
.swiper-pagination-bullet {
@apply rounded-full max-w-2 bg-content4 hover:bg-opacity-70 relative cursor-pointer;
}
.swiper-pagination:not(.swiper-pagination-large) .swiper-pagination-bullet {
@apply max-w-2;
}
/* fraction style */
.swiper-pagination-fraction {
@apply gap-0;
}
.swiper-pagination-fraction .swiper-pagination-bullet {
@apply bg-content3-foreground bg-opacity-10 !h-[4px] grow !max-w-12 !w-full hover:bg-opacity-15 relative cursor-pointer rounded-none first:rounded-l last:rounded-r;
}
.swiper-pagination-fraction .swiper-pagination-bullet-active {
@apply relative;
}
.swiper-pagination-fraction .swiper-pagination-bullet-active::before {
content: '';
@apply absolute w-full h-full bg-gradient-to-r from-[#CC93D3] to-[#793BE0] hover:bg-opacity-100 rounded;
}
.swiper-pagination-bullet::after {
content: '';
@apply absolute inset-x-0 -inset-y-4;
}
.swiper-pagination-bullet-active {
@apply bg-primary hover:bg-opacity-100 grow;
}
.swiper-pagination-large .swiper-pagination-bullet {
@apply max-w-24;
}
.swiper-pagination-primary .swiper-pagination-bullet {
@apply hover:bg-opacity-60 h-2 w-2;
}
.swiper-pagination-primary .swiper-pagination-bullet-active {
@apply bg-primary bg-opacity-100 hover:bg-opacity-100;
}
.swiper-pagination-secondary .swiper-pagination-bullet {
@apply hover:bg-opacity-60 h-2 w-2;
}
.swiper-pagination-secondary .swiper-pagination-bullet-active {
@apply bg-secondary bg-opacity-100 hover:bg-opacity-100;
}
.swiper-pagination-light .swiper-pagination-bullet {
@apply hover:bg-opacity-60 h-2 w-2;
}
.swiper-pagination-light .swiper-pagination-bullet-active {
@apply bg-default-100 bg-opacity-100 hover:bg-opacity-100;
}
.swiper-pagination-dark .swiper-pagination-bullet {
@apply hover:bg-opacity-60 h-2 w-2;
}
.swiper-pagination-dark .swiper-pagination-bullet-active {
@apply bg-foreground bg-opacity-100 hover:bg-opacity-100;
}
.swiper-button-disabled {
@apply opacity-20 !cursor-default;
}
.swiper-pagination.swiper-pagination-lock,
.swiper-button-disabled.swiper-button-lock {
@apply hidden;
}
.circle-us {
@apply absolute top-0 left-0 w-full h-full bg-transparent rounded-full;
}
.circle-us:before,
.circle-us:after {
@apply content-[''] -left-[1px] -top-[1px] border-[#574a6ba5] block absolute w-16 h-16 inset-0 border-[1px] rounded-full;
}
.circle-us:before {
@apply animate-[ripples_2s_linear_infinite];
}
.circle-us:after {
@apply animate-[ripples_2s_linear_1s_infinite];
}
/* Ripple animation (still needs to be defined) */
@keyframes ripples {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.4);
opacity: 0.5;
}
100% {
transform: scale(1.8);
opacity: 0;
}
}
import type { Meta, StoryObj } from '@storybook/react';
import AddressMapComponent from './';
const meta: Meta<typeof AddressMapComponent> = {
title: 'TopLevel/AddressMap',
component: AddressMapComponent,
parameters: {
layout: 'fullscreen'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof AddressMapComponent>;
export const AddressMap: Story = {
args: {
title: "We're Easy to Find",
mapData: {
latitude: 29.970447,
longitude: 31.021278,
zoom: 16
},
button: {
label: 'Register your Interest',
url: 'https://www.google.com'
},
address: `El Wahat Rd,<br/>
First 6th of October,<br/>
Giza Governorate 12573,<br/>
Egypt`,
phone: '+20 2 34567897',
email: 'mafegypt@maf.com',
directionButton: {
label: 'Get Directions',
url: 'https://www.google.com'
}
}
};
import Link from 'next/link';
import { Link as HeroUILink } from '@heroui/react';
import Button from '@/components/base/Button';
import Icon from '@/components/base/Icon';
import Map from './Map';
import cn from '@/lib/merge-clsx';
const AddressMap: React.FC<IAddressMap> = ({
title,
phone,
email,
address,
mapData,
button,
directionButton
}) => {
return (
<section
className={cn(
'bg-primary-900 lg:p-24 p-3',
'[&:not(:first-child)]:-mt-6',
'[&:not(:last-child)]:-mb-6'
)}>
<div
className={cn(
'grid lg:grid-cols-12 lg:grid-rows-1 grid-cols-1 grid-rows-3 p-1 max-w-[1920px] mx-auto bg-background rounded-lg'
)}>
<div className="lg:col-span-4 row-span-1 lg:p-4 xl:p-12 p-6 flex flex-col items-center ">
<div className="grid gap-4 w-full">
<h2 className="font-serif text-3xl lg:text-4xl ">{title}</h2>
<div className="grid grid-cols-[2.25rem_1fr] items-start">
<Icon
name="location-pin"
className="text-[1.5rem] relative top-1"
/>
<div>
<div dangerouslySetInnerHTML={{ __html: address }} />
{directionButton?.url && (
<div className="my-2">
<Button
as={HeroUILink}
href={directionButton?.url}
target="_blank"
color="primary"
size="sm"
className="text-sm"
rel="noopener noreferrer">
<Icon name="location-pin" />
{directionButton?.label}
</Button>
</div>
)}
</div>
</div>
<div className="grid grid-cols-[2.25rem_1fr] items-center">
<Icon name="phone-light" className="text-[1.25rem]" />
<a href={`tel:${phone}`} className="hover:underline">
{phone}
</a>
</div>
<div className="grid grid-cols-[2.25rem_1fr] items-center">
<Icon name="email-light" />
<a href={`mailto:${email}`} className="hover:underline">
{email}
</a>
</div>
{button && (
<div>
<Button
as={Link}
href={button.url}
color="primary"
size="lg"
className="text-sm">
{button.label}
</Button>
</div>
)}
</div>
</div>
<div className="lg:col-span-8 row-span-2">
<div className="rounded-lg overflow-hidden h-full">
<Map {...mapData} />
</div>
</div>
</div>
</section>
);
};
export default AddressMap;
'use client';
import { memo } from 'react';
import {
APIProvider,
Map as GoogleMap,
AdvancedMarker
} from '@vis.gl/react-google-maps';
import marker from './img/marker.png';
import cn from '@/lib/merge-clsx';
const Map: React.FC<MapProps> = ({ latitude, longitude, zoom = 10 }) => {
const position = { lat: latitude, lng: longitude };
console.log(position);
return (
<div className="w-full h-full relative">
<APIProvider apiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || ''}>
<GoogleMap
mapId={'fd953d0c177625eb'}
defaultCenter={position}
defaultZoom={zoom}
gestureHandling={'cooperative'}
disableDefaultUI={true}>
<AdvancedMarker position={position}>
<div>
<img src={marker.src} alt="marker" width={50} height={50} />
</div>
</AdvancedMarker>
</GoogleMap>
</APIProvider>
</div>
);
};
export default memo(Map);
export { default } from './AddressMap';
export * from './AddressMap';
import { Meta, StoryObj } from '@storybook/react';
import AmenitiesCarouselComponent from '.';
import amenityImg1 from '@/assets/img/amenity-1.jpg';
const meta: Meta = {
title: 'TopLevel/AmenitiesCarousel',
component: AmenitiesCarouselComponent,
tags: ['autodocs'],
argTypes: {
onChange: { action: 'onChange triggered' }
}
};
export default meta;
type Story = StoryObj<typeof AmenitiesCarouselComponent>;
export const AmenitiesCarousel: Story = {
args: {
title: 'Amenities',
description:
'World-class workspaces, seamless facilities, and everything you need to work, relax, and stay inspired—all in one place',
amenities: [
{
title: 'Food & Beverages',
description:
"Satisfy your cravings with a diverse mix of flavors, from global cuisines to local favorites. Whether it's a quick bite, a cozy café, or a fine dining experience, every meal is a treat. Gather, feast, and enjoy the perfect blend of taste and ambiance!",
image: {
url: amenityImg1?.src,
width: 930,
height: 480,
alternativeText: 'Food & Beverages'
}
},
{
title: 'Fitness Center',
description:
'Stay active and energized in our state-of-the-art fitness center. Featuring premium equipment, yoga spaces, and personal training options to keep you at your best during your stay.',
image: {
url: amenityImg1?.src,
width: 930,
height: 480,
alternativeText: 'Fitness center'
}
},
{
title: 'Co-Working Spaces',
description:
'Productive environments designed for modern professionals. Enjoy high-speed internet, meeting rooms, and comfortable workstations that inspire creativity and collaboration.',
image: {
url: amenityImg1?.src,
width: 930,
height: 480,
alternativeText: 'Co-working space'
}
}
]
}
};
'use client';
import { useRef } from 'react';
import type { Swiper as SwiperType } from 'swiper';
import Container from '@/components/layout/Container';
import Amenity, { type IAmenity } from './Amenity';
import SwiperElement, {
SwiperElementProps
} from '@/components/shared/SwiperElement';
const AmenitiesCarousel = ({
locale = 'en',
title,
description,
amenities = []
}: IAmenitiesCarousel & { locale?: string }) => {
const swiperRef = useRef<SwiperType | null>(null);
const swiperOptions = {
init: true,
dir: locale === 'ar' ? 'rtl' : 'ltr',
spaceBetween: 100,
slidesPerView: 'auto',
scrollbar: {
el: '#custom-scrollbar',
draggable: true,
hide: false,
dragSize: 200
},
onInit: (swiper: SwiperType) => {
swiperRef.current = swiper;
}
} as SwiperElementProps['options'];
return (
<section className="mx-4 sm:mx-0">
<Container className="rounded-xl bg-primary px-5 py-8 md:p-16 w-full overflow-hidden my-8">
<div className="flex flex-col gap-4 ">
<header className="text-white max-w-xl mb-6 md:mb-8">
<h2 className="text-inherit text-2xl font-serif mb-3 md:text-4xl">
{title}
</h2>
<p className="text-sm font-light md:text-base">{description}</p>
</header>
</div>
{amenities?.length > 0 && (
<div className="relative">
<SwiperElement
ref={swiperRef as any}
key={locale}
className="[&>.swiper]:overflow-visible"
options={swiperOptions}>
{amenities.map((amenity: IAmenity, index) => (
<SwiperElement.Slide key={index}>
<Amenity
{...amenity}
index={(index + 1).toString().padStart(2, '0')}
/>
</SwiperElement.Slide>
))}
</SwiperElement>
</div>
)}
</Container>
</section>
);
};
export default AmenitiesCarousel;
import React from 'react';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
import { cn } from '@heroui/react';
export interface IAmenity {
title: string;
description: string;
image: IDynamicImage;
}
const Amenity: React.FC<IAmenity & { index: string }> = ({
index,
title,
description,
image
}) => {
const cardClassNames = cn([
'lg:min-h-[18em]',
'flex flex-col justify-center lg:gap-4',
'bg-[rgba(40,43,70,0.5)]',
'backdrop-blur-[10px]',
'bg-gradient-to-b',
'from-[#CC93D3]',
'via-[#CC93D3]',
'to-[#793BE0]',
'border border-transparent',
'px-4 py-6 md:p-8',
'text-white',
'rounded-lg',
'lg:max-w-sm xl:max-w-md',
'before:bg-content',
'before:absolute',
'before:inset-0',
'before:rounded-lg',
'before:bg-primary-800/95',
'before:-z-10'
]);
return (
<div className="flex flex-col lg:flex-row gap-4 md:gap-6 lg:min-h-[30em]">
<div className={cardClassNames}>
{index && (
<h1 className="font-light text-5xl md:text-4xl lg:text-8xl mb-4 bg-gradient-to-b from-[#CC93D3] via-[#CC93D3] to-[#793BE0] bg-clip-text text-transparent">
{index}
</h1>
)}
{title && (
<h2 className="text-white font-serif text-xl mb-3 md:text-4xl">
{title}
</h2>
)}
{description && <p className="mb-2">{description}</p>}
</div>
<div className="rounded-xl overflow-hidden relative w-full max-w-6xl">
<div className="lg:absolute lg:min-h-[26em] h-full z-10 top-0 left-0 [&>picture]:w-full [&>picture]:h-full">
<ResponsiveImage
priority
className="select-none h-full lg:object-cover object-center aspect-[2/1]"
src={image?.url}
width={image?.width}
height={image?.width}
sizes="100vw"
/>
</div>
</div>
</div>
);
};
export default Amenity;
export { default } from './AmenitiesCarousel';
export * from './AmenitiesCarousel';
import type { Meta, StoryObj } from '@storybook/react';
import BannerComponent from './Banner';
import image from '@/assets/img/banner-img.jpg';
import area from '@/assets/img/icons/area.png';
import basement from '@/assets/img/icons/basement.png';
import office from '@/assets/img/icons/office.png';
import residence from '@/assets/img/icons/residence.png';
import tower from '@/assets/img/icons/tower.png';
import store from '@/assets/img/icons/store.png';
const meta: Meta<typeof BannerComponent> = {
title: 'TopLevel/Banner',
component: BannerComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Banner: Story = {
args: {
title: 'JUNCTION',
description:
"A launchpad for big ideas, bold moves, and unstoppable innovation. It’s more than just a place to work; it’s a thriving ecosystem where creativity meets opportunity. With dynamic spaces, modern design, and an energy that keeps things moving. This is where ideas spark, connections thrive, and every day brings something new. Whether you're brainstorming your next big thing, teaming up with like-minded innovators, or just enjoying the buzz of a vibrant community, there’s always something happening here.",
button: {
label: 'REGISTER YOUR INTEREST',
url: '#'
},
labels: {
scrollDown: 'scroll down'
},
specifications: [
{
image: {
url: area.src,
width: area.width,
height: area.height,
alternativeText: 'area'
},
label: 'Land area',
value: '93k Sqm'
},
{
image: {
url: tower.src,
width: tower.width,
height: tower.height,
alternativeText: 'tower'
},
label: '# of buildings',
value: '13'
},
{
image: {
url: office.src,
width: office.width,
height: office.height,
alternativeText: 'office'
},
label: '# of offices',
value: '650 Units'
},
{
image: {
url: basement.src,
width: basement.width,
height: basement.height,
alternativeText: 'basement'
},
label: 'Total BUA (Including basement)',
value: '150 Sqm'
},
{
image: {
url: store.src,
width: store.width,
height: store.height,
alternativeText: 'store'
},
label: 'of F&B and retail units',
value: '55'
},
{
image: {
url: residence.src,
width: residence.width,
height: residence.height,
alternativeText: 'residence'
},
label: '1 building with (150 keys) & 100 branded residence',
value: 'Hospitality'
}
],
image: {
url: image.src,
width: image.width,
height: image.height,
alternativeText: 'Banner image'
}
}
};
'use client';
import Link from 'next/link';
import Button from '@/components/base/Button';
import Icon from '@/components/base/Icon/Icon';
import Container from '@/components/layout/Container';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
import Counter from './Counter';
import scrollTheFold from '@/lib/scrollTheFold';
import cn from '@/lib/merge-clsx';
import RenderMarkdown from '@/components/shared/RenderMarkdown';
import { spec } from 'node:test/reporters';
const Banner: React.FC<IBanner> = ({
title,
description,
button,
image,
specifications,
labels
}) => {
return (
<section className="dark py-10 bg-default-50 text-foreground">
<Container>
<div className="relative mb-4 md:mb-8">
<div className="relative z-10">
<h1
className={cn(
'font-sans',
'[-webkit-text-stroke:0.8px]',
'[-webkit-text-fill-color:transparent]',
'text-5xl sm:text-7xl md:text-8xl xl:text-[10rem]',
'text-center uppercase',
'-mb-3 sm:-mb-4 md:-mb-7 xl:-mb-10'
)}>
{title}
</h1>
</div>
<div className="relative overflow-hidden mb-8 lg:px-16">
<div>
<ResponsiveImage
src={image.url}
width={image.width}
height={image.height}
className="mx-auto overflow-hidden object-cover rounded-xl min-h-40"
sizes="100vw"
alt={image.alternativeText}
priority
/>
</div>
</div>
{labels?.scrollDown && (
<div className="hidden absolute z-10 bottom-16 md:bottom-8 -end-4 lg:flex lg:flex-col lg:justify-start">
<div
className={cn(
'relative h-24 w-[1px] before:absolute before:inset-0',
'before:bg-[linear-gradient(100deg,#CC93D3_0%,#793BE0_100%)] ms-1.5'
)}></div>
<button
onClick={scrollTheFold}
className="text-start cursor-pointer mt-2 transition-opacity opacity-50 hover:opacity-90">
<Icon name="scroll" className="text-xl" />
<span className="font-light uppercase text-sm text-start block max-w-min break-words">
{labels.scrollDown}
</span>
</button>
</div>
)}
</div>
<div className="lg:px-[12%]">
<div className="relative">
<RenderMarkdown
components={{
p: ({ children }) => (
<p className="text-white opacity-80 font-sans font-light mb-8 leading-6 tracking-wider md:text-lg xl:text-xl">
{children}
</p>
)
}}>
{description}
</RenderMarkdown>
{button && (
<div className="flex justify-center sm:mt-8 mb-16">
<Button
as={Link}
href={button.url}
color="primary"
size="lg"
className="text-sm">
{button.label}
</Button>
</div>
)}
</div>
<div className="relative">
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-8 lg:gap-10 text-foreground">
{specifications.map(({ label, value, image }) => {
return (
<Counter
key={label}
label={label}
icon={image}
count={value}
/>
);
})}
</div>
</div>
</div>
</Container>
</section>
);
};
export default Banner;
import ResponsiveImage from '@/components/shared/ResponsiveImage';
const Counter: React.FC<CounterProps> = ({ icon, label, count }) => {
return (
<div className="flex items-start h-full gap-5 grow">
<ResponsiveImage
src={icon.url}
width={icon.width}
height={icon.height}
sizes="50px"
className="max-w-[4.5rem] bg-background"
/>
<div className="space-y-1 w-fit">
<h5 className="text-wrap text-white text-4xl lg:text-[2.75rem] whitespace-nowrap font-serif min-w-20">
{count}
</h5>
<p
className="font-thin text-white opacity-70"
dangerouslySetInnerHTML={{ __html: label }}
/>
</div>
</div>
);
};
export default Counter;
export * from './Banner';
export { default } from './Banner';
import type { Meta, StoryObj } from '@storybook/react';
import GalleryCardComponent from './GalleryCard';
import cardImage from '@/components/form/EventFormWidget/img/card-img.jpg';
const meta: Meta<typeof GalleryCardComponent> = {
title: 'TopLevel/Gallery/Card',
component: GalleryCardComponent,
tags: ['autodocs'],
decorators: (Story) => (
<div className="max-w-xs">
<Story />
</div>
)
};
export default meta;
type Story = StoryObj<typeof meta>;
export const GalleryCard: Story = {
args: {
image: {
url: cardImage.src,
width: cardImage.width,
height: cardImage.height,
alt: 'card-1'
},
title: 'Our Offerings'
}
};
import type { Meta, StoryObj } from '@storybook/react';
import GalleryComponent from '.';
import galleryImg1 from '@/assets/img/gallery/gallery-1.jpg';
import galleryImg2 from '@/assets/img/gallery/gallery-2.jpg';
import galleryImg3 from '@/assets/img/gallery/gallery-3.jpg';
import galleryImg4 from '@/assets/img/gallery/gallery-4.jpg';
import galleryImg5 from '@/assets/img/gallery/gallery-5.jpg';
import galleryImg6 from '@/assets/img/gallery/gallery-6.jpg';
const meta: Meta<typeof GalleryComponent> = {
title: 'TopLevel/Gallery',
component: GalleryComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Gallery: Story = {
args: {
title: 'What’s on Your Mind?',
subtitle: 'Let’s Find It!',
description: `What you're looking for, right here! From premium spaces to top-notch perks, seamless convenience, and a vibrant community—designed to elevate your experience and keep you inspired every day.`,
gallery: [
{
image: {
url: galleryImg1.src,
width: galleryImg1.width,
height: galleryImg1.height,
alt: 'Image-1'
},
title: 'Our Offerings'
},
{
image: {
url: galleryImg2.src,
width: galleryImg2.width,
height: galleryImg2.height,
alt: 'image-2'
},
title: 'Discover our community'
},
{
image: {
url: galleryImg3.src,
width: galleryImg3.width,
height: galleryImg3.height,
alt: 'Image-3'
},
title: 'Cultivate Connections'
},
{
image: {
url: galleryImg4.src,
width: galleryImg4.width,
height: galleryImg4.height,
alt: 'Image-4'
},
title: 'Attend Events'
},
{
image: {
url: galleryImg5.src,
width: galleryImg5.width,
height: galleryImg5.height,
alt: 'Image-5'
},
title: 'Grow Together'
},
{
image: {
url: galleryImg6.src,
width: galleryImg6.width,
height: galleryImg6.height,
alt: 'Image-6'
},
title: 'Explore'
}
]
}
};
'use client';
import React from 'react';
import cn from '@/lib/merge-clsx';
import Container from '@/components/layout/Container';
import SwiperElement from '@/components/shared/SwiperElement';
import GalleryCard from './GalleryCard';
const Gallery: React.FC<IGallery> = ({
title,
description,
subtitle,
gallery
}) => {
const Description = (
<p className=" md:max-w-[16rem] lg:max-w-full lg:px-4 md:line-clamp-[7] lg:line-clamp-6">
{description}
</p>
);
const Heading = (
<div className="text-4xl md:text-3xl lg:text-4xl *:leading-[3rem] lg:px-4 *:line-clamp-2 lg:min-h-48">
<h1 className="font-semibold font-serif">{title}</h1>
<p className="md:mt-2 lg:my-5 font-light font-serif">{subtitle}</p>
</div>
);
const stylesOfContent = {
order: 4
};
const Desktoplayout = () => {
return (
<div className="hidden md:grid grid-cols-3 gap-2 md:gap-6 overflow-auto no-scrollbar *:md:max-w-xs mt-4 sm:place-content-center md:w-fit md:mx-auto">
<div
className="hidden md:inline-block text-right"
style={stylesOfContent}>
{Heading}
</div>
<div
className="hidden md:inline-block gap-div"
style={stylesOfContent}
/>
<div className="hidden md:inline-block" style={stylesOfContent}>
{Description}
</div>
{gallery &&
gallery.map(({ image, title }, index) => {
return (
<GalleryCard
image={image}
style={{
order: index + 1
}}
key={index}
classname={cn(
`${index <= 1 ? 'col-span-2 md:col-span-1' : ''}
w-full
${index === 1 ? 'md:top-[5.5em] lg:top-24' : ''}
${index % 6 === 4 ? 'md:bottom-[6.6em] lg:bottom-28' : ''}
${index >= 6 && index % 6 === 1 ? 'md:bottom-[6.6em] lg:bottom-28' : ''}
`
)}
title={title}
/>
);
})}
</div>
);
};
const Mobilelayout = () => (
<div className="md:hidden">
{Heading}
{Description}
<SwiperElement
className="mt-4 max-md:[&>.swiper]:!overflow-visible [&_.swiper-wrapper]:!gap-2"
options={{
slidesPerView: 'auto',
grabCursor: true,
pagination: {
type: 'fraction',
variant: 'primary',
position: 'bottom',
align: 'center'
}
}}>
{Array.from({ length: Math.ceil(gallery.length / 3) }).map((_, i) => (
<SwiperElement.Slide key={i} className="sm:max-w-[50%] w-full">
<div className="grid grid-cols-2 gap-2">
{gallery.slice(i * 3, i * 3 + 3).map(({ image, title }, j) => (
<GalleryCard
key={j}
image={image}
title={title}
classname={cn(j === 0 ? 'col-span-2' : '')}
/>
))}
</div>
</SwiperElement.Slide>
))}
</SwiperElement>
</div>
);
return (
<Container as="section" className="overflow-hidden !my-16 md:!my-20">
<Mobilelayout />
<Desktoplayout />
</Container>
);
};
export default Gallery;
import { CardProps, cn, Card as NextCard } from '@heroui/react';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
interface IGalleryCardProps extends CardProps {
title?: string;
image?: IDynamicImage;
classname?: string;
}
const GalleryCard: React.FC<IGalleryCardProps> = ({
image,
classname,
title,
style
}) => {
return (
<NextCard
style={{
...style
}}
className={cn(
'shadow-none min-h-52 md:min-h-[24rem] lg:min-h-[28rem] inline-block relative w-full group',
classname
)}>
{image && (
<ResponsiveImage
src={image.url}
width={image.width}
height={image.height}
alt={image.alternativeText}
sizes="100vw"
className=" absolute object-cover w-full h-full aspect-[9/16]"
/>
)}
<div className="absolute z-10 w-full h-full bg-gradient-to-t from-[rgba(0,0,0,0)_1%] to-transparent flex items-end p-4 md:p-6">
{title && <h1 className="text-lg text-white font-serif">{title}</h1>}
</div>
</NextCard>
);
};
export default GalleryCard;
export { default } from './Gallery';
export * from './Gallery';
import type { Meta, StoryObj } from '@storybook/react';
import ImageCarouselComponent from './ImageCarousel';
import homePageSwiperImg1 from '@/assets/img/image-carousel-1.jpg';
import homePageSwiperImg2 from '@/assets/img/image-carousel-2.jpg';
import homePageSwiperImg3 from '@/assets/img/image-carousel-3.jpg';
const meta: Meta<typeof ImageCarouselComponent> = {
title: 'TopLevel/ImageCarousel',
component: ImageCarouselComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
}
};
export default meta;
type Story = StoryObj<typeof ImageCarouselComponent>;
export const ImageCarousel: Story = {
args: {
slides: [
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg1.src,
width: homePageSwiperImg1.width,
height: homePageSwiperImg1.height,
alternativeText: 'Business Hub Slide'
}
},
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg2.src,
width: homePageSwiperImg2.width,
height: homePageSwiperImg2.height,
alternativeText: 'Office Space Slide'
}
},
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg3.src,
width: homePageSwiperImg3.width,
height: homePageSwiperImg3.height,
alternativeText: 'Premium Workspace Slide'
}
},
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg1.src,
width: homePageSwiperImg1.width,
height: homePageSwiperImg1.height,
alternativeText: 'Business Hub Slide'
}
},
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg2.src,
width: homePageSwiperImg2.width,
height: homePageSwiperImg2.height,
alternativeText: 'Office Space Slide'
}
},
{
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: homePageSwiperImg3.src,
width: homePageSwiperImg3.width,
height: homePageSwiperImg3.height,
alternativeText: 'Premium Workspace Slide'
}
}
]
}
};
'use client';
import { useMemo } from 'react';
import SwiperElement from '@/components/shared/SwiperElement';
import type { SwiperElementProps } from '@/components/shared/SwiperElement';
import Slide, { ISlideProps } from './Slide';
import type { Swiper as SwiperType } from 'swiper';
import cn from '@/lib/merge-clsx';
import './styles.css';
const ImageCarousel: React.FC<IImageCarousel> = ({ slides }) => {
const swiperOptions = useMemo(() => {
return {
slidesPerView: 'auto',
autoHeight: false,
centeredSlides: true,
slideToClickedSlide: true,
grabCursor: true,
initialSlide: 0,
loop: false,
speed: 800,
scrollbar: {
el: '#scrollbar',
draggable: true,
hide: false,
dragSize: 200
},
on: {
afterInit: (swiper: SwiperType) => {
swiper.slideNext();
}
},
effect: 'creative',
creativeEffect: {
limitProgress: 3,
progressMultiplier: 3
},
breakpoints: {
320: {
creativeEffect: {
next: {
translate: ['35%', 0, 0],
opacity: 1
},
prev: {
translate: ['-35%', 0, 0],
opacity: 1
}
}
},
648: {
creativeEffect: {
next: {
translate: ['29.5%', 0, 0],
scale: 0.9,
opacity: 1
},
prev: {
translate: ['-29.5%', 0, 0],
scale: 0.9,
opacity: 1
}
}
}
}
} as SwiperElementProps['options'];
}, []);
const swiperClass = cn(['max-lg:[&>.swiper]:!overflow-visible']);
return (
<section className="dark bg-default-50 pt-24 pb-12 px-10 lg:pb-16 Carousel overflow-hidden ">
<div className="max-w-[1920px] mx-auto">
<SwiperElement options={swiperOptions} className={swiperClass}>
{slides.map((slide, index) => (
<SwiperElement.Slide
key={index}
className="origin-bottom lg:max-w-screen-lg">
<Slide {...slide} />
</SwiperElement.Slide>
))}
</SwiperElement>
</div>
</section>
);
};
export default ImageCarousel;
import type { Meta, StoryObj } from '@storybook/react';
import SlideComponent from './Slide';
import image from '@/assets/img/image-carousel-1.jpg';
const meta: Meta<typeof SlideComponent> = {
title: 'TopLevel/ImageCarousel ',
component: SlideComponent,
parameters: {
layout: 'centered'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof SlideComponent>;
export const Slide: Story = {
args: {
title: 'Business Park in Egypt',
description:
'Spaces crafted with innovation, sophistication, and convenience. Designed to inspire growth and elevate your brand, our spaces offer the perfect balance of style, functionality, and seamless accessibility.',
image: {
url: image.src,
width: image.width,
height: image.height,
alternativeText: 'Slide image'
}
},
render: (args) => (
<div className="max-w-[60rem]">
<SlideComponent {...args} />
</div>
)
};
import React from 'react';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
export interface ISlideProps {
title?: string;
description?: string;
image: IDynamicImage;
}
const Slide: React.FC<ISlideProps> = ({ title, description, image }) => {
const imageClass =
'z-0 w-full h-full object-cover aspect-[9/16] sm:aspect-[8/10] md:aspect-[4/3]';
return (
<div className="relative rounded-xl overflow-hidden">
<ResponsiveImage
className={imageClass}
src={image.url}
width={image.width}
height={image.height}
alt={image.alternativeText}
priority
sizes="lg 50vw, sm 640px ,85vw"
/>
<div className="absolute inset-0 flex flex-col justify-end bg-gradient-to-t from-primary from-0% to-transparent to-30% z-10 px-6 xl:px-8 2xl:px-10">
<h5 className="text-foreground text-2xl font-light font-serif mb-2 md:text-3xl lg:text-4xl">
{title}
</h5>
<p className="text-foreground font-light mb-8 max-w-screen-md lg:text-lg 2xl:text-xl">
{description}
</p>
</div>
</div>
);
};
export default Slide;
export { default } from './ImageCarousel';
export * from './ImageCarousel';
.Carousel :is(.swiper-slide-prev, .swiper-slide-next) p {
@apply opacity-0 transition-opacity duration-300 ease-in-out;
}
.Carousel :is(.swiper-slide-active) p {
@apply opacity-100 transition-opacity duration-300 ease-in-out;
}
.Carousel :is(.swiper-slide-prev, .swiper-slide-next) h5 {
@apply opacity-0 transition-opacity duration-300 ease-in-out;
}
.Carousel :is(.swiper-slide-active) h5 {
@apply opacity-100 transition-opacity duration-300 ease-in-out;
}
import type { Meta, StoryObj } from '@storybook/react';
import MasterPlanComponent from './MasterPlan';
import image from '@/assets/img/master-plan.jpg';
const meta: Meta<typeof MasterPlanComponent> = {
title: 'TopLevel/MasterPlan',
component: MasterPlanComponent,
parameters: {
layout: 'fullscreen'
},
tags: ['autodocs']
};
export default meta;
type Story = StoryObj<typeof MasterPlanComponent>;
export const MasterPlan: Story = {
args: {
title: 'Explore our Masterplan',
image: {
url: image.src,
width: image.width,
height: image.height,
alternativeText: 'Master Plan Image'
},
description:
"Big ideas need the right space to grow, Whether you're launching, scaling, or reinvesting, we've got the perfect spot for you. Let's build something amazing-together!.",
button: {
label: 'DOWNLOAD BROCHURE',
url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'
}
}
};
'use client';
import { Parallax } from 'react-scroll-parallax';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
import Container from '@/components/layout/Container';
import Button from '@/components/base/Button';
import Link from 'next/link';
import Icon from '@/components/base/Icon';
const MasterPlan: React.FC<IMasterPlan> = ({
title,
description,
image,
button
}: IMasterPlan) => {
return (
<section className="my-6">
<Parallax translateY={[20, -20]}>
<Container as="header" className="text-center max-w-screen-md mb-2 ">
<h2 className="text-2xl font-serif mb-2 md:text-4xl">{title}</h2>
<p className="text-sm font-light md:text-base mb-6">{description}</p>
{button && (
<div className="mt-6 mb-4">
<Button
as={Link}
href={button.url}
color="primary"
size="lg"
target="_blank"
rel="noopener noreferrer"
className="text-sm tracking-wider px-9"
startContent={<Icon name="download" />}>
{button.label}
</Button>
</div>
)}
</Container>
</Parallax>
<div className="relative overflow-hidden">
<Parallax translateY={[-20, 20]} className="relative overflow-hidden">
<ResponsiveImage
src={image.url}
width={image.width}
height={image.height}
sizes="(max-width: 1920px) 100vw, 1920px"
className="mx-auto max-w-full min-h-60 object-cover"
/>
</Parallax>
</div>
</section>
);
};
export default MasterPlan;
export { default } from './MasterPlan';
export * from './MasterPlan';
import type { Meta, StoryObj } from '@storybook/react';
import VideoContentComponent from './VideoContent';
import image from '@/assets/img/about.jpg';
const meta: Meta<typeof VideoContentComponent> = {
title: 'TopLevel/VideoContent',
component: VideoContentComponent,
tags: ['autodocs'],
parameters: {
layout: 'fullscreen'
}
};
export default meta;
type Story = StoryObj<typeof meta>;
export const VideoContent: Story = {
args: {
title: 'Brought to you by Majid Al Futtaim',
description:
"Big ideas need the right space to grow. Whether you're launching, scaling, or reinventing, we’ve got the perfect spot for you. Let’s build something amazing—together!",
videoSet: {
portrait: {
url: 'https://getsamplefiles.com/download/mp4/sample-3.mp4'
},
landscape: {
url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4'
}
},
imageSet: {
portrait: {
url: image.src,
width: image.width,
height: image.height
},
landscape: {
url: image.src,
width: image.width,
height: image.height
}
}
}
};
export const JustImage: Story = {
args: {
title: 'Brought to you by Majid Al Futtaim',
description:
"Big ideas need the right space to grow. Whether you're launching, scaling, or reinventing, we’ve got the perfect spot for you. Let’s build something amazing—together!",
imageSet: {
portrait: {
url: image.src,
width: image.width,
height: image.height
},
landscape: {
url: image.src,
width: image.width,
height: image.height
}
}
}
};
'use client';
import { useMemo } from 'react';
import { Parallax } from 'react-scroll-parallax';
import Container from '@/components/layout/Container';
import { ResponsiveVideo } from '@/components/shared/ResponsiveVideo';
import ResponsiveImage from '@/components/shared/ResponsiveImage';
const VideoContent: React.FC<IVideoContent> = ({
title,
videoSet,
imageSet,
description
}) => {
const className = 'mx-auto max-w-full min-h-60 object-cover';
const imageFallback = useMemo(
() => (
<ResponsiveImage
src={imageSet?.portrait.url}
width={imageSet?.portrait.width}
height={imageSet?.portrait.height}
sizes="100vw"
className={className}>
<ResponsiveImage.Source
media="xxl"
src={imageSet?.landscape.url}
width={imageSet?.landscape.width}
height={imageSet?.landscape.height}
sizes="(max-width: 1920px) 100vw, 1920px"
/>
</ResponsiveImage>
),
[imageSet]
);
return (
<section className="pt-6 dark bg-default-50 text-foreground">
<Parallax translateY={[20, -20]}>
<Container as="header" className="text-center mb-6 md:mb-8">
<h2 className="text-3xl font-serif mb-6 md:text-6xl">{title}</h2>
<p className="text-sm font-light max-w-screen-md mx-auto md:text-base">
{description}
</p>
</Container>
</Parallax>
<div className="relative overflow-hidden">
<Parallax translateY={[-30, 30]} className="relative overflow-hidden">
{videoSet ? (
<ResponsiveVideo
src={videoSet?.portrait.url}
srcSet={
videoSet && [{ src: videoSet.landscape.url, media: 'sm' }]
}
className={className}
autoPlayFallback={imageFallback}
playsInline
autoPlay
muted
loop
/>
) : (
imageFallback
)}
</Parallax>
</div>
</section>
);
};
export default VideoContent;
export * from './VideoContent';
export { default } from './VideoContent';
{
"family": "american-tourister-travel-buddies",
"taskRoleArn": "arn:aws:iam::060686542424:role/EcsTaskS3ReadOnlyAccess",
"networkMode": "bridge",
"containerDefinitions": [
{
"name": "app",
"image": "{{app_image_tag}}",
"cpu": 1,
"memoryReservation": 32,
"essential": true,
"readonlyRootFilesystem": false,
"environment": [
{ "name": "APP_ENV", "value": "{{app_env}}" },
{ "name": "NODE_ENV", "value": "production" },
{ "name": "APP_RECAPTCHA_SECRET", "value": "{{app_recaptcha_secret}}" },
{ "name": "APP_APIGEE_USERNAME", "value": "{{app_apigee_username}}" },
{ "name": "APP_APIGEE_PASSWORD", "value": "{{app_apigee_password}}" }
]
}
]
}
{
"header":{
"menuItems": [
{
"label": "Home",
"value":"home",
"isExternal": true
},
{
"label": "About",
"value":"about"
},
{
"label": "Profile",
"value":"profile"
},
{
"label": "Blog",
"value":"blog",
"isExternal": true
}
]
},
"form": [
{
"id": "071e",
"firstName": "dsdsdfs",
"lastName": "dfdf",
"email": "fdfd@gmail.com",
"mobile": "4533536356"
},
{
"id": "e62c",
"firstName": "Madhan",
"lastName": "kelvin",
"email": "madhankumar.r@krds.fr",
"mobile": "9898895494"
},
{
"id": "b475",
"firstName": "Esther",
"lastName": "kelvin",
"email": "Aletha_Quitzon@gmail.com",
"mobile": "8498954895"
},
{
"id": "614a",
"firstName": "B",
"lastName": "Harvey",
"email": "Aletha_Quitzon@gmail.com",
"mobile": "9898895494"
}
]
}
import clsx from 'clsx';
import { extendTailwindMerge } from 'tailwind-merge';
import type { ClassValue } from 'clsx';
const COMMON_UNITS = ['small', 'medium', 'large'];
/**
* We need to extend the tailwind merge to include NextUI's custom classes. *
* So we can use classes like `text-small` or `text-default-500` and override them.
*/
const twMerge = extendTailwindMerge({
extend: {
theme: {
opacity: ['disabled'],
spacing: ['divider'],
borderWidth: COMMON_UNITS,
borderRadius: COMMON_UNITS
},
classGroups: {
shadow: [{ shadow: COMMON_UNITS }],
'font-size': [{ text: ['tiny', ...COMMON_UNITS] }],
'bg-image': ['bg-stripe-gradient']
}
}
});
export default function mergeClsx(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export default function scrollTheFold() {
window.scrollTo({
top: window.innerHeight,
behavior: 'smooth'
});
}
import galleryImg1 from '@/assets/img/gallery/image-1.jpg';
import { createMockLabels } from './labels';
export const createMockData: () => IPageRenderer = () => {
return {
slug: 'home',
components: [
{
component: 'banner',
title: 'Banner',
description: ` Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo et quae
consequuntur voluptatum quibusdam, autem velit quidem laborum, dignissimos
doloremque ullam eos fugit repellendus maiores eveniet repellat dolor eius
perspiciatis? Lorem ipsum dolor sit amet, consectetur adipisicing elit.`,
image: {
url: galleryImg1.src,
width: galleryImg1.width,
height: galleryImg1.height,
alternativeText: 'Banner image'
},
},
{
component: 'about',
title: 'About',
markdown: `Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo et quae
consequuntur voluptatum quibusdam, autem velit quidem laborum, dignissimos
doloremque ullam eos fugit repellendus maiores eveniet repellat dolor eius
perspiciatis? Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo et quae `
},
{
component: 'profile',
title: 'Registration Form',
labels: createMockLabels().form
}
]
}
}
const labels: { form: IFormLabels } = {
form: {
title: 'Title*',
firstName: 'First Name*',
lastName: 'Last Name*',
email: 'Email*',
mobile: 'Mobile*',
company: 'Company*',
date: 'Date*',
session: 'Session Time*',
budget: 'Budget',
residence: 'Country of Resident',
unitSize: 'Unit Size',
unitType: 'Unit Type*',
purpose: 'What is the purpose of buying?*',
terms:
'I have read and understood the <a href="https://privacy-center.majidalfuttaim.com/client/2d5739a0-dda3-4b4a-a445-c058ae6dd4eb?lang=en&country=AE#/privacy-notice" target="_blank">Privacy Policy</a>',
clearButtonLabel: 'CLEAR',
submitButtonLabel: 'SUBMIT',
errorTitleRequired: 'Please select a title',
errorFirstNameRequired: 'Please enter your first name',
errorFirstNameInvalid: 'Please enter letters only',
errorLastNameRequired: 'Please enter your last name',
errorLastNameInvalid: 'Please enter letters only',
errorEmailRequired: 'Please enter your email address',
errorEmailInvalid: 'Please enter a valid email address',
errorMobileRequired: 'Please enter your mobile number',
errorMobileInvalid: 'Please enter a valid mobile number',
errorCompanyRequired: 'Please enter your company name',
errorTermsRequired: 'Please accept the terms and conditions',
errorDateRequired: 'Please select a date',
errorSessionRequired: 'Please select a session time',
errorPurposeRequired: 'Please select your Purpose of the Buying',
errorUnitTypeRequired: 'Please select a unit',
errorRecaptchaRequired: 'Please complete the reCAPTCHA verification',
formSuccessText:
'Form submitted successfully. Thank you for your interest.',
formErrorText: 'Form submission failed! Please try again.'
}
};
export default labels;
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
module.exports = {
output: 'standalone',
images: {
remotePatterns: [
{
protocol: 'http',
hostname: 'localhost',
port: '1337', // Add port if your dev server runs on it
pathname: '/uploads/**',
},
{
protocol: 'https',
hostname: 'picsum.photos'
},
{
protocol: 'https',
hostname: 's3-ap-southeast-1.amazonaws.com'
}
],
imageSizes: [64, 128, 256, 576, 768, 992, 1200, 1600, 1920, 2048, 3840]
},
webpack: (config, { isServer }) => {
if (process.env.ANALYZE && !isServer) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerPort: 8888,
openAnalyzer: true
})
);
}
return config;
},
async rewrites() {
return [
{
source: '/api/:path*',
destination: `${process.env.NEXT_PUBLIC_API_URL}/:path*`
}
];
},
poweredByHeader: false,
compress: false
};
{
"name": "maf-egypt-business-park",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"analyze": "cross-env ANALYZE=true next build"
},
"dependencies": {
"@conform-to/react": "^1.4.0",
"@conform-to/zod": "^1.4.0",
"@heroui/react": "2.7.6",
"@storybook/react": "^8.6.12",
"@types/node": "^22.14.0",
"@types/react": "^19.1.0",
"@types/react-google-recaptcha": "^2.1.9",
"@vis.gl/react-google-maps": "^1.5.2",
"autoprefixer": "^10.4.21",
"clsx": "^2.1.1",
"color2k": "^2.0.3",
"framer-motion": "^12.6.3",
"lenis": "^1.2.3",
"next": "^15.2.4",
"postcss": "^8.5.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-google-recaptcha": "^3.1.0",
"react-hook-form": "^7.55.0",
"react-markdown": "^10.1.0",
"react-phone-input-2": "^2.15.1",
"react-scroll-parallax": "^3.4.5",
"rehype-raw": "^7.0.0",
"sharp": "^0.33.5",
"swiper": "^11.2.6",
"tailwind-merge": "^2.6.0",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"zod": "^3.24.3"
},
"devDependencies": {
"@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.8.0",
"@storybook/addon-essentials": "^8.6.12",
"@storybook/addon-interactions": "^8.6.12",
"@storybook/addon-links": "^8.6.12",
"@storybook/addon-onboarding": "^8.6.12",
"@storybook/blocks": "^8.6.12",
"@storybook/nextjs": "^8.6.12",
"@storybook/test": "^8.6.12",
"@storybook/theming": "^8.6.12",
"@types/eslint": "^9.6.1",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^9.24.0",
"eslint-config-next": "^15.2.4",
"eslint-plugin-storybook": "^0.12.0",
"husky": "^9.1.7",
"prettier": "^3.5.3",
"pretty-quick": "^4.1.1",
"storybook": "^8.6.12",
"storybook-dark-mode": "^4.0.2",
"webpack-bundle-analyzer": "^4.10.2"
},
"packageManager": "pnpm@10.7.1+sha256.dc514890ea719003cb7a57d6b21af24fdafadd9f171e7567eca1665d7cfcef76"
}
This source diff could not be displayed because it is too large. You can view the blob instead.
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};
<svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 512 103.22"><path d="M340.36.04h89.18V16.5h-35.38v86.6h-17.69V16.5h-36.11V.04zM503.8 70.86c-.19-1.82-1.03-3.25-2.49-4.27-1.48-1.03-3.38-1.54-5.72-1.54-1.64 0-3.05.25-4.23.74-1.17.49-2.08 1.15-2.71 1.99-.62.84-.93 1.8-.96 2.87 0 .9.22 1.68.64 2.33.42.66.98 1.22 1.71 1.67.72.46 1.52.83 2.4 1.14.89.31 1.77.57 2.66.78l4.09 1c1.64.38 3.23.89 4.76 1.54 1.52.64 2.9 1.45 4.11 2.43 1.21.98 2.17 2.16 2.87 3.54.71 1.39 1.07 3.01 1.07 4.87 0 2.52-.65 4.73-1.95 6.64-1.31 1.9-3.19 3.39-5.66 4.46-2.46 1.07-5.43 1.61-8.93 1.61-3.38 0-6.33-.52-8.81-1.56-2.49-1.03-4.44-2.54-5.84-4.52-1.4-1.99-2.15-4.41-2.26-7.26h7.76c.11 1.49.59 2.73 1.41 3.74.82.99 1.9 1.72 3.22 2.22 1.33.48 2.82.73 4.46.73 1.71 0 3.22-.26 4.53-.77 1.29-.51 2.31-1.21 3.04-2.14.75-.9 1.12-1.98 1.13-3.21-.01-1.12-.35-2.05-.99-2.79-.66-.73-1.57-1.34-2.74-1.84-1.17-.49-2.54-.94-4.1-1.33l-4.96-1.25c-3.58-.91-6.42-2.3-8.5-4.15-2.08-1.86-3.11-4.31-3.11-7.39 0-2.53.69-4.75 2.1-6.65 1.39-1.9 3.29-3.38 5.7-4.43 2.42-1.06 5.15-1.58 8.2-1.58 3.09 0 5.8.52 8.14 1.58 2.33 1.05 4.17 2.51 5.5 4.38s2.02 4 2.06 6.42h-7.6zm-40.09-11.8h7.84v30.19c-.01 2.78-.61 5.15-1.79 7.15-1.18 2-2.83 3.52-4.93 4.59-2.1 1.07-4.56 1.61-7.35 1.61-2.55 0-4.84-.46-6.88-1.36-2.04-.9-3.66-2.24-4.84-4.01-1.2-1.78-1.79-3.98-1.79-6.63h7.85c.01 1.16.28 2.16.78 3 .5.84 1.2 1.48 2.08 1.93.9.45 1.94.67 3.1.67 1.26 0 2.33-.26 3.21-.79.87-.52 1.55-1.3 2.01-2.34.46-1.03.7-2.3.71-3.82V59.06zm-30.19 43.41c-1.3 0-2.4-.45-3.32-1.35-.92-.89-1.38-1.98-1.37-3.27-.01-1.25.45-2.32 1.37-3.22.92-.9 2.02-1.35 3.32-1.35 1.25 0 2.34.45 3.26 1.35.93.9 1.4 1.97 1.41 3.22-.01.85-.22 1.63-.66 2.33-.44.71-1 1.26-1.71 1.67-.7.41-1.46.62-2.3.62zm-329-.14L22.11 0H0v103.06h17.69V22.03l65.22 81.07h110.78V86.64H122.2v-27.2h57.49V42.98H122.2V16.5h71.49V.04h-89.18V16.5h.01v85.83zM261.98 73.7l-11.6-14.42-35.37 43.94h23.21l23.76-29.52zM238.22.09h-23.15l82.92 103.05h23.21l-41.46-51.49L321.14.16 297.99.2l-29.84 37.06L238.22.09z"/></svg>
<svg width="512" height="63.478" viewBox="0 0 512 63.478" xmlns="http://www.w3.org/2000/svg"><path d="M52.898 0C38.792 0 29.976 7.053 26.45 21.16c5.29-7.054 11.462-9.699 18.515-7.935 4.024 1.005 6.9 3.926 10.084 7.157 5.186 5.264 11.189 11.357 24.3 11.357 14.106 0 22.922-7.053 26.449-21.16-5.29 7.054-11.462 9.699-18.515 7.935-4.024-1.005-6.9-3.926-10.084-7.157C72.012 6.093 66.01 0 52.898 0zM26.45 31.739c-14.106 0-22.922 7.053-26.449 21.16 5.29-7.054 11.461-9.699 18.514-7.935 4.025 1.007 6.9 3.926 10.084 7.157 5.186 5.264 11.19 11.357 24.3 11.357 14.107 0 22.923-7.053 26.45-21.16-5.29 7.054-11.462 9.699-18.515 7.935-4.024-1.005-6.9-3.926-10.084-7.156-5.186-5.265-11.189-11.358-24.3-11.358z" fill="#38bdf8"/><path d="M158.687 26.747h-9.231v17.868c0 4.765 3.126 4.69 9.231 4.392v7.222c-12.358 1.489-17.272-1.936-17.272-11.614V26.747h-6.85v-7.743h6.85v-10l8.04-2.382v12.382h9.232zm35.192-7.743h8.04V56.23h-8.04v-5.36c-2.83 3.945-7.222 6.328-13.03 6.328-10.124 0-18.537-8.562-18.537-19.58 0-11.093 8.413-19.58 18.538-19.58 5.807 0 10.2 2.382 13.029 6.253zM182.115 49.53c6.7 0 11.764-4.989 11.764-11.912s-5.063-11.912-11.764-11.912-11.763 4.988-11.763 11.912 5.063 11.912 11.763 11.912zm33.205-36.11c-2.83 0-5.137-2.383-5.137-5.138a5.147 5.147 0 0 1 5.137-5.137 5.147 5.147 0 0 1 5.137 5.137c0 2.755-2.308 5.138-5.137 5.138zm-4.02 42.808V19.004h8.04V56.23zm17.346 0V1.881h8.041v54.348zm60.23-37.225h8.487L285.675 56.23h-7.892l-7.743-25.09-7.817 25.09h-7.891l-11.689-37.225h8.487l7.222 25.685 7.817-25.685h7.668l7.743 25.685zm18.464-5.583c-2.83 0-5.137-2.383-5.137-5.138a5.147 5.147 0 0 1 5.137-5.137 5.147 5.147 0 0 1 5.137 5.137c0 2.755-2.308 5.138-5.137 5.138zm-4.02 42.808V19.004h8.04V56.23zm36.926-38.193c8.339 0 14.295 5.659 14.295 15.337v22.856h-8.04V34.192c0-5.658-3.277-8.636-8.34-8.636-5.285 0-9.454 3.127-9.454 10.72V56.23h-8.04V19.004h8.04v4.765c2.457-3.871 6.477-5.733 11.54-5.733zM392.66 4.114h8.04V56.23h-8.04v-5.36c-2.83 3.945-7.222 6.328-13.029 6.328-10.125 0-18.538-8.562-18.538-19.58 0-11.093 8.413-19.58 18.538-19.58 5.807 0 10.2 2.382 13.029 6.253zM380.896 49.53c6.7 0 11.763-4.989 11.763-11.912s-5.063-11.912-11.763-11.912-11.763 4.988-11.763 11.912 5.062 11.912 11.763 11.912zm46.754 7.668c-11.242 0-19.654-8.562-19.654-19.58 0-11.093 8.412-19.58 19.654-19.58 7.296 0 13.625 3.796 16.603 9.603l-6.924 4.02c-1.638-3.498-5.286-5.732-9.753-5.732-6.552 0-11.54 4.988-11.54 11.689s4.988 11.688 11.54 11.688c4.467 0 8.115-2.308 9.902-5.732l6.923 3.945c-3.126 5.882-9.455 9.679-16.75 9.679zm30.003-27.919c0 6.775 20.027 2.68 20.027 16.454 0 7.445-6.477 11.465-14.517 11.465-7.445 0-12.806-3.35-15.188-8.71l6.924-4.021c1.191 3.35 4.169 5.36 8.264 5.36 3.573 0 6.328-1.19 6.328-4.169 0-6.626-20.027-2.903-20.027-16.23 0-6.998 6.03-11.39 13.624-11.39 6.105 0 11.168 2.828 13.773 7.742l-6.774 3.797c-1.34-2.903-3.946-4.244-6.999-4.244-2.903 0-5.435 1.266-5.435 3.946zm34.322 0c0 6.775 20.027 2.68 20.027 16.454 0 7.445-6.477 11.465-14.518 11.465-7.445 0-12.805-3.35-15.188-8.71l6.924-4.021c1.191 3.35 4.17 5.36 8.264 5.36 3.574 0 6.328-1.19 6.328-4.169 0-6.626-20.027-2.903-20.027-16.23 0-6.998 6.03-11.39 13.625-11.39 6.104 0 11.167 2.828 13.773 7.742l-6.775 3.797c-1.34-2.903-3.946-4.244-6.998-4.244-2.904 0-5.435 1.266-5.435 3.946z" fill="#0f172a"/></svg>
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="logo-typescript" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 283.09 69.57">
<g fill="#007ACC">
<path d="M34.98 7.56H20.43v45.07h-5.91V7.56H0V2.21h34.98V7.56z"/>
<path d="M57.94 16.63L41.38 58.39c-2.95 7.45-7.1 11.18-12.45 11.18 -1.5 0-2.75-0.15-3.76-0.46v-5.17c1.24 0.42 2.38 0.63 3.41 0.63 2.91 0 5.09-1.73 6.54-5.2l2.88-6.82L23.94 16.63h6.4l9.74 27.7c0.12 0.35 0.36 1.27 0.74 2.74h0.21c0.12-0.56 0.35-1.45 0.7-2.67l10.23-27.77H57.94z"/>
<path d="M67.37 47.43h-0.14v21.76h-5.77V16.63h5.77v6.33h0.14c2.84-4.78 6.98-7.17 12.45-7.17 4.64 0 8.26 1.61 10.86 4.83 2.6 3.22 3.9 7.54 3.9 12.96 0 6.02-1.46 10.85-4.39 14.47 -2.93 3.62-6.94 5.43-12.02 5.43C73.5 53.47 69.9 51.46 67.37 47.43zM67.23 32.91v5.03c0 2.98 0.97 5.5 2.9 7.58s4.39 3.11 7.37 3.11c3.49 0 6.23-1.34 8.21-4.01 1.98-2.67 2.97-6.39 2.97-11.14 0-4.01-0.93-7.15-2.78-9.42 -1.85-2.27-4.36-3.41-7.52-3.41 -3.35 0-6.05 1.17-8.09 3.5C68.25 26.47 67.23 29.39 67.23 32.91z"/>
<path d="M129.56 36.07h-25.42c0.09 4.01 1.17 7.1 3.23 9.28 2.06 2.18 4.9 3.27 8.51 3.27 4.05 0 7.78-1.34 11.18-4.01v5.41c-3.16 2.3-7.35 3.45-12.55 3.45 -5.09 0-9.08-1.63-11.99-4.9 -2.91-3.27-4.36-7.87-4.36-13.8 0-5.6 1.59-10.17 4.76-13.69 3.18-3.53 7.12-5.29 11.83-5.29s8.35 1.52 10.93 4.57c2.58 3.05 3.87 7.28 3.87 12.69V36.07zM123.65 31.18c-0.02-3.33-0.83-5.92-2.41-7.77 -1.58-1.85-3.78-2.78-6.59-2.78 -2.72 0-5.03 0.97-6.93 2.92 -1.9 1.95-3.07 4.49-3.52 7.63H123.65z"/>
<path d="M134.6 50.59v-6.96c0.73 0.7 1.6 1.34 2.62 1.9 1.02 0.56 2.09 1.04 3.22 1.42s2.26 0.69 3.39 0.9c1.14 0.21 2.19 0.32 3.15 0.32 3.32 0 5.81-0.67 7.45-2.02 1.64-1.35 2.46-3.29 2.46-5.82 0-1.36-0.27-2.54-0.82-3.55 -0.55-1.01-1.3-1.93-2.27-2.76s-2.11-1.63-3.43-2.39c-1.32-0.76-2.74-1.56-4.26-2.41 -1.61-0.89-3.11-1.79-4.5-2.71 -1.39-0.91-2.61-1.92-3.63-3.02 -1.03-1.1-1.84-2.35-2.43-3.74 -0.59-1.39-0.88-3.03-0.88-4.9 0-2.3 0.46-4.29 1.38-5.99 0.92-1.7 2.13-3.1 3.64-4.2 1.5-1.1 3.21-1.92 5.13-2.46 1.92-0.54 3.88-0.81 5.87-0.81 4.55 0 7.86 0.6 9.94 1.79v6.64c-2.72-2.06-6.22-3.09-10.49-3.09 -1.18 0-2.36 0.14-3.54 0.4 -1.18 0.27-2.23 0.71-3.15 1.32 -0.92 0.61-1.67 1.39-2.25 2.36 -0.58 0.96-0.87 2.13-0.87 3.52 0 1.29 0.22 2.4 0.66 3.34 0.44 0.94 1.09 1.79 1.95 2.57 0.86 0.77 1.9 1.52 3.14 2.25 1.23 0.73 2.65 1.52 4.26 2.39 1.65 0.89 3.22 1.83 4.7 2.81s2.78 2.07 3.89 3.27c1.11 1.2 2 2.52 2.65 3.97 0.65 1.45 0.98 3.12 0.98 4.99 0 2.48-0.45 4.59-1.33 6.31 -0.89 1.72-2.09 3.12-3.6 4.2 -1.51 1.08-3.25 1.86-5.23 2.34 -1.97 0.48-4.05 0.72-6.24 0.72 -0.73 0-1.63-0.06-2.7-0.19s-2.17-0.32-3.28-0.56c-1.12-0.25-2.17-0.55-3.17-0.91C136 51.44 135.21 51.03 134.6 50.59z"/>
<path d="M193.25 50.98c-2.77 1.66-6.05 2.5-9.84 2.5 -5.13 0-9.28-1.67-12.43-5.01s-4.73-7.67-4.73-12.99c0-5.93 1.7-10.69 5.1-14.29 3.4-3.6 7.93-5.4 13.61-5.4 3.16 0 5.95 0.59 8.37 1.76v5.91c-2.67-1.88-5.53-2.81-8.58-2.81 -3.68 0-6.7 1.32-9.05 3.96s-3.53 6.1-3.53 10.39c0 4.22 1.11 7.55 3.32 9.98s5.19 3.66 8.91 3.66c3.14 0 6.09-1.04 8.86-3.13V50.98z"/>
<path d="M215.56 22.46c-1.01-0.77-2.46-1.16-4.36-1.16 -2.46 0-4.52 1.16-6.17 3.48s-2.48 5.48-2.48 9.49v18.35h-5.77v-36h5.77v7.42h0.14c0.82-2.53 2.07-4.51 3.76-5.92 1.69-1.42 3.57-2.13 5.66-2.13 1.5 0 2.65 0.16 3.45 0.49V22.46z"/>
<path d="M222.18 7.49c-1.03 0-1.91-0.35-2.64-1.05s-1.09-1.59-1.09-2.67c0-1.08 0.36-1.97 1.09-2.69 0.73-0.71 1.61-1.07 2.64-1.07 1.05 0 1.95 0.36 2.69 1.07 0.74 0.72 1.11 1.61 1.11 2.69 0 1.03-0.37 1.91-1.11 2.64C224.13 7.12 223.23 7.49 222.18 7.49zM224.99 52.63h-5.77v-36h5.77V52.63z"/>
<path d="M234.29 47.43h-0.14v21.76h-5.77V16.63h5.77v6.33h0.14c2.84-4.78 6.98-7.17 12.45-7.17 4.64 0 8.26 1.61 10.86 4.83 2.6 3.22 3.9 7.54 3.9 12.96 0 6.02-1.46 10.85-4.39 14.47s-6.94 5.43-12.02 5.43C240.42 53.47 236.82 51.46 234.29 47.43zM234.15 32.91v5.03c0 2.98 0.97 5.5 2.9 7.58s4.39 3.11 7.37 3.11c3.49 0 6.23-1.34 8.21-4.01s2.97-6.39 2.97-11.14c0-4.01-0.93-7.15-2.78-9.42 -1.85-2.27-4.36-3.41-7.52-3.41 -3.35 0-6.05 1.17-8.09 3.5C235.17 26.47 234.15 29.39 234.15 32.91z"/>
<path d="M283.09 52.28c-1.36 0.75-3.15 1.12-5.38 1.12 -6.3 0-9.46-3.52-9.46-10.55v-21.3h-6.19v-4.92h6.19V7.84l5.77-1.86v10.65h9.07v4.92h-9.07v20.28c0 2.41 0.41 4.14 1.23 5.17s2.18 1.55 4.08 1.55c1.45 0 2.71-0.4 3.76-1.2V52.28z"/>
</g>
</svg>
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: 'Ivy Mode';
src: url('./fonts/ivy-mode-light.woff2') format('woff2');
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: 'Ivy Mode';
src: url('./fonts/ivy-mode-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Ivy Mode';
src: url('./fonts/ivy-mode-semi-bold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
html {
scroll-behavior: smooth;
}
.no-scrollbar {
overflow-x: auto;
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.no-scrollbar::-webkit-scrollbar {
display: none;
/* Chrome, Safari, and Edge */
}
import { heroui } from '@heroui/react';
import colors from './theme/colors';
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./theme/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}'
],
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
serif: ['Ivy Mode', 'serif']
}
}
},
darkMode: 'class',
plugins: [
heroui({
themes: {
light: colors.light,
dark: colors.dark
}
})
]
};
export default config;
import React from 'react';
import { Meta } from '@storybook/react';
import { parseToRgba, readableColor } from 'color2k';
type ColorsItem = {
color: string;
className?: string;
textClassName?: string;
};
type SwatchColors = {
title: string;
items: ColorsItem[];
};
type SwatchSetProps = {
colors: SwatchColors[];
isSemantic?: boolean;
};
const Swatch = ({ color }: { color: string }) => {
const colorText = color
? `#${parseToRgba(color)
.slice(0, 3)
.map((x) => x.toString(16).padStart(2, '0'))
.join('')
.toUpperCase()}`
: 'N/A';
return (
<div
className="flex flex-col items-center justify-center w-28 h-28 m-2 rounded-xl shadow-lg"
style={{
backgroundColor: color
}}>
<span
style={{
color: readableColor(color)
}}>
{colorText}
</span>
</div>
);
};
const SemanticSwatch = ({
color,
className,
textClassName
}: {
color: string;
className?: string;
textClassName?: string;
}) => {
return (
<div
className={`${className} flex flex-col items-center justify-center w-28 h-28 m-2 rounded-xl shadow-lg`}>
<span className={`${textClassName} text-sm`}>{color}</span>
</div>
);
};
const SwatchSet = ({ colors, isSemantic = false }: SwatchSetProps) => (
<div className="flex flex-row flex-wrap items-center justify-center w-full h-full p-2">
{colors.map(({ title, items }) => (
<div key={title} className="flex flex-col items-start w-full h-full">
<h2 className="text-xl font-bold text-foreground">{title}</h2>
<div className="flex flex-row flex-wrap items-center justify-start w-full h-full p-4">
{items.map((c, index) =>
isSemantic ? (
<SemanticSwatch
key={`${c.color}-${index}`}
className={c.className}
color={c.color}
textClassName={c.textClassName}
/>
) : (
<Swatch key={`${c.color}-${index}`} color={c.color} />
)
)}
</div>
</div>
))}
</div>
);
export default {
title: 'Foundations/SemanticColors',
component: SwatchSet,
argTypes: {
isSemantic: {
control: false
}
}
} as Meta<typeof SwatchSet>;
export const SemanticColors = {
args: {
isSemantic: true,
colors: [
{
title: 'Layout',
items: [
{
color: 'background',
className: 'bg-background',
textClassName: 'text-foreground'
},
{
color: 'foreground',
className: 'bg-foreground',
textClassName: 'text-background'
},
{
color: 'divider',
className: 'bg-divider',
textClassName: 'text-foreground'
},
{
color: 'focus',
className: 'bg-focus',
textClassName: 'text-primary-foreground'
}
]
},
{
title: 'Content',
items: [
{
color: 'content1',
className: 'bg-content1',
textClassName: 'text-content1-foreground'
},
{
color: 'content2',
className: 'bg-content2',
textClassName: 'text-content2-foreground'
},
{
color: 'content3',
className: 'bg-content3',
textClassName: 'text-content3-foreground'
},
{
color: 'content4',
className: 'bg-content4',
textClassName: 'text-content4-foreground'
}
]
},
{
title: 'Base',
items: [
{
color: 'default',
className: 'bg-default',
textClassName: 'text-default-foreground'
},
{
color: 'primary',
className: 'bg-primary',
textClassName: 'text-primary-foreground'
},
{
color: 'secondary',
className: 'bg-secondary',
textClassName: 'text-secondary-foreground'
},
{
color: 'success',
className: 'bg-success',
textClassName: 'text-success-foreground'
},
{
color: 'warning',
className: 'bg-warning',
textClassName: 'text-warning-foreground'
},
{
color: 'danger',
className: 'bg-danger',
textClassName: 'text-danger-foreground'
}
]
},
{
title: 'Default',
items: [
{
color: 'default-50',
className: 'bg-default-50',
textClassName: 'text-default-900'
},
{
color: 'default-100',
className: 'bg-default-100',
textClassName: 'text-default-900'
},
{
color: 'default-200',
className: 'bg-default-200',
textClassName: 'text-default-800'
},
{
color: 'default-300',
className: 'bg-default-300',
textClassName: 'text-default-800'
},
{
color: 'default-400',
className: 'bg-default-400',
textClassName: 'text-default-800'
},
{
color: 'default-500',
className: 'bg-default-500',
textClassName: 'text-default-foreground'
},
{
color: 'default-600',
className: 'bg-default-600',
textClassName: 'text-default-50'
},
{
color: 'default-700',
className: 'bg-default-700',
textClassName: 'text-default-100'
},
{
color: 'default-800',
className: 'bg-default-800',
textClassName: 'text-default-100'
},
{
color: 'default-900',
className: 'bg-default-900',
textClassName: 'text-default-100'
}
]
},
{
title: 'Primary',
items: [
{
color: 'primary-50',
className: 'bg-primary-50',
textClassName: 'text-primary-900'
},
{
color: 'primary-100',
className: 'bg-primary-100',
textClassName: 'text-primary-900'
},
{
color: 'primary-200',
className: 'bg-primary-200',
textClassName: 'text-primary-800'
},
{
color: 'primary-300',
className: 'bg-primary-300',
textClassName: 'text-primary-800'
},
{
color: 'primary-400',
className: 'bg-primary-400',
textClassName: 'text-primary-800'
},
{
color: 'primary-500',
className: 'bg-primary-500',
textClassName: 'text-primary-foreground'
},
{
color: 'primary-600',
className: 'bg-primary-600',
textClassName: 'text-primary-50'
},
{
color: 'primary-700',
className: 'bg-primary-700',
textClassName: 'text-primary-100'
},
{
color: 'primary-800',
className: 'bg-primary-800',
textClassName: 'text-primary-100'
},
{
color: 'primary-900',
className: 'bg-primary-900',
textClassName: 'text-primary-100'
}
]
},
{
title: 'Secondary',
items: [
{
color: 'secondary-50',
className: 'bg-secondary-50',
textClassName: 'text-secondary-900'
},
{
color: 'secondary-100',
className: 'bg-secondary-100',
textClassName: 'text-secondary-900'
},
{
color: 'secondary-200',
className: 'bg-secondary-200',
textClassName: 'text-secondary-800'
},
{
color: 'secondary-300',
className: 'bg-secondary-300',
textClassName: 'text-secondary-800'
},
{
color: 'secondary-400',
className: 'bg-secondary-400',
textClassName: 'text-secondary-800'
},
{
color: 'secondary-500',
className: 'bg-secondary-500',
textClassName: 'text-secondary-foreground'
},
{
color: 'secondary-600',
className: 'bg-secondary-600',
textClassName: 'text-secondary-50'
},
{
color: 'secondary-700',
className: 'bg-secondary-700',
textClassName: 'text-secondary-100'
},
{
color: 'secondary-800',
className: 'bg-secondary-800',
textClassName: 'text-secondary-100'
},
{
color: 'secondary-900',
className: 'bg-secondary-900',
textClassName: 'text-secondary-100'
}
]
},
{
title: 'Success',
items: [
{
color: 'success-50',
className: 'bg-success-50',
textClassName: 'text-success-900'
},
{
color: 'success-100',
className: 'bg-success-100',
textClassName: 'text-success-900'
},
{
color: 'success-200',
className: 'bg-success-200',
textClassName: 'text-success-800'
},
{
color: 'success-300',
className: 'bg-success-300',
textClassName: 'text-success-800'
},
{
color: 'success-400',
className: 'bg-success-400',
textClassName: 'text-success-800'
},
{
color: 'success-500',
className: 'bg-success-500',
textClassName: 'text-success-foreground'
},
{
color: 'success-600',
className: 'bg-success-600',
textClassName: 'text-success-50'
},
{
color: 'success-700',
className: 'bg-success-700',
textClassName: 'text-success-100'
},
{
color: 'success-800',
className: 'bg-success-800',
textClassName: 'text-success-100'
},
{
color: 'success-900',
className: 'bg-success-900',
textClassName: 'text-success-100'
}
]
},
{
title: 'Warning',
items: [
{
color: 'warning-50',
className: 'bg-warning-50',
textClassName: 'text-warning-900'
},
{
color: 'warning-100',
className: 'bg-warning-100',
textClassName: 'text-warning-900'
},
{
color: 'warning-200',
className: 'bg-warning-200',
textClassName: 'text-warning-800'
},
{
color: 'warning-300',
className: 'bg-warning-300',
textClassName: 'text-warning-800'
},
{
color: 'warning-400',
className: 'bg-warning-400',
textClassName: 'text-warning-800'
},
{
color: 'warning-500',
className: 'bg-warning-500',
textClassName: 'text-warning-foreground'
},
{
color: 'warning-600',
className: 'bg-warning-600',
textClassName: 'text-warning-50'
},
{
color: 'warning-700',
className: 'bg-warning-700',
textClassName: 'text-warning-100'
},
{
color: 'warning-800',
className: 'bg-warning-800',
textClassName: 'text-warning-100'
},
{
color: 'warning-900',
className: 'bg-warning-900',
textClassName: 'text-warning-100'
}
]
},
{
title: 'Danger',
items: [
{
color: 'danger-50',
className: 'bg-danger-50',
textClassName: 'text-danger-900'
},
{
color: 'danger-100',
className: 'bg-danger-100',
textClassName: 'text-danger-900'
},
{
color: 'danger-200',
className: 'bg-danger-200',
textClassName: 'text-danger-800'
},
{
color: 'danger-300',
className: 'bg-danger-300',
textClassName: 'text-danger-800'
},
{
color: 'danger-400',
className: 'bg-danger-400',
textClassName: 'text-danger-800'
},
{
color: 'danger-500',
className: 'bg-danger-500',
textClassName: 'text-danger-foreground'
},
{
color: 'danger-600',
className: 'bg-danger-600',
textClassName: 'text-danger-50'
},
{
color: 'danger-700',
className: 'bg-danger-700',
textClassName: 'text-danger-100'
},
{
color: 'danger-800',
className: 'bg-danger-800',
textClassName: 'text-danger-100'
},
{
color: 'danger-900',
className: 'bg-danger-900',
textClassName: 'text-danger-100'
}
]
},
{
title: 'darkBlue',
items: [
{
color: 'darkBlue-50',
className: 'bg-darkBlue-50',
textClassName: 'text-darkBlue-900'
},
{
color: 'darkBlue-100',
className: 'bg-darkBlue-100',
textClassName: 'text-darkBlue-900'
},
{
color: 'darkBlue-200',
className: 'bg-darkBlue-200',
textClassName: 'text-darkBlue-800'
},
{
color: 'darkBlue-300',
className: 'bg-darkBlue-300',
textClassName: 'text-darkBlue-800'
},
{
color: 'darkBlue-400',
className: 'bg-darkBlue-400',
textClassName: 'text-darkBlue-800'
},
{
color: 'darkBlue-500',
className: 'bg-darkBlue-500',
textClassName: 'text-darkBlue-foreground'
},
{
color: 'darkBlue-600',
className: 'bg-darkBlue-600',
textClassName: 'text-darkBlue-50'
},
{
color: 'darkBlue-700',
className: 'bg-darkBlue-700',
textClassName: 'text-darkBlue-100'
},
{
color: 'darkBlue-800',
className: 'bg-darkBlue-800',
textClassName: 'text-darkBlue-100'
},
{
color: 'darkBlue-900',
className: 'bg-darkBlue-900',
textClassName: 'text-darkBlue-100'
}
]
}
]
}
};
export default {
light: {
colors: {
default: {
50: '#F0F0F0',
100: '#E3E3E3',
200: '#C7C7C7',
300: '#ABABAB',
400: '#8F8F8F',
500: '#707070',
600: '#545454',
700: '#383838',
800: '#1C1C1C',
900: '#000000'
},
primary: {
'50': '#efeffb',
'100': '#ced0e3',
'200': '#afb1cf',
'300': '#8e92ba',
'400': '#6f73a7',
'500': '#55598e',
'600': '#42466f',
'700': '#2f324f',
'800': '#1c1e31',
'900': '#080a15',
foreground: '#ffffff',
DEFAULT: '#1c1e31'
},
secondary: {
'50': '#f2e7ff',
'100': '#d3bcf9',
'200': '#b490f0',
'300': '#9665e8',
'400': '#7839e0',
'500': '#5e1fc6',
'600': '#49179b',
'700': '#341070',
'800': '#1f0845',
'900': '#0c011c',
foreground: '#ffffff',
DEFAULT: '#7839e0'
}
}
},
dark: {
colors: {
default: {
900: '#E3E3E3',
800: '#C7C7C7',
700: '#ABABAB',
600: '#8F8F8F',
500: '#707070',
400: '#545454',
300: '#383838',
200: '#1C1C1C',
100: '#09090e',
50: '#000000'
},
primary: {
'50': '#efeffb',
'100': '#ced0e3',
'200': '#afb1cf',
'300': '#8e92ba',
'400': '#6f73a7',
'500': '#55598e',
'600': '#42466f',
'700': '#2f324f',
'800': '#1c1e31',
'900': '#080a15',
foreground: '#ffffff',
DEFAULT: '#1c1e31'
},
secondary: {
'50': '#f2e7ff',
'100': '#d3bcf9',
'200': '#b490f0',
'300': '#9665e8',
'400': '#7839e0',
'500': '#5e1fc6',
'600': '#49179b',
'700': '#341070',
'800': '#1f0845',
'900': '#0c011c',
foreground: '#ffffff',
DEFAULT: '#1c1e31'
}
}
}
};
export default {
title: 'Foundations/Typography'
};
export const Typography = () => (
<div className="container">
<div className="flex flex-col gap-4 mb-5">
<div className="text-9xl font-bold">Heading</div>
<div className="text-8xl font-bold">Heading</div>
<div className="text-7xl font-bold">Heading</div>
<div className="text-6xl font-bold">Heading</div>
<div className="text-5xl font-bold">Heading</div>
<div className="text-4xl font-bold">Heading</div>
<div className="text-3xl font-bold">Heading</div>
<div className="text-2xl font-bold">Heading</div>
<div className="text-xl font-bold">Heading</div>
</div>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo et quae
consequuntur voluptatum quibusdam, autem velit quidem laborum, dignissimos
doloremque ullam eos fugit repellendus maiores eveniet repellat dolor eius
perspiciatis? Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
<p>
Quasi aliquam impedit magnam tempora doloribus voluptatibus, at ea dolores
facilis et quod hic, cumque repellendus quidem expedita explicabo
architecto, possimus minima!
</p>
</div>
);
{
"compilerOptions": {
"target": "es5",
"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": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "app/layout.tsx"],
"exclude": ["node_modules"]
}
interface IBanner {
title: string;
description: string;
button: ILink;
image: IDynamicImage;
specifications: {
image: IDynamicImage;
label: string;
value: string;
}[];
labels: {
scrollDown: string;
};
}
interface CounterProps {
icon: IDynamicImage;
label: string;
count: string;
}
interface MapProps {
latitude: number;
longitude: number;
zoom?: number;
}
type IMarkdown = string;
interface IAmenitiesCarousel {
title: string;
description: string;
amenities: IAmenity[];
}
interface IAmenity {
title: string;
description: string;
image: IDynamicImage;
}
interface ISlideProps {
title?: string;
description?: string;
image: IDynamicImage;
}
interface IGallery {
title: string;
description: string;
subtitle: string;
gallery: {
title?: string;
image?: IDynamicImage;
}[];
}
interface IImageCarousel {
slides: ISlideProps[];
}
interface IMasterPlan extends React.HTMLAttributes<HTMLAnchorElement> {
title: string;
description: string;
image: IDynamicImage;
button?: ILink;
}
interface IVideoContent {
title: string;
description: string;
videoSet?: IResponsiveVideoGroup;
imageSet: IResponsiveImageGroup;
}
interface IMapProps {
latitude: number;
longitude: number;
zoom?: number;
}
interface IAddressMap {
title: string;
phone: string;
email: string;
address: IMarkdown;
mapData: IMapProps;
button?: ILink;
directionButton: ILink;
}
interface IFormLabels {
title: string;
firstName: string;
lastName: string;
email: string;
mobile: string;
company: string;
date: string;
session: string;
terms: string;
residence: string;
unitType: string;
unitSize: string;
budget: string;
purpose: string;
clearButtonLabel: string;
submitButtonLabel: string;
errorTitleRequired: string;
errorFirstNameRequired: string;
errorFirstNameInvalid: string;
errorLastNameRequired: string;
errorLastNameInvalid: string;
errorEmailRequired: string;
errorEmailInvalid: string;
errorMobileRequired: string;
errorMobileInvalid: string;
errorCompanyRequired: string;
errorTermsRequired: string;
errorDateRequired: string;
errorSessionRequired: string;
errorUnitTypeRequired: string;
errorPurposeRequired: string;
errorRecaptchaRequired: string;
formSuccessText: string;
formErrorText: string;
}
interface IContactForm {
title?: string;
footerText?: string;
titleOptions: ISelectOption[];
budgetOptions: ISelectOption[];
purposeOptions: ISelectOption[];
unitSizeOptions: ISelectOption[];
unitTypeOptions: ISelectOption[];
labels: IFormLabels;
/*@ignore*/
onSubmit: (values: IContactFormValues) => Promise<IResponse>;
}
type IComponents =
| IMasterPlan
| IVideoContent
| IBanner
| IAddressMap
| IAmenitiesCarousel
| IImageCarousel
| IGallery
| IContactForm;
type IComponent = {
component: string;
isActive: boolean;
} & IComponents;
interface IPageRenderer {
components: IComponent[];
prefix: string;
}
interface ISeo {
metaTitle: string;
metaDescription: string;
keywords?: string;
metaRobots?: string;
metaImage?: IDynamicImage;
}
interface IHeader {
menuItems?: ILink[];
button?: ILink;
}
type IMarkdown = string;
interface IHeader {
menuItems?: ILink[];
button?: ILink;
}
// type IComponents=IBanner
interface ILocale {
locale: string;
}
interface IParams {
locale: string;
}
interface IApiAttributes extends ILocale {}
interface ILink {
label: string;
url: string;
}
interface ISocialLink {
icon: string;
url: string;
label?: string;
}
interface IDynamicImage {
url: string;
width: number;
height: number;
alternativeText: string;
}
interface IDynamicVideo {
url: string;
}
interface IResponsiveImageGroup {
portrait: IDynamicImage;
landscape: IDynamicImage;
square?: IDynamicImage;
}
interface IResponsiveVideoGroup {
portrait: IDynamicVideo;
landscape: IDynamicVideo;
square?: IDynamicVideo;
}
interface ISelectOption {
value: string;
label: string | React.ReactElement;
}
type IApiResponse<T>={
data: T[];
};
interface ISuccessResponse<T>{
success: true;
}
interface IErrorResponse {
success: false;
code?: string;
}
type IResponse<T = Record<string, any>> = ISuccessResponse<T> | IErrorResponse;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment