+ + + [{person.country}] + +
+ ) : ( + + )} +diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbec7dd4..4f022dda 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,6 +11,8 @@ jobs:
name: Format, Typecheck, Build, and Test
runs-on: ubuntu-latest
timeout-minutes: 30
+ env:
+ DEVHUB_BACKEND_URL: ${{ vars.DEVHUB_BACKEND_URL }}
steps:
- name: Checkout
diff --git a/.gitignore b/.gitignore
index d108325a..9b4d3d2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ public/js/home-hero-player.js
# Misc
.DS_Store
+.env
.env.local
.env.development.local
.env.test.local
diff --git a/docs/community-backend.md b/docs/community-backend.md
new file mode 100644
index 00000000..ec210511
--- /dev/null
+++ b/docs/community-backend.md
@@ -0,0 +1,141 @@
+# Community backend integration
+
+> Student Fellows routes and their dynamic sitemap are deferred to the
+> `feat/student-fellows` branch. The backend client and shared data contract are
+> intentionally retained for that later release, but the current MVP directory
+> does not call the backend.
+
+Backend repository: [pixel-point/devhub-backend](https://github.com/pixel-point/devhub-backend).
+Follow its [Vercel setup guide](https://github.com/pixel-point/devhub-backend/blob/main/docs/vercel.md)
+to deploy the API/admin and initialize Neon. In the Vercel project connected to
+`pixel-point/devhub`, set `DEVHUB_BACKEND_URL` to the backend's stable HTTPS
+origin for **Preview**, then redeploy this PR. Configure **Production** separately.
+The API and `/headshots` must be publicly reachable; no browser CORS wildcard
+or auth/database/email secrets are needed in the frontend.
+
+The MVP directory reads the checked-in snapshot at
+`src/lib/community/data/mvps.json`. Its roster, public profile fields, images,
+and links were reconciled against the official
+[Databricks MVP page](https://www.databricks.com/discover/mvps), which is the
+source of truth. The existing `devhub-backend` client remains available for
+Student Fellows and future administrative workflows, but it is not used to
+render MVPs.
+
+MVP portraits are checked in under `public/img/community/mvps`. Each image is a
+768×768 JPEG generated from the supplied source portrait with face-aware square
+cropping and conservative compression. This keeps the 352px desktop card sharp
+on high-density screens without a runtime dependency on the Databricks image
+host.
+
+Start the backend with `pnpm dev:local` on port 3001 and this website with
+`pnpm dev` on port 3000. The backend's explicitly enabled local mode uses the
+imported source data and keeps local edits separate from the source snapshot.
+
+For production or a different local endpoint, set the server-only environment
+variable `DEVHUB_BACKEND_URL` to the backend origin, for example
+`https://backend.example.com`. Restart the website after changing configuration.
+The development default is `http://127.0.0.1:3001`. Production requires an
+explicit URL. Never expose database or authentication secrets through
+`NEXT_PUBLIC_` variables.
+
+## Public API
+
+- `GET /api/v1/people`: `kind=student|mvp`, `q`, `country`, `city`, `cohort`,
+ `expertise`, `featured`, `page`, `pageSize` (1–100, default 24).
+- `GET /api/v1/people/:slug`: a published profile or 404.
+- `GET /api/v1/facets?kind=student|mvp`: countries, cities, cohorts, expertise.
+
+The client in `src/lib/community/people.server.ts` validates response schemas
+and strips undeclared fields before sending data to React. Private email,
+account identifiers, and internal notes are never part of the website DTO.
+Only `published` profiles are accepted. Relative `/headshots/` URLs are resolved
+against the backend origin; ensure that origin and its media files are publicly
+reachable over HTTPS in production.
+
+`additionalLinks` preserves named HTTPS destinations beyond the four primary
+`links` keys, such as YouTube, Medium, and Databricks Community. Its shape is
+`[{ label, url }]` (up to 20 items); the SDK defaults missing arrays to `[]` for
+older responses. Cards expose these destinations through an accessible More
+links menu. An MVP with only an additional link uses that destination for its
+card; student profiles also include these URLs in their Connect menu and
+`sameAs` metadata. Empty labels, unsafe URLs, and private extra fields are not
+accepted into the rendered contract.
+
+## Rendering and freshness
+
+The MVP snapshot contains 87 official members and was verified on 2026-09-16.
+All 87 matched records in the admin export. Twenty-two admin-only records were
+excluded because they were absent from the official page, and the official
+“Director I Author” title was used for Dr. Alan L. Dennis instead of the
+conflicting backend title. Country casing and admin-only city metadata remain
+normalized for the existing filters.
+
+`src/lib/community/mvps.ts` validates the snapshot at module load and projects
+only public card/search fields into React. The base directory and all paginated
+paths are generated statically at build time; malformed and out-of-range paths
+return 404, and `/page/1` permanently redirects to the base route while retaining
+query parameters. Neither production builds nor page requests need
+`DEVHUB_BACKEND_URL` for the MVP experience. Updating the official roster
+requires a deliberate snapshot refresh and redeploy.
+
+The preserved backend loader still batches records in groups of 100, validates
+complete responses, strips private fields, and rejects inconsistent snapshots.
+When the deferred Student Fellows routes are restored, they can continue using
+that loader and its ISR behavior without changing the static MVP boundary.
+
+Search, City/Country multiselect and pagination use this local snapshot, without
+API requests or Next.js server navigations. Values within a facet use OR;
+different facets and search combine with AND. Filtering resets to page 1.
+The dependency-free search matches all query words across name, expertise,
+headline, organization, location and bio, regardless of word order. Accents,
+case, apostrophes and whitespace are normalized; `C++` and `C#` remain distinct.
+Exact words rank above prefixes, which match from the first character; one insertion,
+deletion, replacement or adjacent transposition is allowed only when both words
+have at least five characters. Results needing fewer typo corrections come first.
+Exact full names get a bonus; name and expertise matches outweigh biography
+matches. Ties and empty queries preserve the original directory order. City/Country
+dropdown search uses the same normalization, but remains a strict substring match.
+Country URLs use comma-separated names, for example
+`?country=Belgium,Brazil,Canada`; older repeated `country` parameters are still
+accepted. City values remain repeated parameters because city names can contain
+commas. Page numbers use `/page/N`, with page 1 at the base path; for example
+`/mvps/directory/page/2?q=data&country=Belgium,Brazil`.
+Legacy `?page=N` links remain readable in the browser, but generated links use
+path pagination. A page in the path takes precedence over a legacy query page.
+Native History API updates observe both pathname and search, preserving shareable
+URLs and back/forward navigation without data requests; typing replaces the
+current history entry. Reloaded query URLs apply filters after hydration; the
+initial static HTML is the unfiltered slice for the requested path page.
+Each page path has its own title and canonical; filtered URLs canonicalize to
+the same path without query parameters and share its static metadata.
+Local pagination keeps the document and social titles/canonical in sync without
+fetching a route, including Back/Forward. Activating a pagination link moves focus
+and scroll to the directory so the newly selected cards are immediately visible.
+Query-specific `X-Robots-Tag: noindex, follow` headers keep filtered URLs out of
+the index without making the page dynamically rendered.
+Published student detail URLs remain discoverable through the community sitemap.
+
+Student profiles are generated on demand on their first visit and cached for
+an hour, including metadata. New slugs work without a rebuild. Public API calls
+time out after eight seconds. After an hour, the next visit can receive the old
+page while Next.js regenerates it in the background; this is not a scheduled job
+or a hard one-hour freshness guarantee. An already open tab keeps its snapshot
+until navigation/reload. No webhook or immediate invalidation is configured.
+
+Failed regeneration throws, retaining the last successful page rather than
+caching an unavailable panel or an incomplete list as successful content.
+A first-render failure uses the route error boundary. Actual detail 404s use
+the website's not-found page. Urgent unpublishing needs explicit cache invalidation;
+a redeploy alone may reuse the data cache. Public content can remain in cached
+pages during an outage.
+
+`/community-sitemap.xml` lists published student detail pages at request time.
+It is added to robots.txt when `DEVHUB_BACKEND_URL` is configured, and returns
+a retryable 503 during backend outages. Split it into a sitemap index before
+the directory exceeds 50,000 student profiles. Its public cache lasts five
+minutes; its backend requests remain uncached and independent of the hourly pages.
+
+Backend setup, Better Auth administrator provisioning, Neon migrations, source
+data provenance, and Resend configuration live in the backend repository's
+documentation. A future member cabinet can link authenticated accounts to
+profiles there without making the public website responsible for authentication.
diff --git a/docs/community-design.md b/docs/community-design.md
new file mode 100644
index 00000000..bd4749bf
--- /dev/null
+++ b/docs/community-design.md
@@ -0,0 +1,160 @@
+# MVP and Student Fellows design implementation
+
+> Student Fellows implementation details below are retained for the deferred
+> `feat/student-fellows` branch. The current release publishes only the MVP
+> pages and links to the existing external Student Fellows site.
+
+Implemented 2026-09-07 using the existing DevHub Next.js, Tailwind, and shadcn components. Figma is the visual source. Prime setup was unavailable, and the parent authorized native implementation; no Prime candidate validation, export, or visual parity claim is made.
+
+## Routes and Figma sources
+
+All frames belong to `auWfvBwnxY9q6acMsE4xdd`, page `2:5` (Preview).
+
+| Route | Figma frame | Canvas |
+| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
+| `/mvps` | [12378:7437 — databricks-MVPs-1920](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12378-7437) | 1920 × 3775 |
+| `/mvps/directory` | [12378:6109 — databricks-MVP-directory](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12378-6109) | 1920 × 3829 |
+| `/student-fellows` | [12378:10492 — databricks-student-fellows-1920](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12378-10492) | 1920 × 3473 |
+| `/student-fellows/fellows` | [12378:8397 — databricks-student-fellows](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12378-8397) | 1920 × 3779 |
+| `/student-fellows/fellows/[slug]` | [12378:9655 — databricks-individual-fellow-page](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12378-9655) | 1920 × 2093 |
+
+The original MVP and MVP directory URLs were duplicates. The separate directory was discovered programmatically as a sibling of `12378:7437`, under section `12378:6108`. Student frames share section `12378:8396`.
+
+## Design evidence
+
+Design evidence was captured in the local project workspace at
+`docs/design/community`. These QA artifacts are maintained outside this repository.
+
+- Full reference screenshots: `mvp.png`, `mvp-directory.png`, `student-fellows.png`, `students-list.png`, `student-profile.png`.
+- Exact Plugin API measurements and visible copy: `mvp-measurements.json`, `student-fellows-measurements.json`, `student-profile-measurements.json`, `directories-measurements.json`.
+- Coordinates in measurement manifests are relative to each page canvas, in pixels. They are not inferred from resized screenshots.
+- Whole-page `get_design_context` responses exceeded provider size limits. Section calls recovered the MVP hero (`8376`), benefits (`7538`), requirements (`7574`), and badge (`8335`); Student hero (`11383`), campus cards (`11403`), career sections (`10500`, `10524`), and badge (`11328`); directory heading (`6112`) and card collection (`8486`); profile body (`9751`) and sidebar (`9783`). These IDs use prefix `12378:`.
+- Measurement values are retained as evidence. No browser measurement manifest or machine-owned `audit.json` was produced, so these files do not certify pixel parity.
+
+Important desktop measurements:
+
+| Element | Figma geometry / type |
+| ----------------------------- | ------------------------------------------------------------ |
+| Standard content | x=352, width=1216 on 1920 canvas |
+| Program headline | x=352, y=318, width=966; DM Sans 56/56 |
+| Program badge | width=116; MVP height=135, Student height≈138 |
+| Directory headline | x=192, y=224, width=1344; Inter 96/96, first-line indent=160 |
+| Directory intro | x=1472, y=347, width=256; Inter 16/20 |
+| Directory filters | y=675, height=44; two 160-wide selects, 437-wide search |
+| Directory grid | x=352, y=779, width=1216; 4 columns, 64px gaps |
+| Directory portrait | 256 × 255, displayed as a square media slot |
+| Directory name / organization | Inter 20/25 and 16/20 |
+| Student campus cards | 3 × 384-wide, 32px gaps, 364-high; 48px vector icons |
+| Section headings | Inter 44/55, -4% tracking |
+| Profile content | x=383.5, width=736; sidebar x=1215.5, width=352; 96px gap |
+| Profile portrait | 352 × 390.193 |
+
+The implementation uses the existing `Inter`, `DM Sans`, and `Geist Mono` font setup. Directory text uses Inter; program hero text uses DM Sans. Native responsive layouts collapse grids and stack profile columns. No mobile Figma frames were supplied, so responsive checks are acceptance checks, not pixel-parity evidence.
+
+## Implementation decisions
+
+| Section | Native mode | Implementation |
+| ---------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Shared header / skip link / search | Reuse | `(website)/layout.tsx` and existing Header; no duplicate navigation shell |
+| Shared footer | Adapt | Added MVP and Student Fellows program/directory links to existing Community list; increased copyright and legal-link contrast |
+| Program heroes | Custom composition | `program-hero.tsx`, existing Button, local Figma badges, exact Figma copy |
+| MVP benefits | Custom composition | `program-benefits.tsx`, existing SectionKicker, eight content blocks |
+| Student campus cards | Custom composition | `program-benefits.tsx`, three semantic cards with exact Figma SVG icons |
+| MVP requirements | Custom composition | `program-requirements.tsx`, four rows and exact exported angled SVG rule |
+| Student career pathways | Custom composition | `program-requirements.tsx`, two numbered sections with native lists |
+| Directory headline | Custom composition | `directory-hero.tsx`; shared between the two data kinds |
+| Filters / search | Adapt | Existing Popover, Checkbox, Label, InputGroup and Button; local multiselect and search with URL state and a keyboard-operable magnifier |
+| People cards | Custom composition | `person-card.tsx`, local optimized copies of official photographs and profile data, local social glyphs |
+| Pagination | Adapt | Existing shadcn Pagination components, real links, current-page state and ellipses |
+| Student profile | Custom composition | `student-profile.tsx`, existing BackLink and SectionKicker; actual biography/highlights |
+| Bottom CTA | Adapt | Existing home CTA gains optional `highlightedText`; its default remains `agentic app`. Community CTA supplies Figma titles, actions, and highlights |
+
+All substantial new sections live in `src/components/community/`. The route files own metadata and visible section order. Static MVP data and the preserved API fetch/schema implementation stay in the parent-owned `src/lib/community/` domain.
+
+Small shared changes: `src/components/home/cta.tsx`, `src/components/footer.tsx`, and `src/css/custom.css`. The added `db-paper` token preserves the Figma light surface (`#f9f7f4`) inside the site's existing dark root. No dependencies, header logic, or image optimizer configuration were changed by this frontend work.
+
+## Data and interaction contract
+
+- The MVP directory loads the checked-in, schema-validated snapshot from `src/lib/community/data/mvps.json`; its official roster and public fields were verified against the Databricks MVP page on 2026-09-16. Portraits resolve to face-centered, 768×768 compressed JPEGs in `public/img/community/mvps`. The preserved backend loader remains available for the deferred Student Fellows directory.
+- City and Country are local multiselect filters in both directories. Search and pagination also use the public snapshot already loaded in the browser; changing controls makes no data request.
+- The list uses 20 records per page, matching the Figma four-column/five-row layout. Pagination uses `/page/N` (page 1 uses the base directory); search, comma-separated `country` names and repeated `city` values stay in the query string. Native history keeps all controls local. Legacy `?page=N` and repeated `country` parameters remain supported. Filtering resets to the base path; filtered results clamp to the last available page, while nonexistent unfiltered page paths return 404.
+- URL values are normalized locally; page is a safe integer in 1–100000, `q` is capped at 200 characters, each City/Country value at 100. Cohort and Expertise remain API capabilities and are not exposed by these Figma-aligned controls.
+- Student cards navigate to `/student-fellows/fellows/[slug]`. MVP cards link to an actual published external website/social profile; no unrequested MVP detail route is created.
+- The profile rejects missing records and `kind !== "student"` with `notFound()`. Highlights render only when supplied by the backend. Missing biographies, organizations, expertise, locations, and social URLs do not generate invented copy.
+- Service errors propagate to a retryable route error boundary; failed ISR regeneration retains the previous successful page. Empty successful searches have their own “No matches found” state and clear-filters link. Unknown student slugs remain 404s, distinct from service outages.
+- MVP directory pages are generated statically from the local snapshot. Deferred Student directory and profile routes retain hourly backend revalidation when restored. See `community-backend.md` for the complete boundary.
+- Every page has a specific title, description, and canonical. Paginated MVP paths serve their corresponding cards in static HTML, with page-specific titles and canonicals. Directory query URLs share that path's static metadata, canonicalize to the path without query parameters and retain `noindex, follow` through an HTTP header; public profile pages add escaped JSON-LD using `ProfilePage`, `Person`, and educational `affiliation` (not an unsupported graduation claim). Sitemap integration is parent-owned.
+
+Verified CTA destinations:
+
+- [MVP nomination](https://surveys.training.databricks.com/jfe/form/SV_6Ed034QOD4pcQFU), linked from the existing [Databricks MVP page](https://www.databricks.com/discover/mvps).
+- [Student Fellows application](https://airtable.com/appasC90KmqZ5x1t5/pag6tvR9VUG4Kf1iM/form), supplied by the source/data agent's verified program-link extraction.
+- “Browse fellow profiles” navigates to the internal directory; “Apply today” opens the existing Student Fellows application form. “Fellow sign in” opens the existing [Student Fellows sign-in](https://databricksstudentfellows.com/signin).
+
+## Assets, accessibility, and deviations
+
+Local assets under `public/img/community/`: MVP and Student badge SVGs; `build.svg`, `share.svg`, `learn.svg`; LinkedIn and X SVG glyphs; `membership-rule.svg`; dropdown glyphs and the supplied `default-avatar.svg`. Badges and program illustrations use vector assets rather than raster approximations.
+
+Participant photos always use normalized backend `photoUrl` values. Native images specify dimensions and fixed media geometry, lazy-load directory images, and eagerly load the main profile photo. Future arbitrary admin uploads should retain server-side image size limits/optimization; the frontend does not enforce upload limits. Missing photo URLs show the supplied neutral `default-avatar.svg`, not placeholder text or an invented face.
+
+Known differences and product decisions:
+
+1. Both directories use the Figma City/Country filters. The parent added City to the backend and SDK contract. Empty facet lists are disabled unless a currently active query value must remain clearable. City values are never inferred from institutions or invented.
+2. Directory names and photos in Figma are illustrative and partly duplicated between MVP and Student designs. Actual data determines displayed records, result count, wrapping, and page height. The profile Figma contains inconsistent example location/university/achievements; none are hardcoded into a person's profile.
+3. Existing Header/Footer, legal/privacy links, and product navigation take precedence over obsolete Figma shell links. Four new Community links increase footer height.
+4. The default CTA was extended through a prop rather than copied. CTA window-label contrast and existing footer small-text contrast were raised after browser accessibility findings.
+5. There is no invented mobile reference and no claim of full visual parity. Prime remains unconfigured and no Prime Studio mutations were made.
+
+Keyboard/focus contracts: labelled popovers, checkboxes and search inputs; full-row checkbox labels; Gray 80 input borders and Gray 60 focus borders without a blue ring; Enter or magnifier submit; real pagination links with local activation and focus/scroll to results; current-page ARIA; named social links; decorative assets with empty alt; real person-name alt text; existing skip-to-main link. Single-line checkbox rows retain a 40px pitch. Content sections remain semantic headings, paragraphs, articles, and lists.
+
+## Verification and handoff
+
+- Frontend `pnpm typecheck`: passed after final component changes.
+- Scoped Prettier formatting: completed for all owned source files. `git diff --check`: passed.
+- `pnpm exec fallow dead-code`: final rerun passed with no issues after City integration. Three SDK-only findings (`personKindSchema`, `directoryQuerySchema`, `PeoplePage`) were handed to and resolved by the parent; the frontend did not mutate parent-owned schema exports.
+- `pnpm exec fallow dupes`: completed, 17 existing clone groups / about 1% duplication; no groups involved `src/components/community` or the new routes. Reports were saved in `/tmp/devhub-frontend-{dead-code,dupes}.json`.
+- Local SVG files parsed as XML and contain no script elements. Badge availability and the Student badge appearance were checked.
+- Parent browser review found and prompted correction of numeric Tailwind line-height syntax, missing glyph exports, profile heading colors, JSON-LD educational relation, and CTA/footer contrast. Current code contains these corrections.
+- Parent subsequently reported no overflow or broken images at 390px on Student/MVP program pages, MVP directory, and a student profile. Source worker reported the six baseline integration checks passed; the expanded City/Country suite is owned by that worker.
+- Parent/source worker owns the final production build, repository test suite, live desktop/mobile screenshots, automated accessibility check, and `tests/e2e/community.spec.ts`. Do not infer those final results from the typecheck or design screenshots; record their actual outcomes in the overall delivery report.
+
+No commits, deployment, publication, Prime Studio changes, Figma edits, `.env` changes, or backend-source mutations were performed by this frontend work.
+
+## Workbook reconciliation — 2026-09-08
+
+The supplied MVP export includes links beyond the four primary social icons.
+Cards now expose named `additionalLinks` through an accessible **More links**
+menu built with the existing shadcn DropdownMenu. The menu is nonmodal, stays
+inside its named navigation landmark through an optional portal container,
+supports keyboard navigation and restores trigger focus on Escape. It preserves the card's
+existing layout and uses real source labels and HTTPS destinations. MVP cards
+with only an additional link, such as a YouTube channel, use that destination
+for the name and portrait link. Student profile connections and JSON-LD also
+support the same optional field.
+
+The backend now supplies 105 MVP city values from the workbook and 127 local
+photos across both programs. City filters become available from those actual
+facets. No student source data changed during this reconciliation. This small
+data-driven interaction extension does not establish new Figma or Prime parity
+evidence. Current import and browser checks are summarized in the backend's
+[verification record](https://github.com/pixel-point/devhub-backend/blob/main/docs/verification.md).
+
+Before publication on 2026-09-08, the changes were transferred to
+`feat/community-programs` from the current `origin/main` (`07e7f51`). The final
+production build, 355 unit tests across 39 files and 199 browser tests passed,
+including all 12 community scenarios. Formatting, typecheck and dead-code
+checks passed; existing duplication remains outside the community components.
+
+## Student Fellows hero update — 2026-09-15
+
+Updated the hero actions from [Figma node 12547:14374](https://www.figma.com/design/auWfvBwnxY9q6acMsE4xdd/Databricks-Website-Design?node-id=12547-14374), after synchronizing `feat/community-programs` with the rebased remote branch at `de0db45`.
+
+The student hero now groups the profile directory and Fellow sign-in controls with “Not a fellow yet? Apply today”. The application uses the same source URL as the directory CTA and the exact exported 16px SVG arrow. Buttons are 44px tall, with desktop widths of 245px and 183px, 20px gaps between buttons and before the application prompt (12px in the stacked mobile layout). The prompt wraps as a single group only when the available width is insufficient; no viewport breakpoint forces it onto a separate row. Existing project fonts and grey tokens are retained. The supporting description moves below the actions before the desktop row becomes crowded.
+
+Member authentication in DevHub remains future scope. The sign-in control links to the existing Student Fellows site at `https://databricksstudentfellows.com/signin`, as confirmed by the user.
+
+Browser checks covered 320, 390, 768, 1024, 1280 and 1920px without horizontal overflow. The directory CTA opened the live student directory, and Apply today opened the Databricks Student Fellows Interest Form. The MVP hero retains its existing nomination/directory actions. The page retains one H1, its title/description/canonical, semantic links and a decorative arrow with empty alternative text.
+
+Prime setup requires an organization login and was unavailable. This update uses direct Figma context and local component patterns; no machine Prime parity or pixel-perfect claim is made. No dependencies or backend configuration were changed by the hero update.
+
+Validation: production build, 408 unit tests, 204 browser tests, formatting, typecheck and dead-code checks passed. Existing duplication remains outside the community components.
diff --git a/next.config.mjs b/next.config.mjs
index cf5f5bda..265f450e 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -78,6 +78,11 @@ const nextConfig = {
const latestAppkitDocs = `/docs/appkit/${appkitDocsChannel()}`;
return [
+ {
+ source: "/mvps/directory/page/1",
+ destination: "/mvps/directory",
+ permanent: true,
+ },
{
source: "/docs",
destination: "/docs/start-here",
@@ -132,6 +137,13 @@ const nextConfig = {
},
async headers() {
return [
+ ...["/mvps/directory", "/mvps/directory/page/:page"].flatMap((source) =>
+ ["q", "city", "country", "page"].map((key) => ({
+ source,
+ has: [{ type: "query", key }],
+ headers: [{ key: "X-Robots-Tag", value: "noindex, follow" }],
+ })),
+ ),
{
source: "/js/home-hero-player.js",
headers: [
diff --git a/package.json b/package.json
index 368a04f7..9c6e648c 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"remark-mdx": "^3.1.1",
+ "server-only": "^0.0.1",
"shiki": "3.19.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 57bfbbef..a4699d61 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -107,6 +107,9 @@ importers:
remark-mdx:
specifier: ^3.1.1
version: 3.1.1
+ server-only:
+ specifier: ^0.0.1
+ version: 0.0.1
shiki:
specifier: 3.19.0
version: 3.19.0
@@ -4764,6 +4767,9 @@ packages:
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
engines: {node: '>= 18'}
+ server-only@0.0.1:
+ resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
+
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@@ -10037,6 +10043,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ server-only@0.0.1: {}
+
setprototypeof@1.2.0: {}
sharp@0.34.5:
diff --git a/public/img/community/apply-arrow.svg b/public/img/community/apply-arrow.svg
new file mode 100644
index 00000000..a687384e
--- /dev/null
+++ b/public/img/community/apply-arrow.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/img/community/arrow-right.svg b/public/img/community/arrow-right.svg
new file mode 100644
index 00000000..92417c54
--- /dev/null
+++ b/public/img/community/arrow-right.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/img/community/default-avatar.svg b/public/img/community/default-avatar.svg
new file mode 100644
index 00000000..06bd3e66
--- /dev/null
+++ b/public/img/community/default-avatar.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/img/community/filter-check.svg b/public/img/community/filter-check.svg
new file mode 100644
index 00000000..8946c55b
--- /dev/null
+++ b/public/img/community/filter-check.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/img/community/filter-search.svg b/public/img/community/filter-search.svg
new file mode 100644
index 00000000..344e94ae
--- /dev/null
+++ b/public/img/community/filter-search.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/img/community/linkedin.svg b/public/img/community/linkedin.svg
new file mode 100644
index 00000000..c6dc4f60
--- /dev/null
+++ b/public/img/community/linkedin.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/img/community/membership-rule.svg b/public/img/community/membership-rule.svg
new file mode 100644
index 00000000..0e951abd
--- /dev/null
+++ b/public/img/community/membership-rule.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/img/community/mvp-badge.svg b/public/img/community/mvp-badge.svg
new file mode 100644
index 00000000..d3401807
--- /dev/null
+++ b/public/img/community/mvp-badge.svg
@@ -0,0 +1,86 @@
+
diff --git a/public/img/community/mvp-og-image.jpg b/public/img/community/mvp-og-image.jpg
new file mode 100644
index 00000000..b3b69c2b
Binary files /dev/null and b/public/img/community/mvp-og-image.jpg differ
diff --git a/public/img/community/mvps/mvp-aarni-sillanpaa.jpg b/public/img/community/mvps/mvp-aarni-sillanpaa.jpg
new file mode 100644
index 00000000..b48ca5bf
Binary files /dev/null and b/public/img/community/mvps/mvp-aarni-sillanpaa.jpg differ
diff --git a/public/img/community/mvps/mvp-abiola-david.jpg b/public/img/community/mvps/mvp-abiola-david.jpg
new file mode 100644
index 00000000..ee12a32e
Binary files /dev/null and b/public/img/community/mvps/mvp-abiola-david.jpg differ
diff --git a/public/img/community/mvps/mvp-adi-polak.jpg b/public/img/community/mvps/mvp-adi-polak.jpg
new file mode 100644
index 00000000..c632aa3a
Binary files /dev/null and b/public/img/community/mvps/mvp-adi-polak.jpg differ
diff --git a/public/img/community/mvps/mvp-ajay-kumar-pandey.jpg b/public/img/community/mvps/mvp-ajay-kumar-pandey.jpg
new file mode 100644
index 00000000..c728778e
Binary files /dev/null and b/public/img/community/mvps/mvp-ajay-kumar-pandey.jpg differ
diff --git a/public/img/community/mvps/mvp-alex-wiss-wolferding.jpg b/public/img/community/mvps/mvp-alex-wiss-wolferding.jpg
new file mode 100644
index 00000000..3455cff7
Binary files /dev/null and b/public/img/community/mvps/mvp-alex-wiss-wolferding.jpg differ
diff --git a/public/img/community/mvps/mvp-andrew-sitz.jpg b/public/img/community/mvps/mvp-andrew-sitz.jpg
new file mode 100644
index 00000000..4b678160
Binary files /dev/null and b/public/img/community/mvps/mvp-andrew-sitz.jpg differ
diff --git a/public/img/community/mvps/mvp-ansh-lambda.jpg b/public/img/community/mvps/mvp-ansh-lambda.jpg
new file mode 100644
index 00000000..a8c53254
Binary files /dev/null and b/public/img/community/mvps/mvp-ansh-lambda.jpg differ
diff --git a/public/img/community/mvps/mvp-anuj-kumar-sen.jpg b/public/img/community/mvps/mvp-anuj-kumar-sen.jpg
new file mode 100644
index 00000000..978e8a88
Binary files /dev/null and b/public/img/community/mvps/mvp-anuj-kumar-sen.jpg differ
diff --git a/public/img/community/mvps/mvp-awadelrahman-m-a-ahmed.jpg b/public/img/community/mvps/mvp-awadelrahman-m-a-ahmed.jpg
new file mode 100644
index 00000000..9fc4863f
Binary files /dev/null and b/public/img/community/mvps/mvp-awadelrahman-m-a-ahmed.jpg differ
diff --git a/public/img/community/mvps/mvp-bartosz-konieczny.jpg b/public/img/community/mvps/mvp-bartosz-konieczny.jpg
new file mode 100644
index 00000000..8c5a5195
Binary files /dev/null and b/public/img/community/mvps/mvp-bartosz-konieczny.jpg differ
diff --git a/public/img/community/mvps/mvp-behzad-nikzad.jpg b/public/img/community/mvps/mvp-behzad-nikzad.jpg
new file mode 100644
index 00000000..ea4cd09d
Binary files /dev/null and b/public/img/community/mvps/mvp-behzad-nikzad.jpg differ
diff --git a/public/img/community/mvps/mvp-bianca-stratulat.jpg b/public/img/community/mvps/mvp-bianca-stratulat.jpg
new file mode 100644
index 00000000..030f303b
Binary files /dev/null and b/public/img/community/mvps/mvp-bianca-stratulat.jpg differ
diff --git a/public/img/community/mvps/mvp-casper-lubbers.jpg b/public/img/community/mvps/mvp-casper-lubbers.jpg
new file mode 100644
index 00000000..d83228f7
Binary files /dev/null and b/public/img/community/mvps/mvp-casper-lubbers.jpg differ
diff --git a/public/img/community/mvps/mvp-chalapathi-rao-komirisetti.jpg b/public/img/community/mvps/mvp-chalapathi-rao-komirisetti.jpg
new file mode 100644
index 00000000..0b0f8a04
Binary files /dev/null and b/public/img/community/mvps/mvp-chalapathi-rao-komirisetti.jpg differ
diff --git a/public/img/community/mvps/mvp-dan-williams.jpg b/public/img/community/mvps/mvp-dan-williams.jpg
new file mode 100644
index 00000000..12bdedfc
Binary files /dev/null and b/public/img/community/mvps/mvp-dan-williams.jpg differ
diff --git a/public/img/community/mvps/mvp-daniel-sahal.jpg b/public/img/community/mvps/mvp-daniel-sahal.jpg
new file mode 100644
index 00000000..21e0d21f
Binary files /dev/null and b/public/img/community/mvps/mvp-daniel-sahal.jpg differ
diff --git a/public/img/community/mvps/mvp-derar-alhussein.jpg b/public/img/community/mvps/mvp-derar-alhussein.jpg
new file mode 100644
index 00000000..2f0ebcde
Binary files /dev/null and b/public/img/community/mvps/mvp-derar-alhussein.jpg differ
diff --git a/public/img/community/mvps/mvp-dilorom-abdullah.jpg b/public/img/community/mvps/mvp-dilorom-abdullah.jpg
new file mode 100644
index 00000000..61960b4a
Binary files /dev/null and b/public/img/community/mvps/mvp-dilorom-abdullah.jpg differ
diff --git a/public/img/community/mvps/mvp-dip-kharod.jpg b/public/img/community/mvps/mvp-dip-kharod.jpg
new file mode 100644
index 00000000..ecf8c7c1
Binary files /dev/null and b/public/img/community/mvps/mvp-dip-kharod.jpg differ
diff --git a/public/img/community/mvps/mvp-domonkos-pal.jpg b/public/img/community/mvps/mvp-domonkos-pal.jpg
new file mode 100644
index 00000000..1b192508
Binary files /dev/null and b/public/img/community/mvps/mvp-domonkos-pal.jpg differ
diff --git a/public/img/community/mvps/mvp-doug-macwilliams.jpg b/public/img/community/mvps/mvp-doug-macwilliams.jpg
new file mode 100644
index 00000000..c52de0d3
Binary files /dev/null and b/public/img/community/mvps/mvp-doug-macwilliams.jpg differ
diff --git a/public/img/community/mvps/mvp-dr-alan-l-dennis.jpg b/public/img/community/mvps/mvp-dr-alan-l-dennis.jpg
new file mode 100644
index 00000000..3d74e388
Binary files /dev/null and b/public/img/community/mvps/mvp-dr-alan-l-dennis.jpg differ
diff --git a/public/img/community/mvps/mvp-dylan-ford.jpg b/public/img/community/mvps/mvp-dylan-ford.jpg
new file mode 100644
index 00000000..fb395dff
Binary files /dev/null and b/public/img/community/mvps/mvp-dylan-ford.jpg differ
diff --git a/public/img/community/mvps/mvp-eddie-edgeworth.jpg b/public/img/community/mvps/mvp-eddie-edgeworth.jpg
new file mode 100644
index 00000000..f2e1ce5a
Binary files /dev/null and b/public/img/community/mvps/mvp-eddie-edgeworth.jpg differ
diff --git a/public/img/community/mvps/mvp-elena-boiarskaia.jpg b/public/img/community/mvps/mvp-elena-boiarskaia.jpg
new file mode 100644
index 00000000..59e2f8ca
Binary files /dev/null and b/public/img/community/mvps/mvp-elena-boiarskaia.jpg differ
diff --git a/public/img/community/mvps/mvp-eloisa-elias-t.jpg b/public/img/community/mvps/mvp-eloisa-elias-t.jpg
new file mode 100644
index 00000000..1f0c398d
Binary files /dev/null and b/public/img/community/mvps/mvp-eloisa-elias-t.jpg differ
diff --git a/public/img/community/mvps/mvp-gary-nakanelua.jpg b/public/img/community/mvps/mvp-gary-nakanelua.jpg
new file mode 100644
index 00000000..58b93e77
Binary files /dev/null and b/public/img/community/mvps/mvp-gary-nakanelua.jpg differ
diff --git a/public/img/community/mvps/mvp-gavita-regunath.jpg b/public/img/community/mvps/mvp-gavita-regunath.jpg
new file mode 100644
index 00000000..380f5cd3
Binary files /dev/null and b/public/img/community/mvps/mvp-gavita-regunath.jpg differ
diff --git a/public/img/community/mvps/mvp-geir-alstad.jpg b/public/img/community/mvps/mvp-geir-alstad.jpg
new file mode 100644
index 00000000..25bf8087
Binary files /dev/null and b/public/img/community/mvps/mvp-geir-alstad.jpg differ
diff --git a/public/img/community/mvps/mvp-geoffrey-freeman.jpg b/public/img/community/mvps/mvp-geoffrey-freeman.jpg
new file mode 100644
index 00000000..ff331231
Binary files /dev/null and b/public/img/community/mvps/mvp-geoffrey-freeman.jpg differ
diff --git a/public/img/community/mvps/mvp-hubert-dudek.jpg b/public/img/community/mvps/mvp-hubert-dudek.jpg
new file mode 100644
index 00000000..5fe7418b
Binary files /dev/null and b/public/img/community/mvps/mvp-hubert-dudek.jpg differ
diff --git a/public/img/community/mvps/mvp-ike-ellis.jpg b/public/img/community/mvps/mvp-ike-ellis.jpg
new file mode 100644
index 00000000..13f778f8
Binary files /dev/null and b/public/img/community/mvps/mvp-ike-ellis.jpg differ
diff --git a/public/img/community/mvps/mvp-jacek-laskowski.jpg b/public/img/community/mvps/mvp-jacek-laskowski.jpg
new file mode 100644
index 00000000..1eddc2fd
Binary files /dev/null and b/public/img/community/mvps/mvp-jacek-laskowski.jpg differ
diff --git a/public/img/community/mvps/mvp-jaco-van-gelder.jpg b/public/img/community/mvps/mvp-jaco-van-gelder.jpg
new file mode 100644
index 00000000..bdf6997c
Binary files /dev/null and b/public/img/community/mvps/mvp-jaco-van-gelder.jpg differ
diff --git a/public/img/community/mvps/mvp-jake-duckers.jpg b/public/img/community/mvps/mvp-jake-duckers.jpg
new file mode 100644
index 00000000..bbe3c32f
Binary files /dev/null and b/public/img/community/mvps/mvp-jake-duckers.jpg differ
diff --git a/public/img/community/mvps/mvp-jason-yip.jpg b/public/img/community/mvps/mvp-jason-yip.jpg
new file mode 100644
index 00000000..7f92d0ac
Binary files /dev/null and b/public/img/community/mvps/mvp-jason-yip.jpg differ
diff --git a/public/img/community/mvps/mvp-jonathan-rioux.jpg b/public/img/community/mvps/mvp-jonathan-rioux.jpg
new file mode 100644
index 00000000..261c1482
Binary files /dev/null and b/public/img/community/mvps/mvp-jonathan-rioux.jpg differ
diff --git a/public/img/community/mvps/mvp-josh-adams.jpg b/public/img/community/mvps/mvp-josh-adams.jpg
new file mode 100644
index 00000000..6bff1abe
Binary files /dev/null and b/public/img/community/mvps/mvp-josh-adams.jpg differ
diff --git a/public/img/community/mvps/mvp-josue-a-bogran.jpg b/public/img/community/mvps/mvp-josue-a-bogran.jpg
new file mode 100644
index 00000000..dbd71c4e
Binary files /dev/null and b/public/img/community/mvps/mvp-josue-a-bogran.jpg differ
diff --git a/public/img/community/mvps/mvp-juan-diaz.jpg b/public/img/community/mvps/mvp-juan-diaz.jpg
new file mode 100644
index 00000000..1a034e89
Binary files /dev/null and b/public/img/community/mvps/mvp-juan-diaz.jpg differ
diff --git a/public/img/community/mvps/mvp-julia-forde.jpg b/public/img/community/mvps/mvp-julia-forde.jpg
new file mode 100644
index 00000000..181d105a
Binary files /dev/null and b/public/img/community/mvps/mvp-julia-forde.jpg differ
diff --git a/public/img/community/mvps/mvp-kyjah-keys.jpg b/public/img/community/mvps/mvp-kyjah-keys.jpg
new file mode 100644
index 00000000..71b78a10
Binary files /dev/null and b/public/img/community/mvps/mvp-kyjah-keys.jpg differ
diff --git a/public/img/community/mvps/mvp-lara-rachidi.jpg b/public/img/community/mvps/mvp-lara-rachidi.jpg
new file mode 100644
index 00000000..02e20382
Binary files /dev/null and b/public/img/community/mvps/mvp-lara-rachidi.jpg differ
diff --git a/public/img/community/mvps/mvp-laurenz-wuttke.jpg b/public/img/community/mvps/mvp-laurenz-wuttke.jpg
new file mode 100644
index 00000000..0dcfab90
Binary files /dev/null and b/public/img/community/mvps/mvp-laurenz-wuttke.jpg differ
diff --git a/public/img/community/mvps/mvp-liping-huang.jpg b/public/img/community/mvps/mvp-liping-huang.jpg
new file mode 100644
index 00000000..72a42cc2
Binary files /dev/null and b/public/img/community/mvps/mvp-liping-huang.jpg differ
diff --git a/public/img/community/mvps/mvp-luan-moreno.jpg b/public/img/community/mvps/mvp-luan-moreno.jpg
new file mode 100644
index 00000000..7c64c310
Binary files /dev/null and b/public/img/community/mvps/mvp-luan-moreno.jpg differ
diff --git a/public/img/community/mvps/mvp-maksim-pachkouski.jpg b/public/img/community/mvps/mvp-maksim-pachkouski.jpg
new file mode 100644
index 00000000..8abd6ed0
Binary files /dev/null and b/public/img/community/mvps/mvp-maksim-pachkouski.jpg differ
diff --git a/public/img/community/mvps/mvp-mani-kandasamy.jpg b/public/img/community/mvps/mvp-mani-kandasamy.jpg
new file mode 100644
index 00000000..cc692573
Binary files /dev/null and b/public/img/community/mvps/mvp-mani-kandasamy.jpg differ
diff --git a/public/img/community/mvps/mvp-mantu-samadder.jpg b/public/img/community/mvps/mvp-mantu-samadder.jpg
new file mode 100644
index 00000000..307503df
Binary files /dev/null and b/public/img/community/mvps/mvp-mantu-samadder.jpg differ
diff --git a/public/img/community/mvps/mvp-maria-vechtomova.jpg b/public/img/community/mvps/mvp-maria-vechtomova.jpg
new file mode 100644
index 00000000..24856391
Binary files /dev/null and b/public/img/community/mvps/mvp-maria-vechtomova.jpg differ
diff --git a/public/img/community/mvps/mvp-mate-gulyas.jpg b/public/img/community/mvps/mvp-mate-gulyas.jpg
new file mode 100644
index 00000000..34961323
Binary files /dev/null and b/public/img/community/mvps/mvp-mate-gulyas.jpg differ
diff --git a/public/img/community/mvps/mvp-maulik-dixit.jpg b/public/img/community/mvps/mvp-maulik-dixit.jpg
new file mode 100644
index 00000000..9da93ffe
Binary files /dev/null and b/public/img/community/mvps/mvp-maulik-dixit.jpg differ
diff --git a/public/img/community/mvps/mvp-michael-green.jpg b/public/img/community/mvps/mvp-michael-green.jpg
new file mode 100644
index 00000000..e72acb7f
Binary files /dev/null and b/public/img/community/mvps/mvp-michael-green.jpg differ
diff --git a/public/img/community/mvps/mvp-miguel-diaz.jpg b/public/img/community/mvps/mvp-miguel-diaz.jpg
new file mode 100644
index 00000000..5d3da9ed
Binary files /dev/null and b/public/img/community/mvps/mvp-miguel-diaz.jpg differ
diff --git a/public/img/community/mvps/mvp-nidhi-gupta.jpg b/public/img/community/mvps/mvp-nidhi-gupta.jpg
new file mode 100644
index 00000000..44e93759
Binary files /dev/null and b/public/img/community/mvps/mvp-nidhi-gupta.jpg differ
diff --git a/public/img/community/mvps/mvp-nivethan-venkatachalam.jpg b/public/img/community/mvps/mvp-nivethan-venkatachalam.jpg
new file mode 100644
index 00000000..147eadaa
Binary files /dev/null and b/public/img/community/mvps/mvp-nivethan-venkatachalam.jpg differ
diff --git a/public/img/community/mvps/mvp-pal-de-vibe.jpg b/public/img/community/mvps/mvp-pal-de-vibe.jpg
new file mode 100644
index 00000000..875604d7
Binary files /dev/null and b/public/img/community/mvps/mvp-pal-de-vibe.jpg differ
diff --git a/public/img/community/mvps/mvp-phani-reddy-janga.jpg b/public/img/community/mvps/mvp-phani-reddy-janga.jpg
new file mode 100644
index 00000000..06bdc72b
Binary files /dev/null and b/public/img/community/mvps/mvp-phani-reddy-janga.jpg differ
diff --git a/public/img/community/mvps/mvp-prakash-trivedi.jpg b/public/img/community/mvps/mvp-prakash-trivedi.jpg
new file mode 100644
index 00000000..86d18e01
Binary files /dev/null and b/public/img/community/mvps/mvp-prakash-trivedi.jpg differ
diff --git a/public/img/community/mvps/mvp-r-tyler-croy.jpg b/public/img/community/mvps/mvp-r-tyler-croy.jpg
new file mode 100644
index 00000000..baa63fab
Binary files /dev/null and b/public/img/community/mvps/mvp-r-tyler-croy.jpg differ
diff --git a/public/img/community/mvps/mvp-rahul-gupta.jpg b/public/img/community/mvps/mvp-rahul-gupta.jpg
new file mode 100644
index 00000000..57850d6f
Binary files /dev/null and b/public/img/community/mvps/mvp-rahul-gupta.jpg differ
diff --git a/public/img/community/mvps/mvp-rajaniesh-kaushikk.jpg b/public/img/community/mvps/mvp-rajaniesh-kaushikk.jpg
new file mode 100644
index 00000000..378185ab
Binary files /dev/null and b/public/img/community/mvps/mvp-rajaniesh-kaushikk.jpg differ
diff --git a/public/img/community/mvps/mvp-ranjit-nagesh.jpg b/public/img/community/mvps/mvp-ranjit-nagesh.jpg
new file mode 100644
index 00000000..bae5d648
Binary files /dev/null and b/public/img/community/mvps/mvp-ranjit-nagesh.jpg differ
diff --git a/public/img/community/mvps/mvp-raul-sarachaga.jpg b/public/img/community/mvps/mvp-raul-sarachaga.jpg
new file mode 100644
index 00000000..24cf3b59
Binary files /dev/null and b/public/img/community/mvps/mvp-raul-sarachaga.jpg differ
diff --git a/public/img/community/mvps/mvp-rishabh-pandey.jpg b/public/img/community/mvps/mvp-rishabh-pandey.jpg
new file mode 100644
index 00000000..010122b8
Binary files /dev/null and b/public/img/community/mvps/mvp-rishabh-pandey.jpg differ
diff --git a/public/img/community/mvps/mvp-robert-thompson.jpg b/public/img/community/mvps/mvp-robert-thompson.jpg
new file mode 100644
index 00000000..24abf48d
Binary files /dev/null and b/public/img/community/mvps/mvp-robert-thompson.jpg differ
diff --git a/public/img/community/mvps/mvp-ryan-shiva.jpg b/public/img/community/mvps/mvp-ryan-shiva.jpg
new file mode 100644
index 00000000..6dc9b0fd
Binary files /dev/null and b/public/img/community/mvps/mvp-ryan-shiva.jpg differ
diff --git a/public/img/community/mvps/mvp-sai-nageshwaran.jpg b/public/img/community/mvps/mvp-sai-nageshwaran.jpg
new file mode 100644
index 00000000..65545b71
Binary files /dev/null and b/public/img/community/mvps/mvp-sai-nageshwaran.jpg differ
diff --git a/public/img/community/mvps/mvp-scott-davis.jpg b/public/img/community/mvps/mvp-scott-davis.jpg
new file mode 100644
index 00000000..000842bf
Binary files /dev/null and b/public/img/community/mvps/mvp-scott-davis.jpg differ
diff --git a/public/img/community/mvps/mvp-shashank-shekhar.jpg b/public/img/community/mvps/mvp-shashank-shekhar.jpg
new file mode 100644
index 00000000..6c47a181
Binary files /dev/null and b/public/img/community/mvps/mvp-shashank-shekhar.jpg differ
diff --git a/public/img/community/mvps/mvp-shekhar-shukla.jpg b/public/img/community/mvps/mvp-shekhar-shukla.jpg
new file mode 100644
index 00000000..7998ddde
Binary files /dev/null and b/public/img/community/mvps/mvp-shekhar-shukla.jpg differ
diff --git a/public/img/community/mvps/mvp-shraddha-shetty.jpg b/public/img/community/mvps/mvp-shraddha-shetty.jpg
new file mode 100644
index 00000000..7e8cd743
Binary files /dev/null and b/public/img/community/mvps/mvp-shraddha-shetty.jpg differ
diff --git a/public/img/community/mvps/mvp-shubham-kumar.jpg b/public/img/community/mvps/mvp-shubham-kumar.jpg
new file mode 100644
index 00000000..c42a43c6
Binary files /dev/null and b/public/img/community/mvps/mvp-shubham-kumar.jpg differ
diff --git a/public/img/community/mvps/mvp-simon-whiteley.jpg b/public/img/community/mvps/mvp-simon-whiteley.jpg
new file mode 100644
index 00000000..4a650236
Binary files /dev/null and b/public/img/community/mvps/mvp-simon-whiteley.jpg differ
diff --git a/public/img/community/mvps/mvp-soufiane-darraz.jpg b/public/img/community/mvps/mvp-soufiane-darraz.jpg
new file mode 100644
index 00000000..3cc12923
Binary files /dev/null and b/public/img/community/mvps/mvp-soufiane-darraz.jpg differ
diff --git a/public/img/community/mvps/mvp-soumya-ghosh.jpg b/public/img/community/mvps/mvp-soumya-ghosh.jpg
new file mode 100644
index 00000000..0131a5e2
Binary files /dev/null and b/public/img/community/mvps/mvp-soumya-ghosh.jpg differ
diff --git a/public/img/community/mvps/mvp-srivathsan-rl.jpg b/public/img/community/mvps/mvp-srivathsan-rl.jpg
new file mode 100644
index 00000000..6a556a9f
Binary files /dev/null and b/public/img/community/mvps/mvp-srivathsan-rl.jpg differ
diff --git a/public/img/community/mvps/mvp-steve-notley.jpg b/public/img/community/mvps/mvp-steve-notley.jpg
new file mode 100644
index 00000000..5a56c145
Binary files /dev/null and b/public/img/community/mvps/mvp-steve-notley.jpg differ
diff --git a/public/img/community/mvps/mvp-subramanian-iyer.jpg b/public/img/community/mvps/mvp-subramanian-iyer.jpg
new file mode 100644
index 00000000..ddfc3944
Binary files /dev/null and b/public/img/community/mvps/mvp-subramanian-iyer.jpg differ
diff --git a/public/img/community/mvps/mvp-sudarshan-koirala.jpg b/public/img/community/mvps/mvp-sudarshan-koirala.jpg
new file mode 100644
index 00000000..bdeb4838
Binary files /dev/null and b/public/img/community/mvps/mvp-sudarshan-koirala.jpg differ
diff --git a/public/img/community/mvps/mvp-sudhir-gajre.jpg b/public/img/community/mvps/mvp-sudhir-gajre.jpg
new file mode 100644
index 00000000..d90c718a
Binary files /dev/null and b/public/img/community/mvps/mvp-sudhir-gajre.jpg differ
diff --git a/public/img/community/mvps/mvp-tejas-pandit.jpg b/public/img/community/mvps/mvp-tejas-pandit.jpg
new file mode 100644
index 00000000..aee3f599
Binary files /dev/null and b/public/img/community/mvps/mvp-tejas-pandit.jpg differ
diff --git a/public/img/community/mvps/mvp-vipul-choudhary.jpg b/public/img/community/mvps/mvp-vipul-choudhary.jpg
new file mode 100644
index 00000000..1d482470
Binary files /dev/null and b/public/img/community/mvps/mvp-vipul-choudhary.jpg differ
diff --git a/public/img/community/mvps/mvp-vitalija-bartuseviciute.jpg b/public/img/community/mvps/mvp-vitalija-bartuseviciute.jpg
new file mode 100644
index 00000000..bb405db0
Binary files /dev/null and b/public/img/community/mvps/mvp-vitalija-bartuseviciute.jpg differ
diff --git a/public/img/community/mvps/mvp-yash-mahendra-joshi.jpg b/public/img/community/mvps/mvp-yash-mahendra-joshi.jpg
new file mode 100644
index 00000000..44bd3253
Binary files /dev/null and b/public/img/community/mvps/mvp-yash-mahendra-joshi.jpg differ
diff --git a/public/img/community/mvps/mvp-yuki-saito.jpg b/public/img/community/mvps/mvp-yuki-saito.jpg
new file mode 100644
index 00000000..10a8813f
Binary files /dev/null and b/public/img/community/mvps/mvp-yuki-saito.jpg differ
diff --git a/public/img/community/mvps/mvp-zoe-van-noppen.jpg b/public/img/community/mvps/mvp-zoe-van-noppen.jpg
new file mode 100644
index 00000000..a12e85d8
Binary files /dev/null and b/public/img/community/mvps/mvp-zoe-van-noppen.jpg differ
diff --git a/public/img/community/select-arrow.svg b/public/img/community/select-arrow.svg
new file mode 100644
index 00000000..b14b9739
--- /dev/null
+++ b/public/img/community/select-arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/img/community/student-badge.svg b/public/img/community/student-badge.svg
new file mode 100644
index 00000000..a7bc7dd8
--- /dev/null
+++ b/public/img/community/student-badge.svg
@@ -0,0 +1,89 @@
+
diff --git a/public/img/community/x.svg b/public/img/community/x.svg
new file mode 100644
index 00000000..44dca332
--- /dev/null
+++ b/public/img/community/x.svg
@@ -0,0 +1,10 @@
+
diff --git a/scripts/normalize-appkit-doc-links.mjs b/scripts/normalize-appkit-doc-links.mjs
new file mode 100644
index 00000000..53a948ce
--- /dev/null
+++ b/scripts/normalize-appkit-doc-links.mjs
@@ -0,0 +1,32 @@
+export function normalizeSyncedDocLinks(
+ source,
+ { channel, appKitErrorSource = "" },
+) {
+ let updated = source
+ .replaceAll("](/docs/api/", `](/docs/appkit/${channel}/api/`)
+ .replaceAll(
+ "(./lakebase.md#on-behalf-of-obo--per-user-connections)",
+ "(./lakebase.md#on-behalf-of-obo-per-user-connections)",
+ );
+
+ // DevHub strips the leading underscore: the protected field gets
+ // clientmessage and the later public accessor gets clientmessage-1.
+ // Match the member label too, so a cached sync cannot remap the field
+ // link to the accessor on its second run. Older channels may lack the field.
+ if (
+ /^### \\_clientMessage\?\r?$/m.test(appKitErrorSource) &&
+ /^### clientMessage\r?$/m.test(appKitErrorSource)
+ ) {
+ updated = updated
+ .replaceAll(
+ "[`_clientMessage`](Class.AppKitError.md#_clientmessage)",
+ "[`_clientMessage`](Class.AppKitError.md#clientmessage)",
+ )
+ .replaceAll(
+ "[`clientMessage`](Class.AppKitError.md#clientmessage)",
+ "[`clientMessage`](Class.AppKitError.md#clientmessage-1)",
+ );
+ }
+
+ return updated;
+}
diff --git a/scripts/sync-appkit-docs.mjs b/scripts/sync-appkit-docs.mjs
index b40d37c8..6d8b7c87 100644
--- a/scripts/sync-appkit-docs.mjs
+++ b/scripts/sync-appkit-docs.mjs
@@ -4,6 +4,8 @@ import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
+import { normalizeSyncedDocLinks } from "./normalize-appkit-doc-links.mjs";
+
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "..");
@@ -109,6 +111,7 @@ function walkFiles(root) {
}
function normalizeSyncedDocs(docsRoot) {
+ const appKitErrorSources = new Map();
const upstreamLlmsLinkHelper =
/import\s+\w+Context\s+from\s+["'][^"']+["'];\n\nexport function LlmsTxtLink\([\s\S]*?^}\n\n/gm;
const upstreamSidebarConfigImport =
@@ -150,23 +153,28 @@ type TypedocSidebar = {
.replace(upstreamLlmsLinkHelper, "")
.replaceAll("
- We know this isn't where you intended to land, but we hope - you have some fun while you're here. -
- -Please try again in a moment.
+ ++ {mvp + ? "Meet experts who share knowledge, build community, and grow the Databricks ecosystem." + : "Meet the students building, learning, and shaping the future of data and AI."} +
++ {people.total} {kind === "student" ? "student fellows" : "MVPs"} + {query.q ? ` matching “${query.q}”` : ""} +
+ {people.items.length ? ( ++ Try another search or clear your filters. +
+ ++ {person.organization || person.headline} +
+ ) : null} + > + ); + return ( ++ + + [{person.country}] + +
+ ) : ( + + )} ++ {title === "Share Your\nExpertise" ? ( + <> + Get opportunities to share your expertise at events, like{" "} + + Data + AI Summit + + . + > + ) : ( + description + )} +
+
+ Not a fellow yet?
+
+ Apply today
+
+ {mvp + ? "Recognizing those who share knowledge and grow the community." + : "Learn from Databricks experts and build real-world data and AI skills."} +
+diff --git a/src/components/header/mobile-nav.tsx b/src/components/header/mobile-nav.tsx index bca836b8..e8f1efb7 100644 --- a/src/components/header/mobile-nav.tsx +++ b/src/components/header/mobile-nav.tsx @@ -6,10 +6,8 @@ import { usePathname } from "next/navigation"; import { ArrowUpRight } from "lucide-react"; import { - getActiveProductHref, isExternalHref, isHeaderNavItemActive, - PRODUCT_LINKS, type HeaderNavItem, } from "@/lib/header-navigation"; import { cn } from "@/lib/utils"; @@ -85,10 +83,6 @@ function MobileMenuButton({ ); } -function MobileTreeLine({ className }: { className: string }) { - return ; -} - function MobileTreeText({ active = false, activeFill = "content", @@ -149,10 +143,13 @@ export function MobileNav({ }: MobileNavProps) { const menuId = useId(); const pathname = usePathname() ?? "/"; - const activeProductHref = getActiveProductHref(pathname); const isHomeActive = pathname === "/"; - const productItem = items.find(({ label }) => label === "Product"); - const sectionItems = items.filter(({ label }) => label !== "Product"); + let nextTop = 46; + const positionedItems = items.map((item) => { + const top = nextTop; + nextTop += item.links ? 32 + item.links.length * 34 : 34; + return { item, top }; + }); useEffect(() => { onOpenChange(false); @@ -246,7 +243,7 @@ export function MobileNav({ }; }, [onOpenChange, open]); - if (!productItem || items.length === 0) { + if (items.length === 0) { return null; } @@ -272,18 +269,13 @@ export function MobileNav({