Merge pull request #776 from datopian/feature/website-v0.2.1
Website improvements
66
site/components/Community.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import Container from './Container';
|
||||
import DiscordIcon from './icons/DiscordIcon';
|
||||
import EmailIcon from './icons/EmailIcon';
|
||||
import GitHubIcon from './icons/GitHubIcon';
|
||||
|
||||
import { siteConfig } from '@/config/siteConfig';
|
||||
|
||||
const Stat = ({ title, value, ...props }) => {
|
||||
return (
|
||||
<div {...props}>
|
||||
<span className="text-6xl font-bold text-secondary">{value}</span>
|
||||
<p className="text-lg font-medium">{title}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const IconButton = ({ Icon, text, href, ...props }) => {
|
||||
return (
|
||||
<div {...props}>
|
||||
<a
|
||||
className="rounded border border-secondary px-5 py-3 text-primary dark:text-primary-dark flex items-center hover:bg-secondary hover:text-primary dark:hover:text-primary transition-all duration-200"
|
||||
href={href}
|
||||
>
|
||||
<Icon className="w-6 h-6 mr-2" />
|
||||
{text}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Community() {
|
||||
return (
|
||||
<Container>
|
||||
<h2 className="text-3xl font-bold text-primary dark:text-primary-dark ">
|
||||
Community
|
||||
</h2>
|
||||
<p className="text-lg mt-8 ">
|
||||
We are growing. Get in touch or become a contributor!
|
||||
</p>
|
||||
<div className="flex justify-center mt-12">
|
||||
<Stat title="Stars on GitHub" value="+2k" className="mr-10" />
|
||||
<Stat title="Contributors" value="+70" />
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-center mt-12">
|
||||
<IconButton
|
||||
Icon={GitHubIcon}
|
||||
text="Star Portal.JS on GitHub"
|
||||
className="sm:mr-4 mb-4 w-full sm:w-auto"
|
||||
href={siteConfig.github}
|
||||
/>
|
||||
<IconButton
|
||||
Icon={DiscordIcon}
|
||||
text="Join the Discord server"
|
||||
className="sm:mr-4 mb-4 w-full sm:w-auto"
|
||||
href={siteConfig.discord}
|
||||
/>
|
||||
<IconButton
|
||||
Icon={EmailIcon}
|
||||
text="Subscribe to the Portal.JS newsletter"
|
||||
className="w-full sm:w-auto"
|
||||
href="#hero"
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
7
site/components/Container.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export default function Container({ children }) {
|
||||
return (
|
||||
<div className="lg:max-w-8xl mx-auto px-4 lg:px-8 xl:px-12 mb-32">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import Container from './Container';
|
||||
|
||||
const features: { title: string; description: string; icon: string }[] = [
|
||||
{
|
||||
title: 'Unified sites',
|
||||
@ -37,8 +39,10 @@ const features: { title: string; description: string; icon: string }[] = [
|
||||
|
||||
export default function Features() {
|
||||
return (
|
||||
<div className="lg:max-w-8xl mx-auto px-4 lg:px-8 xl:px-12">
|
||||
<h2 className="text-3xl font-bold">How Portal.JS works?</h2>
|
||||
<Container>
|
||||
<h2 className="text-3xl font-bold text-primary dark:text-primary-dark">
|
||||
How Portal.JS works?
|
||||
</h2>
|
||||
<p className="text-lg mt-8">
|
||||
Portal.JS is built in JavaScript and React on top of the popular Next.js
|
||||
framework, assuming a "decoupled" approach where the frontend is a
|
||||
@ -55,7 +59,7 @@ export default function Features() {
|
||||
<div className="absolute -inset-px rounded-xl border-2 border-transparent opacity-0 [background:linear-gradient(var(--quick-links-hover-bg,theme(colors.sky.50)),var(--quick-links-hover-bg,theme(colors.sky.50)))_padding-box,linear-gradient(to_top,theme(colors.blue.300),theme(colors.blue.400),theme(colors.blue.500))_border-box] group-hover:opacity-100 dark:[--quick-links-hover-bg:theme(colors.slate.800)]" />
|
||||
<div className="relative overflow-hidden rounded-xl p-6">
|
||||
<img src={feature.icon} alt="" className="h-24 w-auto" />
|
||||
<h2 className="mt-4 font-display text-base text-slate-900 dark:text-white">
|
||||
<h2 className="mt-4 font-display text-base text-primary dark:text-primary-dark">
|
||||
<span className="absolute -inset-px rounded-xl" />
|
||||
{feature.title}
|
||||
</h2>
|
||||
@ -66,6 +70,6 @@ export default function Features() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
53
site/components/Gallery.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import Container from './Container';
|
||||
import GalleryItem from './GalleryItem';
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: 'Open Data Northern Ireland',
|
||||
href: 'https://www.opendatani.gov.uk/',
|
||||
image: '/images/showcases/odni.png',
|
||||
description: 'Government Open Data Portal',
|
||||
},
|
||||
{
|
||||
title: 'Birmingham City Observatory',
|
||||
href: 'https://www.cityobservatory.birmingham.gov.uk/',
|
||||
image: '/images/showcases/birmingham.png',
|
||||
description: 'Government Open Data Portal',
|
||||
},
|
||||
{
|
||||
title: 'UAE Open Data',
|
||||
href: 'https://opendata.fcsc.gov.ae/',
|
||||
image: '/images/showcases/uae.png',
|
||||
description: 'Government Open Data Portal',
|
||||
},
|
||||
{
|
||||
title: 'Brazil Open Data',
|
||||
href: 'https://dados.gov.br/',
|
||||
image: '/images/showcases/brazil.png',
|
||||
description: 'Government Open Data Portal',
|
||||
},
|
||||
{
|
||||
title: 'Datahub Open Data',
|
||||
href: 'https://opendata.datahub.io/',
|
||||
image: '/images/showcases/datahub.png',
|
||||
description: 'Demo Data Portal by DataHub',
|
||||
},
|
||||
];
|
||||
|
||||
export default function Gallery() {
|
||||
return (
|
||||
<Container>
|
||||
<h2 className="text-3xl font-bold text-primary dark:text-primary-dark ">
|
||||
Gallery
|
||||
</h2>
|
||||
<p className="text-lg mt-8 ">
|
||||
Discover what's being powered by Portal.JS
|
||||
</p>
|
||||
<div className="not-prose my-12 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{items.map((item) => {
|
||||
return <GalleryItem item={item} />;
|
||||
})}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
24
site/components/GalleryItem.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
export default function GalleryItem({ item }) {
|
||||
return (
|
||||
<a
|
||||
className="rounded overflow-hidden group relative border-1 shadow-lg"
|
||||
target="_blank"
|
||||
href={item.href}
|
||||
>
|
||||
<div
|
||||
className="bg-cover bg-no-repeat bg-top aspect-video w-full group-hover:blur-sm group-hover:scale-105 transition-all duration-200"
|
||||
style={{ backgroundImage: `url(${item.image})` }}
|
||||
>
|
||||
<div className="w-full h-full group-hover:backdrop-brightness-50 transition-all duration-200"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="opacity-0 group-hover:opacity-100 absolute top-0 bottom-0 right-0 left-0 transition-all duration-200 px-2 flex items-center justify-center">
|
||||
<div className="text-center text-primary-dark">
|
||||
<span className="text-xl font-semibold">{item.title}</span>
|
||||
<p className="text-base font-medium">{item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@ -32,7 +32,7 @@ export function Hero() {
|
||||
const el = useRef(null);
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden -mb-32 mt-[-4.5rem] pb-32 pt-[4.5rem] lg:mt-[-4.75rem] lg:pt-[4.75rem]">
|
||||
<div className="overflow-hidden -mb-32 mt-[-4.5rem] pb-32 pt-[4.5rem] lg:mt-[-4.75rem] lg:pt-[4.75rem]" id="hero">
|
||||
<div className="py-16 sm:px-2 lg:relative lg:py-20 lg:px-0">
|
||||
{/* Commented code on line 37, 39 and 113 will reenable the two columns hero */}
|
||||
{/* <div className="mx-auto grid max-w-2xl grid-cols-1 items-center gap-y-16 gap-x-8 px-4 lg:max-w-8xl lg:grid-cols-2 lg:px-8 xl:gap-x-16 xl:px-12"> */}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { siteConfig } from '@/config/siteConfig';
|
||||
import { NextSeo } from 'next-seo';
|
||||
import { useTheme } from 'next-themes';
|
||||
import Link from 'next/link';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@ -58,6 +59,7 @@ export default function Layout({
|
||||
tableOfContents?;
|
||||
}) {
|
||||
// const { toc } = children.props;
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
const currentSection = useTableOfContents(tableOfContents);
|
||||
|
||||
@ -87,17 +89,21 @@ export default function Layout({
|
||||
>
|
||||
Built by{' '}
|
||||
<img
|
||||
src="/datopian-logo.png"
|
||||
src={
|
||||
theme === 'dark'
|
||||
? '/images/datopian-light-logotype.svg'
|
||||
: '/images/datopian-dark-logotype.svg'
|
||||
}
|
||||
alt="Datopian Logo"
|
||||
className="h-6 ml-2"
|
||||
/>
|
||||
</a>
|
||||
</footer>
|
||||
{/** TABLE OF CONTENTS */}
|
||||
{tableOfContents.length > 0 && (siteConfig.tableOfContents) && (
|
||||
{tableOfContents.length > 0 && siteConfig.tableOfContents && (
|
||||
<div className="hidden xl:fixed xl:right-0 xl:top-[4.5rem] xl:block xl:w-1/5 xl:h-[calc(100vh-4.5rem)] xl:flex-none xl:overflow-y-auto xl:py-16 xl:pr-6 xl:mb-16">
|
||||
<nav aria-labelledby="on-this-page-title" className="w-56">
|
||||
<h2 className="font-display text-md font-medium text-slate-900 dark:text-white">
|
||||
<h2 className="font-display text-md font-medium text-primary dark:text-primary-dark">
|
||||
On this page
|
||||
</h2>
|
||||
<ol className="mt-4 space-y-3 text-sm">
|
||||
@ -108,7 +114,7 @@ export default function Layout({
|
||||
href={`#${section.id}`}
|
||||
className={
|
||||
isActive(section)
|
||||
? 'text-sky-500'
|
||||
? 'text-secondary'
|
||||
: 'font-normal text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-300'
|
||||
}
|
||||
>
|
||||
|
||||
@ -11,7 +11,7 @@ export default function MDXPage({ source, frontMatter }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="prose mx-auto prose-a:text-primary dark:prose-a:text-primary-dark prose-strong:text-primary dark:prose-strong:text-primary-dark prose-code:text-primary dark:prose-code:text-primary-dark prose-headings:text-primary dark:prose-headings:text-primary-dark prose text-primary dark:text-primary-dark prose-headings:font-headings dark:prose-invert prose-a:break-words">
|
||||
<div className="prose mx-auto prose-a:text-primary dark:prose-a:text-primary-dark prose-strong:text-primary dark:prose-strong:text-primary-dark prose-headings:text-primary dark:prose-headings:text-primary-dark text-primary dark:text-primary-dark prose-headings:font-headings dark:prose-invert prose-a:break-words">
|
||||
<header>
|
||||
<div className="mb-6">
|
||||
{/* Default layout */}
|
||||
|
||||
@ -29,12 +29,12 @@ export default function NavItem({ item }) {
|
||||
{Object.prototype.hasOwnProperty.call(item, "href") ? (
|
||||
<Link
|
||||
href={item.href}
|
||||
className="text-slate-500 inline-flex items-center mr-2 px-1 pt-1 text-sm font-medium hover:text-slate-600"
|
||||
className="text-slate-600 dark:text-slate-400 inline-flex items-center mr-2 px-1 pt-1 text-sm font-medium hover:text-slate-500"
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
) : (
|
||||
<div className="text-slate-500 inline-flex items-center mr-2 px-1 pt-1 text-sm font-medium hover:text-slate-600 fill-slate-500 hover:fill-slate-600">
|
||||
<div className="text-slate-600 dark:text-slate-400 inline-flex items-center mr-2 px-1 pt-1 text-sm font-medium hover:text-slate-500 fill-slate-500 hover:fill-slate-600">
|
||||
{item.name}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -22,24 +22,7 @@ export default function NewsletterForm() {
|
||||
data-type="subscription"
|
||||
className="mt-3 sm:flex"
|
||||
>
|
||||
<div className="sib-input sib-form-block !p-0 block w-full sm:flex-auto sm:w-32">
|
||||
<div className="form__entry entry_block w-full">
|
||||
<label htmlFor="name" className="sr-only entry__label">
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
id="NAME"
|
||||
name="NAME"
|
||||
type="text"
|
||||
required
|
||||
placeholder="Your name"
|
||||
className="input entry__field !w-full px-2 py-3 text-base rounded-md bg-slate-200 dark:bg-slate-800 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-400 focus:ring-offset-gray-900"
|
||||
/>
|
||||
|
||||
<label className="entry__error entry__error--primary text-red-400 text-sm"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sib-input sib-form-block !p-0 block w-full sm:flex-auto sm:w-64 mt-3 sm:mt-0 sm:ml-3">
|
||||
<div className="sib-input sib-form-block !p-0 block w-full sm:flex-auto sm:w-64 mt-3 sm:mt-0">
|
||||
<div className="form__entry entry_block w-full">
|
||||
<label htmlFor="email" className="sr-only entry__label">
|
||||
Email address
|
||||
@ -79,10 +62,7 @@ export default function NewsletterForm() {
|
||||
<input type="hidden" name="locale" value="en" />
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
id="error-message"
|
||||
className="sib-form-message-panel !border-none"
|
||||
>
|
||||
<div id="error-message" className="sib-form-message-panel !border-none">
|
||||
<div className="sib-form-message-panel__text sib-form-message-panel__text--center !text-red-400 justify-center">
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
|
||||
14
site/components/icons/DiscordIcon.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
export default function DiscordIcon(props) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
{...props}
|
||||
>
|
||||
<path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612Zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
14
site/components/icons/EmailIcon.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
export default function EmailIcon(props) {
|
||||
return (
|
||||
<svg
|
||||
fill="currentColor"
|
||||
viewBox="0 0 2150 2150"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M1920 428.266v1189.54l-464.16-580.146-88.203 70.585 468.679 585.904H83.684l468.679-585.904-88.202-70.585L0 1617.805V428.265l959.944 832.441L1920 428.266ZM1919.932 226v52.627l-959.943 832.44L.045 278.628V226h1919.887Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
7
site/components/icons/GitHubIcon.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export default function GitHubIcon(props) {
|
||||
return (
|
||||
<svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor" {...props}>
|
||||
<path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -19,11 +19,10 @@ const config = {
|
||||
{ name: "Docs", href: "/docs" },
|
||||
{ name: "Components", href: "/docs/components" },
|
||||
{ name: "Learn", href: "/learn" },
|
||||
{ name: "Gallery", href: "/gallery" },
|
||||
{ name: "Data Literate", href: "/data-literate" },
|
||||
{ name: "DL Demo", href: "/data-literate/demo" },
|
||||
{ name: "Excel Viewer", href: "/excel-viewer" },
|
||||
{ name: "GitHub", href: "https://github.com/datopian/portal.js" },
|
||||
// { name: "Gallery", href: "/gallery" },
|
||||
// { name: "Data Literate", href: "/data-literate" },
|
||||
// { name: "DL Demo", href: "/data-literate/demo" },
|
||||
// { name: "Excel Viewer", href: "/excel-viewer" },
|
||||
],
|
||||
footerLinks: [],
|
||||
nextSeo: {
|
||||
|
||||
@ -12,6 +12,7 @@ import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import rehypeSlug from "rehype-slug";
|
||||
import rehypePrismPlus from "rehype-prism-plus";
|
||||
import * as tw from "../tailwind.config";
|
||||
|
||||
import { serialize } from "next-mdx-remote/serialize";
|
||||
|
||||
@ -65,7 +66,7 @@ const parse = async function (source, format, scope) {
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http:www.w3.org/2000/svg",
|
||||
fill: "#ab2b65",
|
||||
fill: tw.theme.extend.colors.secondary.DEFAULT,
|
||||
viewBox: "0 0 20 20",
|
||||
className: "w-5 h-5",
|
||||
},
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import Community from '@/components/Community';
|
||||
import Features from '@/components/Features';
|
||||
import Gallery from '@/components/Gallery';
|
||||
import { Hero } from '@/components/Hero';
|
||||
import { UnstyledLayout } from '@flowershow/core';
|
||||
import Layout from '../components/Layout';
|
||||
@ -10,6 +12,8 @@ export default function Home() {
|
||||
<UnstyledLayout>
|
||||
<Hero />
|
||||
<Features />
|
||||
<Gallery />
|
||||
<Community />
|
||||
</UnstyledLayout>
|
||||
</Layout>
|
||||
</>
|
||||
|
||||
1
site/public/images/datopian-dark-logotype.svg
Normal file
|
After Width: | Height: | Size: 59 KiB |
1
site/public/images/datopian-light-logotype.svg
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
site/public/images/showcases/birmingham.png
Normal file
|
After Width: | Height: | Size: 1004 KiB |
BIN
site/public/images/showcases/brazil.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
site/public/images/showcases/datahub.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
site/public/images/showcases/odni.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
site/public/images/showcases/uae.png
Normal file
|
After Width: | Height: | Size: 421 KiB |
@ -32,12 +32,12 @@ module.exports = {
|
||||
dark: colors.slate[950],
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: colors.gray[700],
|
||||
dark: colors.gray[300],
|
||||
DEFAULT: colors.gray[800],
|
||||
dark: colors.gray[100],
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "",
|
||||
dark: "",
|
||||
DEFAULT: "#60a5fa",
|
||||
dark: "#60a5fa",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||