Skip to content

Pages and Features

umutxyp edited this page Oct 17, 2026 · 2 revisions

Pages and Features

A tour of everything the site does: each page, the live parts, search and sharing, and the API routes. Settings mentioned here are described in full on Configuration.

How the site is put together


The pages

Home: /

  • A large headline (hero.headline) and a subline under it (hero.subline). The subline can contain live numbers and **bold** text.
  • An optional featured badge above the headline (home.featured.display, off by default).
  • A button to the About page, with your avatar and the About page title.
  • A newsletter block at the bottom when newsletter.display is true (off by default).
  • If /blog is switched on in routes, a "Latest from the blog" section that reads posts from src/app/blog/posts/. The repository does not include blog posts or blog pages.

About: /about

From top to bottom:

  1. Avatar (if about.avatar.display), your name and role.
  2. Your time zone next to a globe icon (person.timezone).
  3. Language tags (person.languages).
  4. Social links as buttons. On small screens they become icon-only buttons.
  5. A "Schedule a call" pill (if about.calendar.display).
  6. Intro (about.intro), Work Experience, Studies and Technical focus. Each section can be hidden in content.tsx.

Intro text and experience achievements support live numbers and **bold**.

Work: /work

One card per .mdx file in src/app/work/projects/. Each card shows:

  • the cover image (a live screenshot when available),
  • the title and summary,
  • Read case study (only when the file has text after its front matter),
  • View project (only when the file has a link).

Cards are sorted by the order field, lowest first. Projects without order come last, newest publishedAt first. See Adding Projects.

Case study: /work/<slug>

