diff --git a/.gitignore b/.gitignore index dd97500e4..8078664c7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ node_modules/ .a11yrc.json *.DS_Store coverage/ +assets/*.js +script.js +style.css \ No newline at end of file diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000..e765a53e3 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +nodejs 18.18.0 + diff --git a/assets/tailwind-output.css b/assets/tailwind-output.css index 55f3a15eb..424333eef 100644 --- a/assets/tailwind-output.css +++ b/assets/tailwind-output.css @@ -592,6 +592,18 @@ video { } } +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + .pointer-events-none { pointer-events: none; } @@ -672,6 +684,14 @@ video { z-index: 850; } +.col-span-1 { + grid-column: span 1 / span 1; +} + +.col-span-4 { + grid-column: span 4 / span 4; +} + .\!my-auto { margin-top: auto !important; margin-bottom: auto !important; @@ -682,6 +702,15 @@ video { margin-bottom: 0.75rem; } +.my-padding-large { + margin-top: 1.5rem; + margin-bottom: 1.5rem; +} + +.mb-12 { + margin-bottom: 3rem; +} + .mb-\[0\.1875rem\] { margin-bottom: 0.1875rem; } @@ -910,14 +939,26 @@ video { resize: both; } +.grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + .flex-row { flex-direction: row; } +.flex-col-reverse { + flex-direction: column-reverse; +} + .flex-wrap { flex-wrap: wrap; } +.items-start { + align-items: flex-start; +} + .items-center { align-items: center; } @@ -930,6 +971,16 @@ video { justify-content: space-between; } +.gap-gap-large { + gap: 1rem; +} + +.space-x-gap-large > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} + .space-y-1 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); @@ -942,6 +993,12 @@ video { margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); } +.space-y-\[0\.3125rem\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.3125rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.3125rem * var(--tw-space-y-reverse)); +} + .self-start { align-self: flex-start; } @@ -1169,6 +1226,11 @@ video { padding-bottom: 0px !important; } +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + .px-4 { padding-left: 1rem; padding-right: 1rem; @@ -1194,6 +1256,11 @@ video { padding-bottom: 1.15625rem; } +.py-margin-web { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + .py-padding-large { padding-top: 1.5rem; padding-bottom: 1.5rem; @@ -1214,6 +1281,10 @@ video { padding-bottom: 0.375rem; } +.pt-margin-web { + padding-top: 2.5rem; +} + .pt-padding-x-large { padding-top: 2.25rem; } @@ -1434,6 +1505,22 @@ video { a-z-a--z0-9: -; } +.site-max-width { + max-width: 1440px; +} + +.default-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 1rem; +} + +@media (min-width: 768px) { + .default-grid { + grid-template-columns: repeat(8, minmax(0, 1fr)); + } +} + .hover\:bg-dark-accent-1-hovered:hover { --tw-bg-opacity: 1; background-color: rgb(253 60 254 / var(--tw-bg-opacity)); @@ -1501,6 +1588,19 @@ video { } @media (min-width: 768px) { + .sm\:col-span-8 { + grid-column: span 8 / span 8; + } + + .sm\:my-0 { + margin-top: 0px; + margin-bottom: 0px; + } + + .sm\:mb-20 { + margin-bottom: 5rem; + } + .sm\:flex { display: flex; } @@ -1509,18 +1609,77 @@ video { display: none; } + .sm\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .sm\:grid-cols-8 { + grid-template-columns: repeat(8, minmax(0, 1fr)); + } + + .sm\:flex-row { + flex-direction: row; + } + + .sm\:items-center { + align-items: center; + } + + .sm\:justify-between { + justify-content: space-between; + } + + .sm\:border-0 { + border-width: 0px; + } + + .sm\:border-t { + border-top-width: 1px; + } + + .sm\:px-0 { + padding-left: 0px; + padding-right: 0px; + } + .sm\:px-\[0\.9375rem\] { padding-left: 0.9375rem; padding-right: 0.9375rem; } + .sm\:px-margin-web { + padding-left: 2.5rem; + padding-right: 2.5rem; + } + + .sm\:py-0 { + padding-top: 0px; + padding-bottom: 0px; + } + .sm\:py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; } + + .sm\:pb-margin-web { + padding-bottom: 2.5rem; + } + + .sm\:pt-padding-large { + padding-top: 1.5rem; + } } @media (min-width: 1280px) { + .md\:col-span-4 { + grid-column: span 4 / span 4; + } + + .md\:mb-0 { + margin-bottom: 0px; + } + .md\:block { display: block; } @@ -1619,6 +1778,11 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity)); } +.group:hover .group-hover\:dark\:text-dark-neutral-1:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + .dark\:data-\[active\]\:bg-dark-surface-3[data-active]:where(.dark, .dark *) { background-color: rgba(255,255,255,0.12); } diff --git a/src/context/uiProvider.tsx b/src/context/uiProvider.tsx index af7c73f7a..c90df43c7 100644 --- a/src/context/uiProvider.tsx +++ b/src/context/uiProvider.tsx @@ -5,9 +5,9 @@ import React, { useState, useContext, useEffect, -} from "react"; +} from 'react'; -import { ThemeManager, Theme } from "../utils/storage"; +import { ThemeManager, Theme } from '../utils/storage'; type UIProviderProps = { theme: Theme; @@ -20,21 +20,21 @@ export const useUIProvider = () => { const context = useContext(UIContext); if (context === undefined) { - throw new Error("useUIProvider must be used within a UIProvider"); + throw new Error('useUIProvider must be used within a UIProvider'); } return context; }; -export const UIProvider: FC> = ({ children }) => { +export const UIProvider: FC<{ children: React.ReactNode }> = ({ children }) => { const [theme, setTheme] = useState('light'); useEffect(() => { - if (typeof window !== "undefined") { + if (typeof window !== 'undefined') { const currentTheme = ThemeManager.get(); if (!currentTheme) { - ThemeManager.set("light"); + ThemeManager.set('light'); } else { setTheme(currentTheme); } @@ -43,7 +43,7 @@ export const UIProvider: FC> = ({ children }) => { const toggleTheme = () => { setTheme((prev) => { - const newTheme = prev === "dark" ? "light" : "dark"; + const newTheme = prev === 'dark' ? 'light' : 'dark'; ThemeManager.set(newTheme); document.documentElement.classList.toggle('dark', newTheme === 'dark'); // Toggles the dark class return newTheme; diff --git a/src/lib/types.ts b/src/lib/types.ts index 34e775843..80b36053e 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -7,35 +7,35 @@ export type GlobalSettings = { navigationTopics: Tag[] | null; topNavigationApp: { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link } | null; footerLinksTopics: | { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }[] | null; footerLinksEcosystem: | { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }[] | null; footerLinksCompany: | { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }[] | null; footerLinksHelp: | { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }[] | null; footerGithubLink: string | null; @@ -45,14 +45,14 @@ export type GlobalSettings = { connectBlockSupportTitle: string; connectBlockSupportButton: { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }; connectBlockSocialTitle: string; connectBlockSocialButton: { id: string; - key: string | ""; // Label of the link - value: string | ""; // URL of the link + key: string | ''; // Label of the link + value: string | ''; // URL of the link }; connectBlockNewsletterTitle: string; }; @@ -63,3 +63,31 @@ export interface Navigation { title: string; snippet: string; } + +export type Link = { + label: string; + url: string; +}; + +export type FooterPageData = { + footerGithubLink: string | null; + footerXLink: string | null; + footerDiscordLink: string | null; + footerLinksHelp: Link[]; + footerLinksCompany: Link[]; + footerLinksEcosystem: Link[]; +}; + +export type CategoryJSON = { + created_at?: string; + description?: string; + html_url?: string; + id: number; + locale: string; + name: string; + outdated?: boolean; + position?: number; + source_locale?: string; + updated_at?: string; + url?: string; +}; diff --git a/src/modules/footer/Footer.tsx b/src/modules/footer/Footer.tsx new file mode 100644 index 000000000..a568e9e39 --- /dev/null +++ b/src/modules/footer/Footer.tsx @@ -0,0 +1,132 @@ +import { FC } from 'react'; +import { FooterPageData } from '../../lib/types'; + +import { MiniUnicon } from '../../svgs/Logos'; +import { Github, X, Discord } from '../../svgs/Icons'; +import { LinkBase, TextButton } from '../../base/Button'; + +type Props = { + footerPageData: FooterPageData; +}; + +const Footer: FC = ({ footerPageData }) => { + return ( +
+

Footer

+
+
+ + +

+ Uniswap Labs +

+
+
+
+ +
+
+
+

+ @{new Date().getFullYear()} Uniswap Labs +

+
+ {footerPageData?.footerGithubLink ? ( + + + + ) : null} + {footerPageData?.footerXLink ? ( + + + + ) : null} + {footerPageData?.footerDiscordLink ? ( + + + + ) : null} +
+
+
+ ); +}; + +export default Footer; diff --git a/src/modules/footer/index.tsx b/src/modules/footer/index.tsx new file mode 100644 index 000000000..db0a62485 --- /dev/null +++ b/src/modules/footer/index.tsx @@ -0,0 +1 @@ +export { renderFooter } from './renderFooter'; diff --git a/src/modules/footer/renderFooter.tsx b/src/modules/footer/renderFooter.tsx new file mode 100644 index 000000000..c7991eeb6 --- /dev/null +++ b/src/modules/footer/renderFooter.tsx @@ -0,0 +1,18 @@ +import { render } from 'react-dom'; +import { FooterPageData } from '../../lib/types'; +import { Settings } from '../shared'; +import { createTheme, ThemeProviders } from '../shared'; +import Footer from './Footer'; + +export async function renderFooter( + settings: Settings, + footerPageData: FooterPageData, + container: HTMLElement +) { + render( + +