From 2fb1140d87ebb295cc57ac8836ab5d6859054d13 Mon Sep 17 00:00:00 2001 From: ECWireless Date: Sun, 2 Aug 2026 02:31:33 +0000 Subject: [PATCH 1/2] feat: refresh Valhalla member archive --- AGENTS.md | 2 + app/api/channel/route.ts | 4 +- app/api/files/route.ts | 4 +- app/config.ts | 10 + app/favicon.ico | Bin 25931 -> 0 bytes app/fonts.ts | 39 + app/globals.css | 891 ++++++++++++++++++++ app/icon.svg | 3 + app/layout.tsx | 83 +- app/page.tsx | 563 +++++++++++-- app/shared/Footer.jsx | 24 - app/shared/Header.jsx | 42 +- app/shared/WalletControl.tsx | 129 +++ app/utils/fuzzy.ts | 42 + docs/pr-review-workflow.md | 94 ++- docs/session-workflow.md | 345 ++++---- next.config.js | 9 +- public/brand/crystal.svg | 62 ++ public/brand/full-m800.svg | 13 + public/brand/portal-arch-c.webp | Bin 0 -> 2152124 bytes public/brand/swords.svg | 3 + public/brand/symbol-m500.svg | 3 + public/fonts/MAZIUSREVIEW20.09-Regular.woff | Bin 0 -> 26148 bytes public/fonts/MaziusDisplay-Bold.otf | Bin 0 -> 31848 bytes public/fonts/MaziusDisplay-Extraitalic.otf | Bin 0 -> 28204 bytes sample.env | 4 + 26 files changed, 2019 insertions(+), 350 deletions(-) delete mode 100644 app/favicon.ico create mode 100644 app/fonts.ts create mode 100644 app/globals.css create mode 100644 app/icon.svg delete mode 100644 app/shared/Footer.jsx create mode 100644 app/shared/WalletControl.tsx create mode 100644 app/utils/fuzzy.ts create mode 100644 public/brand/crystal.svg create mode 100644 public/brand/full-m800.svg create mode 100644 public/brand/portal-arch-c.webp create mode 100644 public/brand/swords.svg create mode 100644 public/brand/symbol-m500.svg create mode 100644 public/fonts/MAZIUSREVIEW20.09-Regular.woff create mode 100644 public/fonts/MaziusDisplay-Bold.otf create mode 100644 public/fonts/MaziusDisplay-Extraitalic.otf diff --git a/AGENTS.md b/AGENTS.md index 59f0a3a..31a07f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -61,6 +61,8 @@ These instructions apply to the entire repository. Known environment variable names: - `NEXT_PUBLIC_PROJECT_ID` +- `DEV_ALLOWED_ORIGINS` +- `S3_BUCKET` - `S3_ENDPOINT` - `S3_REGION` - `S3_KEY` diff --git a/app/api/channel/route.ts b/app/api/channel/route.ts index c50312f..eb7b3ac 100644 --- a/app/api/channel/route.ts +++ b/app/api/channel/route.ts @@ -3,7 +3,7 @@ import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { verifyMessage } from "ethers"; import { NextResponse } from "next/server"; -import { s3Client } from "../../config"; +import { getS3Bucket, s3Client } from "../../config"; import { MEMBER_SIGN_MESSAGE, NOT_MEMBER_ERROR, @@ -42,7 +42,7 @@ export async function POST(req: Request) { if (members.includes(address.toLowerCase())) { const bucketParams = { - Bucket: "raid-guild-valhalla", + Bucket: getS3Bucket(), Key: requestBody.key, }; diff --git a/app/api/files/route.ts b/app/api/files/route.ts index 7ea4490..c00c9c2 100644 --- a/app/api/files/route.ts +++ b/app/api/files/route.ts @@ -4,7 +4,7 @@ import { } from "@aws-sdk/client-s3"; import { verifyMessage } from "ethers"; import { NextResponse } from "next/server"; -import { s3Client } from "../../config"; +import { getS3Bucket, s3Client } from "../../config"; import { MEMBER_SIGN_MESSAGE, NOT_MEMBER_ERROR, @@ -14,7 +14,6 @@ import { logServerError, } from "../shared/memberAuth"; -const bucketParams = { Bucket: "raid-guild-valhalla" }; const S3_LIST_PAGE_SIZE = 500; const S3_LIST_MAX_PAGES = 10; const S3_LIST_MAX_FILES = S3_LIST_PAGE_SIZE * S3_LIST_MAX_PAGES; @@ -69,6 +68,7 @@ export async function POST(req: Request) { const members = await fetchMemberAddresses(); if (members.includes(address.toLowerCase())) { + const bucketParams = { Bucket: getS3Bucket() }; const files: ValhallaFile[] = []; let continuationToken: string | undefined; let pagesFetched = 0; diff --git a/app/config.ts b/app/config.ts index 0d89865..d82ea85 100644 --- a/app/config.ts +++ b/app/config.ts @@ -5,6 +5,16 @@ export const CONFIG = { THE_GRAPH_API_KEY: process.env.THE_GRAPH_API_KEY, }; +export function getS3Bucket() { + const bucket = process.env.S3_BUCKET?.trim(); + + if (!bucket) { + throw new Error("S3_BUCKET is not configured."); + } + + return bucket; +} + const hasS3Key = Boolean(process.env.S3_KEY); const hasS3Secret = Boolean(process.env.S3_SECRET); diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/app/fonts.ts b/app/fonts.ts new file mode 100644 index 0000000..d4ca667 --- /dev/null +++ b/app/fonts.ts @@ -0,0 +1,39 @@ +import { EB_Garamond, Ubuntu_Mono } from "next/font/google"; +import localFont from "next/font/local"; + +export const maziusDisplay = localFont({ + src: [ + { + path: "../public/fonts/MAZIUSREVIEW20.09-Regular.woff", + weight: "400", + style: "normal", + }, + { + path: "../public/fonts/MaziusDisplay-Bold.otf", + weight: "700", + style: "normal", + }, + { + path: "../public/fonts/MaziusDisplay-Extraitalic.otf", + weight: "400", + style: "italic", + }, + ], + variable: "--font-display", + display: "swap", +}); + +export const ebGaramond = EB_Garamond({ + subsets: ["latin"], + variable: "--font-body", + weight: ["400", "500", "600", "700"], + style: ["normal", "italic"], + display: "swap", +}); + +export const ubuntuMono = Ubuntu_Mono({ + subsets: ["latin"], + variable: "--font-mono", + weight: ["400", "700"], + display: "swap", +}); diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..eb24e94 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,891 @@ +:root { + color-scheme: light; + --moloch-100: #faeeeb; + --moloch-200: #efc5bb; + --moloch-300: #e39b8b; + --moloch-400: #d25c41; + --moloch-500: #bd482d; + --moloch-600: #8b3521; + --moloch-700: #5c2316; + --moloch-800: #29100a; + --scroll-100: #f9f7e7; + --scroll-200: #ece5ac; + --scroll-300: #dccd6a; + --scroll-400: #d2c141; + --scroll-500: #b5a22c; + --scroll-600: #837820; + --scroll-700: #534a13; + --scroll-800: #211e07; + --neutral-100: #f1efee; + --neutral-200: #d5cecd; + --neutral-300: #b9aeac; + --neutral-400: #9e8e8a; + --neutral-500: #806f6b; + --neutral-600: #645754; + --neutral-700: #433937; + --neutral-800: #221d1c; + --neutral-white: #fafafa; + --neutral-black: #0d0d0d; + --radius: 0.625rem; + --page-width: 80rem; + --page-gutter: clamp(1rem, 4vw, 3rem); +} + +* { + box-sizing: border-box; +} + +html { + min-width: 20rem; + background: var(--scroll-100); + scroll-behavior: smooth; +} + +body { + min-height: 100vh; + margin: 0; + background: var(--scroll-100); + color: var(--moloch-800); + font-family: var(--font-body), Georgia, serif; + font-size: 1rem; + line-height: 1.6; + font-variant: normal; + font-variant-caps: normal; + font-feature-settings: + "smcp" 0, + "c2sc" 0, + "pcap" 0, + "c2pc" 0; + text-rendering: optimizeLegibility; +} + +button, +input, +textarea, +select { + font: inherit; +} + +button, +a { + -webkit-tap-highlight-color: transparent; +} + +button:focus-visible, +a:focus-visible { + outline: 0.125rem solid var(--moloch-500); + outline-offset: 0.25rem; +} + +::selection { + background: var(--moloch-500); + color: var(--scroll-100); +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + white-space: nowrap; +} + +.site-shell { + position: relative; + display: flex; + min-height: 100vh; + flex-direction: column; + background: + radial-gradient(circle at 92% 6%, rgb(189 72 45 / 11%), transparent 28rem), + linear-gradient(rgb(41 16 10 / 2.5%) 1px, transparent 1px), + linear-gradient(90deg, rgb(41 16 10 / 2.5%) 1px, transparent 1px), + var(--scroll-100); + background-size: + auto, + 4rem 4rem, + 4rem 4rem, + auto; +} + +.site-shell::before { + position: absolute; + top: 5rem; + left: 50%; + width: min(calc(100% - (2 * var(--page-gutter))), var(--page-width)); + border-top: 1px solid rgb(41 16 10 / 14%); + content: ""; + transform: translateX(-50%); +} + +.site-content { + z-index: 1; + display: flex; + width: 100%; + flex: 1; +} + +.site-header, +.valhalla-main { + width: min(calc(100% - (2 * var(--page-gutter))), var(--page-width)); + margin-inline: auto; +} + +.site-header { + z-index: 10; + display: flex; + min-height: 5rem; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.brand-home-link { + display: inline-flex; + align-items: center; + gap: 1rem; + color: inherit; + text-decoration: none; +} + +.brand-logo-full { + width: clamp(8.75rem, 16vw, 11rem); + height: auto; +} + +.brand-logo-symbol { + display: none; + width: 2.5rem; + height: auto; +} + +.brand-context { + padding-left: 1rem; + border-left: 1px solid var(--neutral-300); + color: var(--neutral-600); + font-family: var(--font-mono), monospace; + font-size: 0.75rem; + letter-spacing: 0.04em; + line-height: 1.4; +} + +.wallet-control { + display: inline-flex; + min-width: 0; + align-items: center; +} + +.rg-button { + display: inline-flex; + min-height: 3rem; + align-items: center; + justify-content: center; + gap: 0.625rem; + padding: 0.75rem 2rem; + border: 2px solid transparent; + border-radius: var(--radius); + cursor: pointer; + font-family: var(--font-body), Georgia, serif; + font-size: 0.95rem; + font-weight: 700; + letter-spacing: 0.06em; + line-height: 1.2; + text-transform: uppercase; + transition: + background-color 150ms ease, + border-color 150ms ease, + color 150ms ease, + transform 150ms ease; +} + +.rg-button:hover:not(:disabled) { + transform: translateY(-2px); +} + +.rg-button:active:not(:disabled) { + transform: translateY(0); +} + +.rg-button:disabled { + cursor: wait; + opacity: 0.58; +} + +.rg-button--primary { + background: var(--moloch-500); + color: var(--scroll-100); +} + +.rg-button--primary:hover:not(:disabled) { + background: var(--moloch-700); +} + +.rg-button--secondary { + border-color: var(--moloch-800); + background: transparent; + color: var(--moloch-800); +} + +.rg-button--secondary:hover:not(:disabled) { + background: var(--moloch-800); + color: var(--scroll-100); +} + +.rg-button--header { + min-height: 2.5rem; + max-width: 14rem; + padding: 0.5rem 1rem; + overflow: hidden; + font-family: var(--font-mono), monospace; + font-size: 0.75rem; + text-overflow: ellipsis; + text-transform: none; + white-space: nowrap; +} + +.valhalla-main { + display: flex; + flex-direction: column; + justify-content: center; + padding-block: clamp(2rem, 4vw, 4rem); +} + +.hero { + display: grid; + align-items: center; + gap: clamp(2rem, 4vw, 4rem); + grid-template-columns: minmax(0, 1.05fr) minmax(18rem, 0.95fr); +} + +.hero-copy { + position: relative; + z-index: 1; + max-width: 42rem; +} + +.eyebrow { + display: flex; + align-items: center; + gap: 0.75rem; + margin: 0 0 1.25rem; + color: var(--moloch-600); + font-family: var(--font-mono), monospace; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.08em; + line-height: 1.5; + text-transform: uppercase; +} + +.eyebrow::before { + width: 2.25rem; + border-top: 2px solid currentColor; + content: ""; +} + +.hero-title { + max-width: 10ch; + margin: 0; + color: var(--moloch-800); + font-family: var(--font-display), Georgia, serif; + font-size: clamp(4rem, 7vw, 6.5rem); + font-weight: 700; + letter-spacing: -0.03em; + line-height: 0.9; +} + +.hero-title em { + color: var(--moloch-500); + font-weight: 400; +} + +.hero-description { + max-width: 35rem; + margin: 1.5rem 0 0; + color: var(--neutral-700); + font-size: clamp(1.125rem, 2vw, 1.35rem); + line-height: 1.5; +} + +.hero-action { + margin-top: 2rem; +} + +.hero-step { + margin-bottom: 0.75rem; +} + +.hero-art { + position: relative; + min-height: clamp(19rem, 34vw, 29rem); + isolation: isolate; +} + +.hero-art::before { + position: absolute; + z-index: -1; + inset: 8% 4%; + border: 1px solid rgb(189 72 45 / 38%); + border-radius: 50%; + content: ""; +} + +.hero-art-image { + object-fit: contain; + filter: saturate(0.9) contrast(1.03); + mix-blend-mode: multiply; + mask-image: + linear-gradient( + to right, + transparent 0%, + black 13%, + black 87%, + transparent 100% + ), + linear-gradient( + to bottom, + transparent 0%, + black 12%, + black 88%, + transparent 100% + ); + mask-composite: intersect; + -webkit-mask-image: + linear-gradient( + to right, + transparent 0%, + black 13%, + black 87%, + transparent 100% + ), + linear-gradient( + to bottom, + transparent 0%, + black 12%, + black 88%, + transparent 100% + ); + -webkit-mask-composite: source-in; +} + +.access-region { + position: relative; + z-index: 2; + margin-top: clamp(2rem, 5vw, 4rem); +} + +.gate-card { + display: grid; + align-items: center; + gap: 2rem; + padding-block: 1.5rem; + border-block: 1px solid var(--neutral-300); + color: var(--moloch-800); + grid-template-columns: minmax(0, 1fr) auto; +} + +.gate-card--error { + border-color: var(--moloch-400); +} + +.brand-crystal { + width: 2.75rem; + height: 2.75rem; + background: currentColor; + mask: url("/brand/crystal.svg") center / contain no-repeat; + -webkit-mask: url("/brand/crystal.svg") center / contain no-repeat; +} + +.gate-copy { + max-width: 43rem; +} + +.gate-eyebrow { + margin-bottom: 0.65rem; +} + +.gate-title { + display: flex; + align-items: center; + gap: 0.75rem; + margin: 0; + font-family: var(--font-display), Georgia, serif; + font-size: clamp(1.75rem, 3vw, 2.5rem); + font-weight: 700; + letter-spacing: -0.01em; + line-height: 1.15; +} + +.gate-description { + max-width: 40rem; + margin: 0.65rem 0 0; + color: var(--neutral-600); + font-size: 1.05rem; + line-height: 1.55; +} + +.gate-error { + margin: 0.85rem 0 0; + color: var(--moloch-600); + font-size: 0.95rem; + line-height: 1.45; +} + +.gate-action { + display: flex; + min-width: max-content; + justify-content: flex-end; +} + +.loading-mark { + width: 1.5rem; + height: 1.5rem; + flex: 0 0 auto; + border: 2px solid var(--neutral-300); + border-top-color: var(--moloch-400); + border-radius: 50%; + animation: gate-spin 800ms linear infinite; +} + +.alert { + display: flex; + align-items: flex-start; + gap: 0.75rem; + margin-bottom: 1.5rem; + padding: 0.9rem 1rem; + border: 1px solid var(--moloch-300); + border-radius: calc(var(--radius) - 0.15rem); + background: var(--moloch-100); + color: var(--moloch-700); + font-size: 1rem; +} + +.alert::before { + flex: 0 0 auto; + width: 0.55rem; + height: 0.55rem; + margin-top: 0.5rem; + border-radius: 50%; + background: var(--moloch-500); + content: ""; +} + +.archive { + margin-top: clamp(3rem, 7vw, 6rem); +} + +.archive-header { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 2rem; + margin-bottom: 2rem; + padding-bottom: 1.5rem; + border-bottom: 1px solid var(--neutral-300); +} + +.archive-heading-group .eyebrow { + margin-bottom: 0.65rem; +} + +.archive-title { + margin: 0; + font-family: var(--font-display), Georgia, serif; + font-size: clamp(2.5rem, 5vw, 4.25rem); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1; +} + +.archive-count { + flex: 0 0 auto; + color: var(--neutral-600); + font-family: var(--font-mono), monospace; + font-size: 0.75rem; + letter-spacing: 0.04em; +} + +.archive-tools { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; +} + +.archive-search { + display: flex; + width: min(100%, 30rem); + min-height: 2.75rem; + align-items: center; + gap: 0.6rem; + padding-inline: 0.8rem 0.45rem; + border: 1px solid var(--neutral-300); + border-radius: calc(var(--radius) - 0.2rem); + background: rgb(249 247 231 / 76%); + color: var(--neutral-600); + transition: + border-color 150ms ease, + box-shadow 150ms ease; +} + +.archive-search:focus-within { + border-color: var(--moloch-500); + box-shadow: 0 0 0 0.2rem rgb(189 72 45 / 12%); +} + +.archive-search-icon { + width: 1rem; + height: 1rem; + flex: 0 0 auto; +} + +.archive-search input { + width: 100%; + min-width: 0; + padding: 0; + border: 0; + outline: 0; + background: transparent; + color: var(--moloch-800); + font-size: 0.95rem; + line-height: 1.4; +} + +.archive-search input::placeholder { + color: var(--neutral-600); + opacity: 1; +} + +.archive-search input::-webkit-search-cancel-button { + display: none; +} + +.archive-search-clear { + display: grid; + width: 2rem; + height: 2rem; + flex: 0 0 auto; + padding: 0; + place-items: center; + border: 0; + border-radius: 50%; + background: transparent; + color: var(--neutral-600); + cursor: pointer; +} + +.archive-search-clear:hover { + background: var(--moloch-100); + color: var(--moloch-700); +} + +.archive-search-clear svg { + width: 1rem; + height: 1rem; +} + +.archive-search-status { + flex: 0 0 auto; + margin: 0; + color: var(--neutral-600); + font-family: var(--font-mono), monospace; + font-size: 0.7rem; + letter-spacing: 0.03em; +} + +.file-grid { + display: grid; + margin: 0; + padding: 0; + gap: 0.625rem; + grid-template-columns: repeat(3, minmax(0, 1fr)); + list-style: none; +} + +.file-card { + display: grid; + width: 100%; + min-height: 4.25rem; + align-items: center; + gap: 0.75rem; + padding: 0.7rem 0.85rem; + overflow: hidden; + border: 1px solid var(--neutral-300); + border-radius: calc(var(--radius) - 0.2rem); + background: rgb(249 247 231 / 68%); + color: var(--moloch-800); + cursor: pointer; + grid-template-columns: auto minmax(0, 1fr) auto; + text-align: left; + transition: + background-color 160ms ease, + border-color 160ms ease, + color 160ms ease, + transform 160ms ease; +} + +.file-card:hover:not(:disabled) { + border-color: var(--moloch-500); + background: var(--moloch-100); + transform: translateX(0.15rem); +} + +.file-card:disabled { + cursor: wait; + opacity: 0.66; +} + +.file-card-leading { + display: grid; + width: 1.75rem; + height: 1.75rem; + place-items: center; + border-radius: 50%; + background: var(--moloch-100); + color: var(--moloch-600); +} + +.file-card-copy { + min-width: 0; +} + +.file-card-icon, +.file-card-arrow { + width: 1rem; + height: 1rem; + flex: 0 0 auto; +} + +.file-card-spinner { + width: 1rem; + height: 1rem; + border: 2px solid currentColor; + border-right-color: transparent; + border-radius: 50%; + animation: gate-spin 700ms linear infinite; +} + +.file-card-arrow { + color: var(--neutral-500); + transition: transform 160ms ease; +} + +.file-card:hover .file-card-arrow { + color: var(--moloch-600); + transform: translate(0.15rem, -0.15rem); +} + +.file-card-title { + display: block; + width: 100%; + overflow: hidden; + font-size: 0.95rem; + font-weight: 600; + line-height: 1.25; + text-overflow: ellipsis; + white-space: nowrap; +} + +.file-card-path { + display: block; + width: 100%; + overflow: hidden; + color: var(--neutral-600); + font-family: var(--font-mono), monospace; + font-size: 0.62rem; + letter-spacing: 0.02em; + text-overflow: ellipsis; + white-space: nowrap; +} + +.archive-state { + display: flex; + min-height: 16rem; + align-items: center; + justify-content: center; + flex-direction: column; + gap: 0.75rem; + padding: 2rem; + border: 1px dashed var(--neutral-400); + border-radius: var(--radius); + color: var(--neutral-600); + text-align: center; +} + +.archive-state .brand-crystal { + margin-bottom: 0.5rem; + color: var(--moloch-500); +} + +.archive-state-search-icon { + width: 2rem; + height: 2rem; + margin-bottom: 0.5rem; + color: var(--moloch-500); +} + +.archive-state p { + max-width: 34rem; + margin: 0 0 1rem; +} + +.archive-state--error { + border-color: var(--moloch-300); + background: rgb(250 238 235 / 62%); +} + +.archive-state-title { + margin: 0; + color: var(--moloch-800); + font-family: var(--font-display), Georgia, serif; + font-size: clamp(1.75rem, 4vw, 2.5rem); + font-weight: 700; + line-height: 1.2; +} + +@keyframes gate-spin { + to { + transform: rotate(360deg); + } +} + +@media (max-width: 63.999rem) { + .hero { + gap: 2rem; + grid-template-columns: minmax(0, 1fr) minmax(16rem, 0.8fr); + } + + .file-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 47.999rem) { + :root { + --page-gutter: 1rem; + } + + .site-header { + min-height: 4.75rem; + } + + .site-shell { + background-size: + auto, + 2rem 2rem, + 2rem 2rem, + auto; + } + + .site-shell::before { + top: 4.75rem; + } + + .brand-logo-full, + .brand-context { + display: none; + } + + .brand-logo-symbol { + display: block; + } + + .rg-button--header { + max-width: 11rem; + } + + .valhalla-main { + padding-top: 2.25rem; + } + + .hero { + gap: 1.5rem; + grid-template-columns: 1fr; + } + + .hero-title { + font-size: clamp(4rem, 20vw, 6rem); + } + + .hero-description { + margin-top: 1.5rem; + } + + .hero-action { + margin-top: 1.5rem; + } + + .hero-art { + min-height: min(88vw, 28rem); + } + + .hero--connected .hero-art { + display: none; + } + + .access-region { + margin-top: 2rem; + } + + .gate-card { + align-items: start; + grid-template-columns: 1fr; + } + + .gate-action { + width: 100%; + grid-column: auto; + } + + .gate-action .rg-button, + .gate-action .wallet-control, + .gate-action .wallet-control .rg-button { + width: 100%; + } + + .archive-header { + align-items: flex-start; + flex-direction: column; + gap: 1rem; + } + + .archive-tools { + align-items: stretch; + flex-direction: column; + } + + .archive-search { + width: 100%; + } + + .archive-search-status { + padding-inline: 0.15rem; + } + + .file-grid { + grid-template-columns: 1fr; + } + + .file-card { + min-height: 4rem; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + } +} diff --git a/app/icon.svg b/app/icon.svg new file mode 100644 index 0000000..416d709 --- /dev/null +++ b/app/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/layout.tsx b/app/layout.tsx index 41e512e..0766164 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,16 +1,19 @@ "use client"; -import { Titillium_Web } from "next/font/google"; import "@rainbow-me/rainbowkit/styles.css"; -import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit"; +import { + getDefaultConfig, + lightTheme, + RainbowKitProvider, +} from "@rainbow-me/rainbowkit"; import { WagmiProvider } from "wagmi"; import { gnosis } from "wagmi/chains"; import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; -import { Providers } from "./providers"; -import { Flex } from "@chakra-ui/react"; import { Header } from "./shared/Header"; -import { Footer } from "./shared/Footer"; +import { ebGaramond, maziusDisplay, ubuntuMono } from "./fonts"; +import "./globals.css"; + const projectId = process.env.NEXT_PUBLIC_PROJECT_ID; const config = getDefaultConfig({ @@ -22,7 +25,39 @@ const config = getDefaultConfig({ const queryClient = new QueryClient(); -const titillium = Titillium_Web({ subsets: ["latin"], weight: ["400"] }); +const rainbowBaseTheme = lightTheme({ + accentColor: "#bd482d", + accentColorForeground: "#f9f7e7", + borderRadius: "medium", + fontStack: "system", + overlayBlur: "small", +}); + +const raidGuildRainbowTheme = { + ...rainbowBaseTheme, + colors: { + ...rainbowBaseTheme.colors, + actionButtonBorder: "#d5cecd", + actionButtonSecondaryBackground: "#f1efee", + connectButtonBackground: "#bd482d", + connectButtonText: "#f9f7e7", + generalBorder: "#d5cecd", + generalBorderDim: "#ece5ac", + menuItemBackground: "#faeeeb", + modalBackground: "#f9f7e7", + modalBorder: "#d5cecd", + modalText: "#29100a", + modalTextDim: "#645754", + modalTextSecondary: "#645754", + profileAction: "#f1efee", + profileActionHover: "#efc5bb", + profileForeground: "#f9f7e7", + selectedOptionBorder: "#bd482d", + }, + fonts: { + body: "var(--font-body)", + }, +}; export default function RootLayout({ children, @@ -31,29 +66,19 @@ export default function RootLayout({ }) { return ( - - - - - - -
- {children} -