The slug is the file name without .mdx. The page shows:

  • a "Projects" link back to /work, the publish date and the title,
  • team avatars and names (each name links to the member's linkedIn URL),
  • the cover image (16:10),
  • the MDX content, with live numbers filled in,
  • a Visit <title> button when link is set,
  • a Related projects list: the other projects in /work order, except the first of them (the page asks for range={[2]}).

All case study pages are generated at build time.

Gallery: /gallery

A masonry grid of the images listed in siteData.gallery: two columns on wide screens, one column on phones. By default it shows the live screenshots of all eight example projects.

GitHub: /github

  • Pinned work: the repositories pinned on your GitHub profile, in the same order. The site reads them from your public profile page, because the GitHub REST API does not expose pins. If that fails, it uses github.highlight instead. Pinned repositories owned by an organisation are left out, because they are not in your own repository list.
  • Other repositories: all your other public repositories (up to 100), most stars first.
  • Each card shows the name, description (or "This project ships without a description yet."), language with GitHub's colour dot, stars, forks and the last update date.
  • Data is cached for one hour.

If GitHub returns nothing, the page shows: "GitHub rate limits prevented loading repositories. Try again in a few minutes."

404

Any unknown page, and any page switched off in routes, shows "404 – Page Not Found".


Theme and layout

  • Header: a floating bar with a button for each enabled page and, if display.themeSwitcher is on, a light/dark toggle. On screens 768 px wide or less it sits at the bottom of the screen and the buttons show icons only (Home keeps its label).
  • Footer: © <year> umutxyp and an icon for each social link.
  • Light and dark mode: on the first visit the site follows the visitor's system setting. The toggle switches between light and dark and the choice is remembered in the browser (localStorage, key data-theme). The style.theme value in the config is not read by the start-up script.
  • Look: colours, borders, surfaces and scaling come from style; the background (dots by default) comes from effects.

Live numbers

Text can contain tokens like %beatra.servers% or %mcstat.players%. When a page is built, src/lib/live-stats.ts replaces them with current numbers.

Where tokens work: hero.subline, about.introDescription, every experience achievement, and a project's summary and MDX content.

Where the numbers come from: stat tiles on codeshare.me, the author's studio site. Each tile is HTML of the form <dd>value</dd><dt>label</dt>. The code knows these pages and labels:

Token prefix Page read Keys
studio / products, servers, users, players
beatra /projects/beatra servers, users, playing
sylon /projects/sylon servers, users, uptime
mcstat /projects/mcstat servers, players, skins, capes
justdiscord /projects/justdiscord servers, bots, emojis, visitors
justanime /projects/justanime titles, characters, schedule

How it behaves:

  • Numbers are read at build time and refreshed every 7 days.
  • If a page cannot be read, the last known values stored in the code (FALLBACK) are used, and the log shows live stats: https://codeshare.me/... unreadable, using last known values: ....
  • An unknown token (for example a typo) is left in the text as it is.

For your own portfolio you have two choices:

  1. Write plain numbers. Remove the tokens from your text. Nothing else is needed.
  2. Use your own source. In src/lib/live-stats.ts, change SOURCE to your site, describe your pages and labels in SOURCES, and set starting values in FALLBACK. Your pages must contain the same <dd>value</dd><dt>label</dt> markup.

Live project screenshots

Each project's cover can be a real screenshot of its website, served from /screenshots/<slug>.

When a project gets one: its front matter does not say screenshot: false, it has a link (or screenshotUrl), and it has at least one entry in images. The first image is the fallback.

How a capture works (src/app/screenshots/[slug]/route.ts):

  1. Chromium opens the page at 1600 × 1000 (scale 1.25, so the image is 2000 × 1250), in dark mode with reduced motion.
  2. It waits up to 25 seconds for the page to load, then up to 8 seconds for the network to go quiet.
  3. It hides cookie and consent banners, waits 2.5 seconds for late popups, presses Escape, then hides dialogs, full-screen overlays and anything pinned to the lower half of the screen.
  4. It refuses pages that look like a bot check or a consent wall (for example "Just a moment", "Verify you are human").
  5. It saves a JPEG at quality 80.

When it runs: every screenshot is taken during the build and refreshed in the background once a week.

When it fails:

  • During next build or next dev, the route serves the project's first image from public/ instead.
  • During a weekly refresh, the last good screenshot is kept and the capture is retried later.
  • Either way the log shows screenshot <slug> <- <url> failed: <reason>.

The covers are used on /work, on case study pages and in the gallery.


Password-protected pages

  1. Add the page to protectedRoutes in once-ui.config.ts, for example "/about": true.
  2. Set PAGE_ACCESS_PASSWORD in .env.local or in your host's settings.

Visitors then see "This page is password protected" with a password field. The password is sent to POST /api/authenticate; if it is right, the server sets an authToken cookie for one hour and the page appears. A wrong password shows "Incorrect password".

Warning: This is a light gate for things like a draft page. It is checked in the browser by RouteGuard, and the cookie value is the fixed text authenticated. Do not use it to hide anything secret.


Search and sharing

Feature Where
Page title, description and Open Graph tags Home, About, Work, case studies and Gallery, through Once UI's Meta.generate. /github sets its own title and description.
Schema.org data Every page except the 404 page, through Once UI's Schema (webPage, or blogPosting for case studies)
Generated Open Graph images /api/og/generate?title=...
Sitemap /sitemap.xml: enabled routes, every case study, and blog posts if any
Robots /robots.txt: allows all crawlers and links the sitemap
RSS feed /api/rss: reads src/app/blog/posts/, which does not exist in this repository, so the feed has no items

Open Graph images are 1280 × 720 PNGs with a dark background, the page title, your avatar, your name and your role. The Geist font is downloaded from Google Fonts each time an image is made, and the avatar is loaded from baseURL, so set meta.baseURL to your own domain.


API routes

Route Method What it does
/api/authenticate POST Body {"password": "..."}. Returns 200 {"success": true} and sets the authToken cookie, 401 {"message": "Incorrect password"}, or 500 if PAGE_ACCESS_PASSWORD is not set.
/api/check-auth GET 200 {"authenticated": true} if the cookie is present, otherwise 401 {"authenticated": false}.
/api/og/generate GET ?title= → a 1280 × 720 PNG. Title defaults to Portfolio.
/api/rss GET RSS 2.0 feed (see above). Every value is XML-escaped, and the post summary is escaped text rather than a CDATA block, so &, < or quotes in a title, summary or tag do not break the feed.
/screenshots/<slug> GET The project's screenshot as JPEG (see above).

Note: There is no /api/og/fetch or /api/og/proxy. Those routes came with the Once UI template and fetched whatever URL they were given; nothing on the site used them, so they were removed. Once UI's OgCard link preview loads its data from those two routes, so it does not work here unless you give it the preview yourself (see Troubleshooting).


Redirects

next.config.mjs permanently redirects /work/code-share-marketplace to /work/codeshare-technology. It exists for an old link of the author's and is safe to remove in your copy.

Clone this wiki locally