diff --git a/app/dwosi/components/browser-frame.tsx b/app/dwosi/components/browser-frame.tsx deleted file mode 100644 index cdefa92..0000000 --- a/app/dwosi/components/browser-frame.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { ReactNode } from "react" - -import { cn } from "@/lib/utils" - -/** Minimal browser window used to present real product screenshots consistently. */ -export function BrowserFrame({ url, children, className }: { url?: string; children: ReactNode; className?: string }) { - return ( -
- -
{children}
-
- ) -} diff --git a/app/dwosi/components/contribution-field.tsx b/app/dwosi/components/contribution-field.tsx index f9f79bb..54c1d8c 100644 --- a/app/dwosi/components/contribution-field.tsx +++ b/app/dwosi/components/contribution-field.tsx @@ -8,22 +8,28 @@ import { DWOSI_THEME_ATTR } from "../theme" /** * A living, pixel-art contribution graph drawn on a canvas. Cells "commit" * at random and fade out, and light up under the cursor on precise pointers. - * Quiet behind the content (the `focus` ellipse), pauses when off-screen and - * draws a single static frame for people who prefer reduced motion. + * + * - "background" fills a section behind its content, stays quiet inside the + * `focus` ellipse and fades at the edges. + * - "panel" fills a box like a GitHub contribution graph: seven rows, one per + * day of the week, revealed left to right like time passing. + * + * Pauses when off-screen and draws a single still frame for reduced motion. */ interface ContributionFieldProps { className?: string - /** Quiet area behind the content, as fractions of the canvas size */ + mode?: "background" | "panel" + /** Quiet area behind the content, as fractions of the canvas size (background mode) */ focus?: { x: number; y: number; rx: number; ry: number } - /** Fade the top edge too (the bottom edge always fades) */ + /** Fade the top edge too; the bottom edge always fades (background mode) */ fadeTop?: boolean } -const CELL = 10 -const GAP = 4 -const PITCH = CELL + GAP -const COMMITS_PER_CELL_PER_SECOND = 0.01 +const BACKGROUND_CELL = 10 +const BACKGROUND_GAP = 4 +const PANEL_ROWS = 7 +const PANEL_GAP = 6 const DECAY_SECONDS = 1.4 const FRAME_MS = 1000 / 30 @@ -44,6 +50,7 @@ function seededRandom(seed: number) { export function ContributionField({ className, + mode = "background", focus = { x: 0.5, y: 0.45, rx: 0.34, ry: 0.42 }, fadeTop = false, }: ContributionFieldProps) { @@ -56,14 +63,20 @@ export function ContributionField({ const ctx = canvas?.getContext("2d") if (!canvas || !host || !ctx) return + const panel = mode === "panel" const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches const finePointer = window.matchMedia("(hover: hover) and (pointer: fine)").matches + const commitsPerCellPerSecond = panel ? 0.03 : 0.01 + const roundCells = panel && typeof ctx.roundRect === "function" let width = 0 let height = 0 + let cell = BACKGROUND_CELL + let pitch = BACKGROUND_CELL + BACKGROUND_GAP let cols = 0 let rows = 0 let originX = 0 + let originY = 0 let quiet = new Float32Array(0) let edge = new Float32Array(0) let weight = new Float32Array(0) @@ -81,9 +94,10 @@ export function ContributionField({ const readColors = () => { const root = document.documentElement const styles = getComputedStyle(root) + const light = root.getAttribute(DWOSI_THEME_ATTR) === "light" brandColor = `hsl(${styles.getPropertyValue("--brand").trim()})` emptyColor = `hsl(${styles.getPropertyValue("--foreground").trim()})` - emptyAlpha = root.getAttribute(DWOSI_THEME_ATTR) === "light" ? 0.05 : 0.07 + emptyAlpha = panel ? (light ? 0.08 : 0.1) : light ? 0.05 : 0.07 } const layout = () => { @@ -95,9 +109,22 @@ export function ContributionField({ canvas.height = Math.round(height * dpr) ctx.setTransform(dpr, 0, 0, dpr, 0, 0) - cols = Math.ceil(width / PITCH) - rows = Math.ceil(height / PITCH) - originX = (width - (cols * PITCH - GAP)) / 2 + if (panel) { + cell = Math.max(8, Math.floor((height - PANEL_GAP * (PANEL_ROWS - 1)) / PANEL_ROWS)) + pitch = cell + PANEL_GAP + rows = PANEL_ROWS + cols = Math.max(1, Math.floor((width + PANEL_GAP) / pitch)) + originY = (height - (rows * pitch - PANEL_GAP)) / 2 + originX = (width - (cols * pitch - PANEL_GAP)) / 2 + } else { + cell = BACKGROUND_CELL + pitch = BACKGROUND_CELL + BACKGROUND_GAP + cols = Math.ceil(width / pitch) + rows = Math.ceil(height / pitch) + originY = 0 + originX = (width - (cols * pitch - BACKGROUND_GAP)) / 2 + } + const count = cols * rows quiet = new Float32Array(count) edge = new Float32Array(count) @@ -112,22 +139,40 @@ export function ContributionField({ for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const i = row * cols + col - const x = (originX + col * PITCH + CELL / 2) / width - const y = (row * PITCH + CELL / 2) / height - const distance = Math.hypot((x - focusX) / rx, (y - focusY) / focusRy) - // `quiet` dims cells behind the content, `edge` fades the section edges to nothing - quiet[i] = 0.06 + 0.94 * smoothstep(0.6, 1.25, distance) - edge[i] = smoothstep(1, 0.6, y) * (fadeTop ? smoothstep(0, 0.3, y) : 1) - weight[i] = quiet[i] * edge[i] - - // Resting levels, like a contribution graph: mostly empty, a few busy days const roll = random() - rest[i] = roll > 0.975 ? 0.8 : roll > 0.94 ? 0.55 : roll > 0.88 ? 0.3 : 0 - delay[i] = distance * 0.35 + random() * 0.15 + + if (panel) { + quiet[i] = 1 + edge[i] = 1 + // Busier than a background, like a real summer of contributions + rest[i] = roll > 0.88 ? 0.95 : roll > 0.72 ? 0.7 : roll > 0.52 ? 0.45 : roll > 0.34 ? 0.22 : 0 + delay[i] = (col / cols) * 0.9 + random() * 0.1 + } else { + const x = (originX + col * pitch + cell / 2) / width + const y = (row * pitch + cell / 2) / height + const distance = Math.hypot((x - focusX) / rx, (y - focusY) / focusRy) + // `quiet` dims cells behind the content, `edge` fades the section edges to nothing + quiet[i] = 0.06 + 0.94 * smoothstep(0.6, 1.25, distance) + edge[i] = smoothstep(1, 0.6, y) * (fadeTop ? smoothstep(0, 0.3, y) : 1) + // Resting levels, like a contribution graph: mostly empty, a few busy days + rest[i] = roll > 0.975 ? 0.8 : roll > 0.94 ? 0.55 : roll > 0.88 ? 0.3 : 0 + delay[i] = distance * 0.35 + random() * 0.15 + } + weight[i] = quiet[i] * edge[i] } } } + const fillCell = (x: number, y: number) => { + if (roundCells) { + ctx.beginPath() + ctx.roundRect(x, y, cell, cell, 3) + ctx.fill() + } else { + ctx.fillRect(x, y, cell, cell) + } + } + const draw = (now: number) => { const elapsed = (now - start) / 1000 ctx.clearRect(0, 0, width, height) @@ -148,7 +193,7 @@ export function ContributionField({ ctx.globalAlpha = lit ? (0.15 + 0.75 * level) * (0.25 + 0.75 * quiet[i]) * edge[i] * reveal : emptyAlpha * (0.4 + 0.6 * quiet[i]) * edge[i] * reveal - ctx.fillRect(originX + col * PITCH, row * PITCH, CELL, CELL) + fillCell(originX + col * pitch, originY + row * pitch) } } } @@ -157,7 +202,7 @@ export function ContributionField({ const step = (seconds: number) => { const decay = Math.exp(-seconds / DECAY_SECONDS) - const chance = COMMITS_PER_CELL_PER_SECOND * seconds + const chance = commitsPerCellPerSecond * seconds for (let i = 0; i < heat.length; i++) { heat[i] *= decay if (Math.random() < chance * weight[i]) heat[i] = Math.max(heat[i], 0.5 + Math.random() * 0.5) @@ -174,8 +219,8 @@ export function ContributionField({ const onPointerMove = (event: PointerEvent) => { const rect = canvas.getBoundingClientRect() - const col = Math.floor((event.clientX - rect.left - originX) / PITCH) - const row = Math.floor((event.clientY - rect.top) / PITCH) + const col = Math.floor((event.clientX - rect.left - originX) / pitch) + const row = Math.floor((event.clientY - rect.top - originY) / pitch) for (let dr = -1; dr <= 1; dr++) { for (let dc = -1; dc <= 1; dc++) { const r = row + dr @@ -223,7 +268,7 @@ export function ContributionField({ visibilityObserver.disconnect() host.removeEventListener("pointermove", onPointerMove) } - }, [focusX, focusY, focusRx, focusRy, fadeTop]) + }, [mode, focusX, focusY, focusRx, focusRy, fadeTop]) return ( href.startsWith("http") @@ -64,26 +64,7 @@ export function Cta({ href, children, variant = "primary", arrow = false, classN {children} {arrow && - ) -} - -/** Brand-colored inline link. Arrow points right for in-site links, diagonally for external ones. */ -export function TextLink({ href, children, className }: { href: string; children: ReactNode; className?: string }) { - const external = isExternal(href) - const Icon = external ? ArrowUpRight : ArrowRight - - return ( - - {children} - ) } diff --git a/app/dwosi/components/dsoc-stories.tsx b/app/dwosi/components/dsoc-stories.tsx deleted file mode 100644 index fdb97b3..0000000 --- a/app/dwosi/components/dsoc-stories.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import connectImpactDB from "@/lib/impact-db" -import { getImpactStoryModel } from "@/models/ImpactStory" -import { DWOSI_LINKS } from "../data" -import { TextLink } from "./cta" - -interface DsocStory { - _id: string - name: string - role: string - cohort?: string - content: string - imageUrl?: string -} - -/** Approved, public DSOC stories from the impact-stories admin. Real quotes only. */ -async function getDsocStories(): Promise { - if (!process.env.IMPACT_MONGODB_URI) return [] - - try { - const connection = await connectImpactDB() - const ImpactStory = getImpactStoryModel(connection) - const stories = await ImpactStory.find({ - program: "dsoc", - isApproved: true, - visibility: { $in: ["public", "featured"] }, - }) - .select("name role cohort content imageUrl featuredRank createdAt") - .sort({ featuredRank: 1, createdAt: -1 }) - .limit(3) - .lean() - - return JSON.parse(JSON.stringify(stories)) - } catch (error) { - console.error("Unable to load DSOC stories:", error) - return [] - } -} - -function excerpt(text: string, max = 280) { - const clean = text.replace(/\s+/g, " ").trim() - if (clean.length <= max) return clean - const cut = clean.slice(0, max) - return `${cut.slice(0, cut.lastIndexOf(" ")).replace(/[\s,.;:!?-]+$/, "")}…` -} - -export async function DsocStories() { - const stories = await getDsocStories() - if (stories.length === 0) return null - - return ( -
-
- {stories.map((story) => ( -
-
“{excerpt(story.content)}”
-
- - - {story.name} - - {[story.role, story.cohort].filter(Boolean).join(" · ")} - - -
-
- ))} -
-
- Read more stories -
-
- ) -} diff --git a/app/dwosi/components/dwosi-footer.tsx b/app/dwosi/components/dwosi-footer.tsx index 13c308b..d15354e 100644 --- a/app/dwosi/components/dwosi-footer.tsx +++ b/app/dwosi/components/dwosi-footer.tsx @@ -1,88 +1,31 @@ -import Link from "next/link" - import { DWOSI_LINKS } from "../data" -import { DwosiLogo } from "./dwosi-logo" -const columns = [ - { - title: "Initiative", - links: [ - { label: "Projects", href: "/dwosi#projects" }, - { label: "How it works", href: "/dwosi#how-it-works" }, - { label: "DSOC", href: DWOSI_LINKS.dsoc }, - { label: "FAQ", href: "/dwosi#faq" }, - ], - }, - { - title: "Community", - links: [ - { label: "GitHub", href: DWOSI_LINKS.github }, - { label: "Discord", href: DWOSI_LINKS.discord }, - { label: "LinkedIn", href: DWOSI_LINKS.linkedin }, - { label: "YouTube", href: DWOSI_LINKS.youtube }, - ], - }, - { - title: "Dev Weekends", - links: [ - { label: "Home", href: "/" }, - { label: "Mentorship", href: "/mentorship" }, - { label: "Contact", href: `mailto:${DWOSI_LINKS.email}` }, - ], - }, +const links = [ + { label: "GitHub", href: DWOSI_LINKS.github }, + { label: "Discord", href: DWOSI_LINKS.discord }, + { label: "LinkedIn", href: DWOSI_LINKS.linkedin }, + { label: "YouTube", href: DWOSI_LINKS.youtube }, ] -const linkClass = "dw-touch text-sm text-muted-foreground can-hover:text-foreground" - -function FooterLink({ href, label }: { href: string; label: string }) { - if (href.startsWith("http")) { - return ( - - {label} - - ) - } - if (href.startsWith("mailto:")) { - return ( - - {label} - - ) - } - return ( - - {label} - - ) -} - export function DwosiFooter() { return (
-
-
- -

- The Dev Weekends Open Source Initiative. Real products, built in the open by our community. -

-
- {columns.map((column) => ( -
-

{column.title}

-
    - {column.links.map((link) => ( -
  • - -
  • - ))} -
-
- ))} -
-
-

- © {new Date().getFullYear()} Dev Weekends -

+
+

DWOSI is an initiative of Dev Weekends. Free for contributors.

+
) diff --git a/app/dwosi/components/dwosi-header.tsx b/app/dwosi/components/dwosi-header.tsx index d0ccd06..aea7548 100644 --- a/app/dwosi/components/dwosi-header.tsx +++ b/app/dwosi/components/dwosi-header.tsx @@ -1,5 +1,5 @@ import Link from "next/link" -import { Github, Menu } from "lucide-react" +import { Menu } from "lucide-react" import { Button } from "@/components/ui/button" import { @@ -10,19 +10,19 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { cn } from "@/lib/utils" -import { DWOSI_LINKS, PRIMARY_CTA } from "../data" +import { PRIMARY_CTA } from "../data" import { Cta, iconButtonClass } from "./cta" import { DwosiLogo } from "./dwosi-logo" import { ThemeToggle } from "./theme-toggle" const navItems = [ + { label: "The record", href: "/dwosi#record" }, { label: "Projects", href: "/dwosi#projects" }, - { label: "How it works", href: "/dwosi#how-it-works" }, - { label: "DSOC", href: "/dwosi#dsoc" }, - { label: "FAQ", href: "/dwosi#faq" }, + { label: "Partners", href: "/dwosi#partners" }, + { label: "Hiring", href: "/dwosi#hiring" }, ] -const menuItemClass = "rounded-lg px-3 py-3 transition-none" +const menuItemClass = "rounded-[4px] px-3 py-3 transition-none" export function DwosiHeader() { return ( @@ -30,24 +30,18 @@ export function DwosiHeader() {
- -
- + {PRIMARY_CTA.label} @@ -59,7 +53,7 @@ export function DwosiHeader() { - + {navItems.map((item) => ( {item.label} @@ -67,11 +61,8 @@ export function DwosiHeader() { ))} - {PRIMARY_CTA.label} - - - - GitHub + + {PRIMARY_CTA.label} diff --git a/app/dwosi/components/dwosi-logo.tsx b/app/dwosi/components/dwosi-logo.tsx index 5ed39a7..2d4e97d 100644 --- a/app/dwosi/components/dwosi-logo.tsx +++ b/app/dwosi/components/dwosi-logo.tsx @@ -5,7 +5,7 @@ import { cn } from "@/lib/utils" export function DwosiMark({ className }: { className?: string }) { return ( - DWOSI - by Dev Weekends - + dwosi ) } diff --git a/app/dwosi/components/project-cards.tsx b/app/dwosi/components/project-cards.tsx deleted file mode 100644 index 60147e0..0000000 --- a/app/dwosi/components/project-cards.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import Image from "next/image" -import { Github } from "lucide-react" -import type { LucideIcon } from "lucide-react" - -import { Badge } from "@/components/ui/badge" -import { Card } from "@/components/ui/card" -import { cn } from "@/lib/utils" -import { DWOSI_LINKS, type DwosiProject } from "../data" -import { BrowserFrame } from "./browser-frame" -import { TextLink } from "./cta" - -export function IconTile({ icon: Icon, className }: { icon: LucideIcon; className?: string }) { - return ( - - - ) -} - -function DsocBadge() { - return ( - - DSOC 2026 - - ) -} - -const hostname = (url: string) => new URL(url).hostname.replace(/^www\./, "") - -function ProjectLinks({ project }: { project: DwosiProject }) { - if (!project.websiteUrl && !project.repositoryUrl) { - return ( -

- In development. Ask about it on Discord -

- ) - } - - return ( -
- {project.websiteUrl && Visit {hostname(project.websiteUrl)}} - {project.repositoryUrl && ( - - - )} -
- ) -} - -export function FlagshipCard({ project }: { project: DwosiProject }) { - const Icon = project.icon - - return ( - -
- - {project.screenshot ? ( - {`Screenshot - ) : ( -
-
- )} -
-
-
-
-
-

{project.name}

-

{project.category}

-
- {project.dsoc && } -
-

{project.description}

-
- -
-
-
- ) -} - -export function ProjectCard({ project }: { project: DwosiProject }) { - return ( - -
- - {project.dsoc && } -
-

{project.name}

-

{project.category}

-

{project.description}

-
- -
-
- ) -} diff --git a/app/dwosi/components/section-heading.tsx b/app/dwosi/components/section-heading.tsx index b977c2f..36e0ab9 100644 --- a/app/dwosi/components/section-heading.tsx +++ b/app/dwosi/components/section-heading.tsx @@ -2,28 +2,7 @@ import type { ReactNode } from "react" import { cn } from "@/lib/utils" -interface SectionHeadingProps { - eyebrow: string - title: ReactNode - description?: ReactNode - align?: "center" | "left" - className?: string -} - +/** Orange mono label above section titles */ export function Eyebrow({ children, className }: { children: ReactNode; className?: string }) { - return

{children}

-} - -export function SectionHeading({ eyebrow, title, description, align = "center", className }: SectionHeadingProps) { - const centered = align === "center" - - return ( -
- {eyebrow} -

{title}

- {description && ( -

{description}

- )} -
- ) + return

{children}

} diff --git a/app/dwosi/data.ts b/app/dwosi/data.ts index 10f496b..46a9785 100644 --- a/app/dwosi/data.ts +++ b/app/dwosi/data.ts @@ -1,5 +1,15 @@ -import type { LucideIcon } from "lucide-react" -import { Briefcase, CalendarClock, Cloud, GraduationCap, MonitorPlay, Route } from "lucide-react" +/** Open issues across the public DWOSI repositories (not the website's own issues). */ +const OPEN_ISSUES_QUERY = [ + "is:issue", + "is:open", + "repo:pathment/pathment", + "repo:devweekends/meshly-cloud-core", + "repo:devweekends/meshly-cloud-api", + "repo:devweekends/meshly-cloud-web", + "repo:devweekends/meshly-cloud-desktop", + "repo:devweekends/codehands-desktop", + "repo:devweekends/codehands-contracts", +].join(" ") export const DWOSI_LINKS = { github: "https://github.com/devweekends", @@ -7,175 +17,127 @@ export const DWOSI_LINKS = { linkedin: "https://www.linkedin.com/company/devweekends/", youtube: "https://www.youtube.com/@devweekends", email: "info@devweekends.com", - dsoc: "/dsoc", - dsocProjects: "/dsoc/projects", - impactNumbers: "/our-story#impact", - stories: "/testimonials", + openIssues: `https://github.com/search?type=issues&q=${encodeURIComponent(OPEN_ISSUES_QUERY)}`, } /** The one conversion goal on DWOSI pages. Repeated in the header, hero and closing CTA. */ -export const PRIMARY_CTA = { label: "Start contributing", href: "/dwosi#how-it-works" } +export const PRIMARY_CTA = { label: "View open issues", href: DWOSI_LINKS.openIssues } -export interface DwosiProject { - slug: string - name: string - category: string - description: string - icon: LucideIcon - websiteUrl?: string - repositoryUrl?: string - /** Part of the DSOC 2026 cohort */ - dsoc?: boolean - /** Real screenshot of the product, top of the page, 16:10 or wider */ - screenshot?: string +export interface RecordEntry { + title: string + repo: string + detail: string + status: "merged" | "in review" + url: string } -export const flagshipProjects: DwosiProject[] = [ +/** Real pull requests from DWOSI repositories, as of October 2026. */ +export const record: RecordEntry[] = [ { - slug: "buildment", - name: "Buildment", - category: "Learning", - description: - "An interactive course platform where you learn engineering by building projects, with several project variants per course so every learner's work is their own.", - icon: GraduationCap, + title: "feat(orgs): add workspace logo upload, cropping, and display", + repo: "pathment", + detail: "1 review", + status: "merged", + url: "https://github.com/pathment/pathment/pull/794", }, { - slug: "pathment", - name: "Pathment", - category: "Mentorship", - description: - "A mentorship platform for organizations that run structured, mentor-guided training, with task-based workflows, progress tracking and gamification.", - icon: Route, - websiteUrl: "https://pathment.me/", - repositoryUrl: "https://github.com/Sheryar-Ahmed/pathment", - dsoc: true, - screenshot: "/images/dsoc/pathment.png", + title: "fix: resolve file upload failures in mentee task submissions", + repo: "pathment", + detail: "1 review", + status: "merged", + url: "https://github.com/pathment/pathment/pull/793", + }, + { + title: "feat(gamification): improve XP, coins, and role based badges", + repo: "pathment", + detail: "1 review", + status: "merged", + url: "https://github.com/pathment/pathment/pull/791", }, { - slug: "community-cloud", - name: "Community Cloud", - category: "Infrastructure", - description: - "Contribute spare compute and submit workloads that a shared Kubernetes cluster schedules with Volcano, with monitoring and usage tracking built in.", - icon: Cloud, + title: "fix(community): don't count self-rewards on the contribution leaderboard", + repo: "pathment", + detail: "awaiting review", + status: "in review", + url: "https://github.com/pathment/pathment/pull/804", }, ] -export const moreProjects: DwosiProject[] = [ +/** Published Dev Weekends numbers. Keep in sync with components/home-impact.tsx. */ +export const communityStats = [ + { value: "1,000+", label: "Engineers trained since 2018" }, + { value: "$20K+", label: "Open source stipends" }, + { value: "100+", label: "Remote placements" }, + { value: "20+", label: "Engineers at Turing and Scale AI" }, +] + +export interface Repository { + slug: string + description: string + href?: string + /** Part of the DSOC 2026 cohort */ + dsoc?: boolean +} + +export const repositories: Repository[] = [ { - slug: "inroad", - name: "Inroad", - category: "Careers · AI", - description: - "Finds companies that fit you, researches each one, finds the person who can hire you and drafts a note you send from your own Gmail.", - icon: Briefcase, - websiteUrl: "https://inroad-web.vercel.app/", + // devweekends/Buildment is private for now + slug: "devweekends/buildment", + description: "Learn engineering by building projects, with several variants per course.", }, { - // Built by the CodeHands AI team - slug: "goalslot", - name: "GoalSlot", - category: "Productivity", - description: - "Define goals, block time for them on your calendar, track deep work with a live timer and prove your progress with reports.", - icon: CalendarClock, - websiteUrl: "https://www.goalslot.io/", - repositoryUrl: "https://github.com/ZeeshanAdilButt/goal-slot-web", + slug: "pathment", + description: "Mentor-guided training for organizations, with task workflows and progress tracking.", + href: "https://github.com/pathment/pathment", dsoc: true, }, { - slug: "content-control-platform", - name: "Content Control Platform", - category: "Learning content", - description: - "Video and blog apps on shared infrastructure that guide each learner using their background, goals and what they have already watched or read.", - icon: MonitorPlay, + // Community Cloud, built as Meshly Cloud + slug: "devweekends/meshly-cloud", + description: "Our community cloud: shared Kubernetes from contributed compute, scheduled with Volcano.", + href: "https://github.com/orgs/devweekends/repositories?q=meshly-cloud", }, -] - -export const comparison = { - before: { - label: "Practice projects", - points: [ - "Nobody uses what you build.", - "Nobody reviews your code.", - "Your GitHub fills up with tutorial clones.", - ], - }, - after: { - label: "DWOSI projects", - points: [ - "Your code ships in real products, not throwaway demos.", - "Maintainers review your pull request before it merges.", - "Your profile shows merged work on live products.", - ], - }, -} - -export const steps: { title: string; description: string; link: { label: string; href: string } }[] = [ { - title: "Pick a project", - description: "Choose a product below and get it running locally from its README.", - link: { label: "See the projects", href: "/dwosi#projects" }, + slug: "inroad", + description: "Finds companies that fit you and drafts a note to the person who can hire you.", + href: "https://inroad-web.vercel.app/", }, { - title: "Say hi on Discord", - description: "Introduce yourself and ask a maintainer which issue to start with.", - link: { label: "Join the Discord", href: DWOSI_LINKS.discord }, + slug: "devweekends/codehands", + description: "A local-first coding agent that plans, implements, tests in a sandbox and hands you a change to approve.", + href: "https://github.com/orgs/devweekends/repositories?q=codehands", }, { - title: "Open a pull request", - description: "Push your change, get a review from a maintainer and watch it ship.", - link: { label: "Browse repositories", href: DWOSI_LINKS.github }, + // SafeStream; repository and Slack channel: content-control-platform + slug: "content-control-platform", + description: "SafeStream: ask a question and get the video moments that answer it, filtered by your own rules.", }, ] -/** Published Dev Weekends numbers. Keep in sync with components/home-impact.tsx. */ -export const proofStats = [ - { value: "9", label: "Members selected for Google Summer of Code 2026" }, - { value: "$20K+", label: "Open source stipends earned through GSoC and LFX" }, - { value: "2,800+", label: "Engineers in the Dev Weekends Discord" }, - { value: "1,000+", label: "Engineers trained by Dev Weekends since 2018" }, -] - -export const dsocFacts = [ - { value: "10–12 wks", label: "Coding period" }, - { value: "1:1", label: "Mentorship" }, - { value: "Monthly", label: "Stipend per milestone" }, - { value: "15–20 hrs", label: "Per week" }, -] - -export const faqs = [ - { - question: "Do I need open source experience?", - answer: - "No. You need the basics of the project's stack and a willingness to read code you didn't write. Ask on Discord and the maintainers can suggest an issue that fits your level.", - }, +export const partnerOffers = [ { - question: "Do I need to be in DSOC to contribute?", - answer: - "No. The repositories are public, so you can pick an issue and open a pull request at any time. DSOC adds a dedicated mentor, a structured plan and a stipend.", + title: "Underwrite DSOC cohorts", + description: "Fund monthly stipends tied to delivered milestones in a 10 to 12 week summer cycle.", }, { - question: "Does it cost anything?", - answer: "No. Contributing is free, and DSOC participants are paid a monthly stipend.", + title: "Provide code reviewers", + description: "3 to 5 hours a week from your team to review pull requests and guide contributors 1:1.", }, { - question: "How much time does it take?", - answer: - "Contribute at your own pace. DSOC participants should plan for 15–20 hours a week, and mentors usually spend 3–5 hours a week.", + title: "Host open repositories", + description: "Place an open source project inside DWOSI for steady contributors and maintainer oversight.", }, { - question: "When do DSOC applications open?", - answer: - "DSOC 2026 applications are closed. The next cycle opens next summer, and dates will be announced on the DSOC page and in our Discord.", - }, - { - question: "How do I become a mentor?", - answer: `Email ${DWOSI_LINKS.email} with your experience and the project you would like to mentor. Mentors run weekly check-ins and review pull requests.`, + title: "Hire by pull request", + description: "Hire engineers by reading their merged, maintainer-reviewed work across DWOSI products.", }, +] + +export const hiringSteps = [ + { title: "Tell us the role", description: "Stack, level and location or remote." }, { - question: "Can I propose my own project?", - answer: `Yes. Email ${DWOSI_LINKS.email} with what you want to build and who it is for, and the team will get back to you.`, + title: "Review real contributions", + description: "Merged pull requests and review threads from matching contributors.", }, + { title: "Interview with context", description: "Talk through code you have already read." }, ] diff --git a/app/dwosi/dwosi.css b/app/dwosi/dwosi.css index a0131a3..763ccc2 100644 --- a/app/dwosi/dwosi.css +++ b/app/dwosi/dwosi.css @@ -5,65 +5,75 @@ * own theme. `html:has()` carries the tokens up to , which lets the page * background and portalled content (dropdown menus) use them too. * - * Brand green is reserved for the primary action and links. Everything else - * uses neutrals. + * Dev Weekends orange marks the primary action, links and section labels. + * Everything else uses warm neutrals. * * DWOSI is dark by default and ignores the site-wide theme. The DWOSI toggle * sets html[data-dwosi-theme="light"] (see theme.ts) to switch to light. + * `.dw-light` and `.dw-dark` pin a band or card to one theme either way. */ [data-dwosi], -html:has([data-dwosi]) { - --background: 228 16% 5%; - --foreground: 220 14% 96%; - --card: 228 14% 7.5%; - --card-foreground: 220 14% 96%; - --popover: 228 14% 8%; - --popover-foreground: 220 14% 96%; - --primary: 220 14% 96%; - --primary-foreground: 228 16% 6%; - --secondary: 228 12% 12%; - --secondary-foreground: 220 14% 96%; - --muted: 228 12% 9%; - --muted-foreground: 220 9% 64%; - --accent: 228 12% 13%; - --accent-foreground: 220 14% 96%; +html:has([data-dwosi]), +[data-dwosi] .dw-dark { + --background: 220 6% 7%; + --foreground: 45 14% 94%; + --card: 220 5% 9.5%; + --card-foreground: 45 14% 94%; + --popover: 220 5% 10%; + --popover-foreground: 45 14% 94%; + --primary: 45 14% 94%; + --primary-foreground: 220 6% 7%; + --secondary: 220 4% 13%; + --secondary-foreground: 45 14% 94%; + --muted: 220 5% 10.5%; + --muted-foreground: 40 4% 62%; + --accent: 220 4% 14%; + --accent-foreground: 45 14% 94%; --destructive: 0 72% 51%; --destructive-foreground: 0 0% 100%; - --border: 228 10% 16%; - --input: 228 10% 20%; - --ring: 158 72% 50%; - --radius: 0.75rem; - --brand: 158 72% 50%; - --brand-foreground: 228 16% 6%; - --shadow-color: 0 0% 0%; - - --dw-shadow-sm: 0 1px 2px hsl(var(--shadow-color) / 0.05); - --dw-shadow-md: 0 1px 2px hsl(var(--shadow-color) / 0.04), 0 12px 32px -16px hsl(var(--shadow-color) / 0.18); + --border: 220 4% 16%; + --input: 220 4% 22%; + --ring: 16 100% 60%; + --radius: 0.5rem; + /* Dev Weekends orange, shared with DSOC (#FF6B35) */ + --brand: 16 100% 60%; + --brand-foreground: 220 6% 7%; + /* Deeper orange for buttons and badges so white text passes WCAG AA (4.5:1) */ + --cta: 16 90% 44%; + --cta-foreground: 0 0% 100%; --dw-ease-out: cubic-bezier(0.23, 1, 0.32, 1); } html[data-dwosi-theme="light"]:has([data-dwosi]), -html[data-dwosi-theme="light"] [data-dwosi] { - --background: 0 0% 100%; - --foreground: 224 24% 9%; +html[data-dwosi-theme="light"] [data-dwosi], +[data-dwosi] .dw-light { + --background: 45 14% 94%; + --foreground: 220 6% 7%; --card: 0 0% 100%; - --card-foreground: 224 24% 9%; + --card-foreground: 220 6% 7%; --popover: 0 0% 100%; - --popover-foreground: 224 24% 9%; - --primary: 224 24% 9%; - --primary-foreground: 0 0% 100%; - --secondary: 220 16% 96%; - --secondary-foreground: 224 24% 9%; - --muted: 220 16% 97%; - --muted-foreground: 220 9% 40%; - --accent: 220 16% 95%; - --accent-foreground: 224 24% 9%; - --border: 220 14% 91%; - --input: 220 14% 87%; - --ring: 158 84% 28%; - --brand: 158 84% 28%; + --popover-foreground: 220 6% 7%; + --primary: 220 6% 7%; + --primary-foreground: 45 14% 94%; + --secondary: 45 10% 90%; + --secondary-foreground: 220 6% 7%; + --muted: 45 12% 91%; + --muted-foreground: 40 5% 36%; + --accent: 45 10% 89%; + --accent-foreground: 220 6% 7%; + --border: 40 8% 84%; + --input: 40 8% 78%; + /* Darker orange so links and labels stay readable on the light background */ + --ring: 16 85% 40%; + --brand: 16 85% 40%; --brand-foreground: 0 0% 100%; - --shadow-color: 224 24% 9%; + --cta: 16 85% 40%; + --cta-foreground: 0 0% 100%; +} + +/* Text color is inherited as a computed value, so pinned surfaces set it again */ +[data-dwosi] :is(.dw-light, .dw-dark) { + color: hsl(var(--foreground)); } /* Native controls and scrollbars follow the DWOSI theme, not the site theme */ @@ -83,18 +93,19 @@ html[data-dwosi-theme="light"]:has([data-dwosi]) { /* ---------- Type scale ---------- */ .dw-display { - font-size: clamp(2.5rem, 1.6rem + 3.6vw, 4.5rem); - line-height: 1.08; - letter-spacing: -0.045em; - font-weight: 600; + /* Scales with the viewport so the hero title stays on two lines from tablet up */ + font-size: clamp(2.75rem, 6.2vw, 4.5rem); + line-height: 1.02; + letter-spacing: -0.055em; + font-weight: 650; text-wrap: balance; } .dw-title { - font-size: clamp(1.875rem, 1.5rem + 1.2vw, 2.5rem); - line-height: 1.1; - letter-spacing: -0.035em; - font-weight: 600; + font-size: clamp(2rem, 1.2rem + 2.4vw, 3.25rem); + line-height: 1.05; + letter-spacing: -0.045em; + font-weight: 650; text-wrap: balance; } @@ -123,11 +134,19 @@ html[data-dwosi-theme="light"]:has([data-dwosi]) { line-height: 1.5; } +.dw-wordmark { + font-family: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 0.9375rem; + font-weight: 500; + letter-spacing: -0.01em; +} + .dw-stat { - font-size: clamp(2rem, 1.6rem + 1.2vw, 2.5rem); + font-family: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem); line-height: 1; - letter-spacing: -0.035em; - font-weight: 600; + letter-spacing: -0.02em; + font-weight: 500; font-variant-numeric: tabular-nums; } @@ -139,20 +158,6 @@ html[data-dwosi-theme="light"]:has([data-dwosi]) { -webkit-backdrop-filter: saturate(180%) blur(12px); } -.dw-shadow-sm { - box-shadow: var(--dw-shadow-sm); -} - -.dw-shadow-md { - box-shadow: var(--dw-shadow-md); -} - -/* Thin neutral outline so screenshots never blend into the background */ -.dw-img-outline { - outline: 1px solid hsl(var(--foreground) / 0.08); - outline-offset: -1px; -} - /* ---------- Interaction ---------- */ [data-dwosi] :is(a, button, summary, [tabindex]):focus-visible { @@ -192,10 +197,6 @@ html[data-dwosi-theme="light"]:has([data-dwosi]) { .dw-arrow-link:hover .dw-arrow { transform: translateX(2px); } - - .dw-arrow-link:hover .dw-arrow-diagonal { - transform: translate(1px, -1px); - } } /* ---------- Motion ---------- */ @@ -247,25 +248,6 @@ html[data-dwosi-theme="light"]:has([data-dwosi]) { } } -/* FAQ: content fades in instead of animating height */ -.dw-faq [role="region"] { - animation: none !important; -} - -.dw-faq [role="region"][data-state="open"] > div { - animation: dw-fade-in 200ms var(--dw-ease-out); -} - -.dw-faq button[data-state] > svg { - transition: transform 200ms var(--dw-ease-out); -} - -@keyframes dw-fade-in { - from { - opacity: 0; - } -} - /* Theme toggle shows the icon for the current theme */ .dwosi-icon-light { display: none; diff --git a/app/dwosi/page.tsx b/app/dwosi/page.tsx index 4d2c604..75b0550 100644 --- a/app/dwosi/page.tsx +++ b/app/dwosi/page.tsx @@ -1,33 +1,23 @@ import type { Metadata } from "next" -import { Check, Minus } from "lucide-react" +import { ArrowUpRight, Plus } from "lucide-react" -import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion" -import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { ContributionField } from "./components/contribution-field" -import { Cta, TextLink } from "./components/cta" -import { DsocStories } from "./components/dsoc-stories" -import { DwosiMark } from "./components/dwosi-logo" -import { FlagshipCard, ProjectCard } from "./components/project-cards" -import { Eyebrow, SectionHeading } from "./components/section-heading" +import { Cta } from "./components/cta" +import { Eyebrow } from "./components/section-heading" import { DWOSI_LINKS, PRIMARY_CTA, - comparison, - dsocFacts, - faqs, - flagshipProjects, - moreProjects, - proofStats, - steps, + communityStats, + hiringSteps, + partnerOffers, + record, + repositories, } from "./data" -// DSOC stories come from the impact-stories database -export const revalidate = 3600 - const title = "DWOSI · Dev Weekends Open Source Initiative" const description = - "Contribute to products like Buildment, Pathment and Community Cloud, and get your pull requests reviewed by the engineers who maintain them." + "Where early-career engineers prove their work in public. A free open source initiative where contributors build live products, with every pull request reviewed by product maintainers." export const metadata: Metadata = { title: { absolute: title }, @@ -50,236 +40,236 @@ export const metadata: Metadata = { } const container = "mx-auto max-w-6xl px-4 sm:px-6" -const section = "scroll-mt-16 py-12 sm:py-16" +const section = "scroll-mt-16 border-t py-16 sm:py-24" +const partnerHref = "/dwosi#partners" +const partnerMail = `mailto:${DWOSI_LINKS.email}?subject=DWOSI%20partnership` function Hero() { return ( -
- -
-

- - - DWOSI - · Dev Weekends Open Source Initiative - -

-

Ship real products, not practice projects.

-

- Students and early-career engineers contribute to products like Buildment, Pathment and Community Cloud, - and get their pull requests reviewed by the engineers who maintain them. -

-
- - {PRIMARY_CTA.label} - - - See the projects - +
+
+
+ Dev Weekends Open Source Initiative +

Where early‑career engineers prove their work in public.

+
+

+ A free open source initiative where contributors build live products, from Volcano-scheduled + Kubernetes clusters to AI career tools, with every pull request reviewed by product maintainers. +

+
+ + {PRIMARY_CTA.label} + + + Partner with us + +
+
+
+ +
+
+

contributions to devweekends/* over one summer

+ Example +
+
+ +
) } -function Why() { +function Record() { return ( -
-
- -
-
-

{comparison.before.label}

-
    - {comparison.before.points.map((point) => ( -
  • -
  • - ))} -
-
-
-

{comparison.after.label}

-
    - {comparison.after.points.map((point) => ( -
  • -
  • - ))} -
-
+
+
+
+ The record +

A resume says. A pull request shows.

+

+ Every contribution leaves a public trail: the code, the review conversation, the revisions and the + release it shipped in. +

+
+
+ +

Real pull requests from DWOSI repositories.

) } -function HowItWorks() { +function Community() { return ( -
-
- -
    - {steps.map((step, index) => ( -
  1. - -

    {step.title}

    -

    {step.description}

    - - {step.link.label} - -
  2. +
    +
    +

    From a 30K+ member community

    +
    + {communityStats.map((stat) => ( +
    +
    {stat.label}
    +
    {stat.value}
    +
    ))} -
+
) } -function Projects() { +function Repositories() { + const cellClass = "group flex flex-col gap-2 bg-card p-5 sm:p-6" + return (
- - -
- {flagshipProjects.map((project) => ( - - ))} -
+

Pick a repository

+
+ {repositories.map((repository) => { + const content = ( + <> + + + {repository.slug} + {repository.dsoc && " · DSOC 2026"} + + {repository.href && ( + + {repository.description} + + ) -
-
-

More from DWOSI

-

Earlier-stage products and DSOC projects.

-
- - All DSOC projects - -
- -
= 4 && "lg:grid-cols-4" - )} - > - {moreProjects.map((project) => ( - - ))} + return repository.href ? ( + + {content} + (opens in a new tab) + + ) : ( +
+ {content} +
+ ) + })} + + + your-project + + + Building something the community should own? Propose it for DWOSI. + +
) } -function Proof() { +function Partners() { return ( -
+
- -
- {proofStats.map((stat) => ( -
-
{stat.label}
-
{stat.value}
-
+
+

Partner on code, mentorship and hiring.

+

+ Join current partner Cyberiad Labs in backing public engineering education that produces verifiable, + production-ready contributors. +

+
+
    + {partnerOffers.map((offer, index) => ( +
  1. + +

    {offer.title}

    +

    {offer.description}

    +
  2. ))} -
-
- How we count these numbers + +
+ + Partner at {DWOSI_LINKS.email} +
-
) } -function Dsoc() { +function Hiring() { return ( -
-
-
-
- DSOC · Dev Weekends Summer of Code -

Get a mentor and a stipend with DSOC

-

- DSOC is the mentored summer program inside DWOSI. Selected contributors spend 10–12 weeks building a - DWOSI project with a mentor, with progress reviewed every month. -

-
- - Closed - -

The next cycle opens next summer.

-
- - Explore DSOC - -
-
- {dsocFacts.map((fact) => ( -
-
{fact.label}
-
{fact.value}
-
- ))} -
+
+
+
+ For hiring teams +

+ {/* Non-breaking hyphen keeps "take-home" on one line */} + Skip the take‑home. + Read the history. +

-
-
- ) -} - -function Faq() { - return ( -
-
- - Something else on your mind? Email{" "} - - {DWOSI_LINKS.email} - - . - - } - /> - - {faqs.map((faq) => ( - - {faq.question} - {faq.answer} - +
    + {hiringSteps.map((step, index) => ( +
  1. + + + {step.title} + {step.description} + +
  2. ))} - +
) @@ -287,19 +277,15 @@ function Faq() { function FinalCta() { return ( -
- -
-

Pick a project and open your first pull request.

-

- It's free, the code is public, and maintainers review what you send. -

-
- +
+
+

Your next commit could be on a live product.

+
+ {PRIMARY_CTA.label} - - Join the Discord + + Partner at {DWOSI_LINKS.email}
@@ -311,12 +297,11 @@ export default function DwosiPage() { return ( <> - - - - - - + + + + + ) diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx deleted file mode 100644 index 9e6fb66..0000000 --- a/components/ui/accordion.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client" - -import * as React from "react" -import * as AccordionPrimitive from "@radix-ui/react-accordion" -import { ChevronDown } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Accordion = AccordionPrimitive.Root - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AccordionItem.displayName = "AccordionItem" - -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)) -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName - -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
-
-)) -AccordionContent.displayName = AccordionPrimitive.Content.displayName - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/package-lock.json b/package-lock.json index bdc23e2..7c8e031 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "@next/third-parties": "15.4.0-canary.51", - "@radix-ui/react-accordion": "1.3.1", "@radix-ui/react-checkbox": "1.3.2", "@radix-ui/react-dialog": "1.1.13", "@radix-ui/react-dropdown-menu": "2.1.6", @@ -1205,227 +1204,6 @@ "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", "license": "MIT" }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.3.1.tgz", - "integrity": "sha512-lCZ6sbGS/7WO0j84yx4srIgOf0MRJ/sZ13RonADXxvKBym8xrxNCq5f6DibGcr38sIlwPk8/52uYdXeOPsbEDw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.2.0", - "@radix-ui/react-collapsible": "1.2.1", - "@radix-ui/react-collection": "1.2.0", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.3.0", - "@radix-ui/react-direction": "1.2.0", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-primitive": "2.2.0", - "@radix-ui/react-use-controllable-state": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.2.0.tgz", - "integrity": "sha512-KABY+VMIRPJL+Vyzv/335FEhXXD/xDv8BMb1kl48/aXJZMH0LtHCTx5ga5RnxaEP3nZHtmTLf1P9vanmFX46bw==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.2.0.tgz", - "integrity": "sha512-+yiQzqcc7Sy7/5s0jrMCjpPRFB3538VNrXPWdTLZhE/SCfgEws4aI6lHWN/vvcnyhHndROWBzqmqB4QBrITZ9Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.3.0", - "@radix-ui/react-primitive": "2.2.0", - "@radix-ui/react-slot": "1.5.0", - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", - "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-context": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.3.0.tgz", - "integrity": "sha512-v5AYEocMISkbJ+1fTXzZpiFv7NRr3D2WiYbLIKf+FkmJ8VkP6d503eV2n34MFussHXY1pcoq3yfJiQH77dc4Mg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-direction": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.2.0.tgz", - "integrity": "sha512-FtRA52a/r+LKStFT+neLUm+8vSe7wbzkbQGGeU8ixFiwC8NU14Evoq9ATECqL3eGbcUzJR4fyfA4KkK/q6dfqg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-id": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", - "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.2.0.tgz", - "integrity": "sha512-HCTSPMNqv55Qk0IX4geJbpyXazmqulcimwuyjxTkKi29v+QZbG2Zho9BnbBq4YS2PF+KlNb2CXoLz66uUmblkg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.5.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-slot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.5.0.tgz", - "integrity": "sha512-tyYd9ddPXAysAbdbD9eYxgwpCSv6f3PncqVSNKQFSR5lcJVLz3cb/pANDoYrLiHBpXv7skortyUgGUWsYuPPFQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.3.0.tgz", - "integrity": "sha512-TAcBI7bw2ljYCbv4+zuTSd6zICu8pRt6SDN2vJ/Z06K2MXh6I9WYFe/A9ovlFDtR5HVHGm5iDxDoABm/++dbKg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.2.0", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", - "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", - "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", @@ -1632,207 +1410,6 @@ } } }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.2.1.tgz", - "integrity": "sha512-fSzLb/qy1wuZSxQBcxpW0hNXYHDMWiIXDGyJGdA4+FSLknOWZsNRrTCUavxb4PI8b8lvHo/CysO6NVi5zLpo5g==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.2.0", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.3.0", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-presence": "1.1.11", - "@radix-ui/react-primitive": "2.2.0", - "@radix-ui/react-use-controllable-state": "1.3.0", - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.2.0.tgz", - "integrity": "sha512-KABY+VMIRPJL+Vyzv/335FEhXXD/xDv8BMb1kl48/aXJZMH0LtHCTx5ga5RnxaEP3nZHtmTLf1P9vanmFX46bw==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", - "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-context": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.3.0.tgz", - "integrity": "sha512-v5AYEocMISkbJ+1fTXzZpiFv7NRr3D2WiYbLIKf+FkmJ8VkP6d503eV2n34MFussHXY1pcoq3yfJiQH77dc4Mg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-id": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", - "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.11.tgz", - "integrity": "sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.2.0.tgz", - "integrity": "sha512-HCTSPMNqv55Qk0IX4geJbpyXazmqulcimwuyjxTkKi29v+QZbG2Zho9BnbBq4YS2PF+KlNb2CXoLz66uUmblkg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.5.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-slot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.5.0.tgz", - "integrity": "sha512-tyYd9ddPXAysAbdbD9eYxgwpCSv6f3PncqVSNKQFSR5lcJVLz3cb/pANDoYrLiHBpXv7skortyUgGUWsYuPPFQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.3.0.tgz", - "integrity": "sha512-TAcBI7bw2ljYCbv4+zuTSd6zICu8pRt6SDN2vJ/Z06K2MXh6I9WYFe/A9ovlFDtR5HVHGm5iDxDoABm/++dbKg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.2.0", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", - "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", - "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-collection": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", diff --git a/package.json b/package.json index 74478ee..595547c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ }, "dependencies": { "@next/third-parties": "15.4.0-canary.51", - "@radix-ui/react-accordion": "1.3.1", "@radix-ui/react-checkbox": "1.3.2", "@radix-ui/react-dialog": "1.1.13", "@radix-ui/react-dropdown-menu": "2.1.6", @@ -46,8 +45,8 @@ "pptxgenjs": "4.0.1", "react": "19.0.0", "react-dom": "19.0.0", - "react-force-graph-2d": "1.27.1", "react-hook-form": "^7.53.0", + "react-force-graph-2d": "1.27.1", "react-markdown": "^10.1.0", "remark-gfm": "^4.0.1", "swiper": "^12.1.4", diff --git a/tailwind.config.ts b/tailwind.config.ts index 18c1545..afc7295 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -32,24 +32,14 @@ module.exports = { DEFAULT: "hsl(var(--brand) / )", foreground: "hsl(var(--brand-foreground) / )", }, + cta: { + DEFAULT: "hsl(var(--cta) / )", + foreground: "hsl(var(--cta-foreground) / )", + }, }, borderRadius: { DEFAULT: "var(--radius)", }, - keyframes: { - "accordion-down": { - from: { height: "0" }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: "0" }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, }, }, plugins: [