Commit Graph

98 Commits

Author SHA1 Message Date
Ilia Mashkov cb3bdce24a feat: tag all PocketBase fetches for ISR cache invalidation
Each getCollection/getFirstRecord call now passes the collection name
as a cache tag so revalidateTag can target individual collections.
2026-05-18 21:34:43 +03:00
Ilia Mashkov 42ca683c65 feat: add tags/revalidate options to PocketBase fetch client
PB_URL falls back through PB_URL → NEXT_PUBLIC_PB_URL → localhost so
internal Docker hostname is used server-side without leaking into the
client bundle. cache: force-cache replaced with next: { tags, revalidate }
for ISR tag-based invalidation.
2026-05-18 21:34:34 +03:00
Ilia Mashkov fea6682024 feat: switch to standalone output with PocketBase remotePatterns
Drops static export (STATIC_EXPORT env var) in favour of standalone
for ISR. Images remotePatterns reads PB_HOSTNAME/PB_PORT env vars so
Docker internal hostname works without hardcoding.
2026-05-18 21:34:25 +03:00
Ilia Mashkov 540df57f8d feat: add 404 page with centered layout
not-found.tsx renders oversized Fraunces heading with a back link.
Body gets flex flex-col min-h-screen so main can flex-1 to fill
available height without pushing the footer off screen.
2026-05-18 20:46:22 +03:00
Ilia Mashkov b88263a65a fix: DetailedProjectCard — render description as RichText 2026-05-18 20:46:13 +03:00
Ilia Mashkov 06e39b58c6 refactor: ProjectsSection — use shared buildFileUrl, pass url prop, switch to stacked layout 2026-05-18 20:46:02 +03:00
Ilia Mashkov ac9ee0eb4e feat: ProjectCard — add url prop, RichText description, open link in new tab 2026-05-18 20:45:54 +03:00
Ilia Mashkov 2ae5ae3210 feat: wire Footer to PocketBase site_settings
Fetches CV file, email and social links via expand=contacts,contacts.socials.
CV rendered as polymorphic Button with download attr; socials and email
rendered as Link components.
2026-05-18 20:45:44 +03:00
Ilia Mashkov f159c6e861 feat: add SocialRecord, ContactsRecord, SiteSettingsRecord API types
Models PocketBase relations: SiteSettings → contacts → ContactsRecord
→ socials[] → SocialRecord. expand fields typed as optional resolved
records for use with PocketBase expand query param.
2026-05-18 20:45:32 +03:00
Ilia Mashkov b33b9f328c feat: add Link shared component
Renders Next.js Link for internal routes, plain anchor with
target="_blank" rel="noopener noreferrer" when external prop is set.
2026-05-18 20:45:17 +03:00
Ilia Mashkov c9631f9905 feat: add buildFileUrl utility with tests
Moved from ProjectsSection inline function to shared/lib/utils.
Accepts optional baseUrl for testability without env mocking.
2026-05-18 20:45:06 +03:00
Ilia Mashkov ba7395cb32 feat: make Button polymorphic — renders <a> when href is provided
Discriminated union types (AsButton | AsAnchor), isAnchorProps type guard
eliminates all 'as' casts. as const satisfies for VARIANTS/SIZES lookup
tables. brutal-border replaces border-[3px] in ghost variant.
2026-05-18 20:44:50 +03:00
Ilia Mashkov 7e542597d0 feat: Footer widget with email link and CV download, added to root layout 2026-05-18 14:15:25 +03:00
Ilia Mashkov 0552a2a8e5 refactor: register text-section-title in @theme inline, use as plain utility class 2026-05-18 14:06:01 +03:00
Ilia Mashkov d955aeb628 refactor: replace inline style with Tailwind class and font-wonk utility 2026-05-18 14:04:56 +03:00
Ilia Mashkov b40ff4f588 fix: fluid section title with clamp() to prevent wrapping below 900px 2026-05-18 14:02:03 +03:00
Ilia Mashkov 531de6899e refactor: ProjectCard sm button, left-border year matching ExperienceCard style 2026-05-18 13:20:47 +03:00
Ilia Mashkov 10034ec561 refactor: ProjectCard sidebar layout — year, tags, button in sidebar 2026-05-18 13:14:40 +03:00
Ilia Mashkov 458ee0e449 refactor: CardSidebar layout breakpoint md → lg for wider description area 2026-05-18 13:11:53 +03:00
Ilia Mashkov 979e2071d1 refactor: widen section and sidebar, plain period text, Badge xs size for stack 2026-05-18 13:07:01 +03:00
Ilia Mashkov 37098be3c8 feat: Badge size prop (sm/md) and use Badge in ExperienceCard 2026-05-18 13:02:07 +03:00
Ilia Mashkov 48a08ec3fb feat: formatMonthYearRange — period now includes abbreviated month 2026-05-18 13:01:58 +03:00
Ilia Mashkov 1550989fd9 feat: CardSidebar layout component and ExperienceCard sidebar redesign
Sidebar: period badge, company, stack tags.
Main: role title and rich-text description.
2026-05-18 12:51:33 +03:00
Ilia Mashkov 782c619a91 feat: ExperienceCard stack field and Card subcomponent layout 2026-05-18 12:39:41 +03:00
Ilia Mashkov 543020f85c feat: apply Fraunces font to ProjectCard title 2026-05-18 12:39:33 +03:00
Ilia Mashkov e00c1460e1 refactor: responsive spacing on CardHeader and CardFooter 2026-05-18 12:39:20 +03:00
Ilia Mashkov f874a943ff fix: a11y — accessible label on SectionAccordion, opacity-60 on category headings 2026-05-18 12:39:07 +03:00
Ilia Mashkov ff62cba5b1 feat: add line-height-relaxed token and text selection/focus-visible styles 2026-05-18 12:38:28 +03:00
Ilia Mashkov f4986d6657 chore: split React import to satisfy linter in ViewTransitionWrapper 2026-05-18 12:38:17 +03:00
Ilia Mashkov e3959c0e45 fix: add cursor-pointer to Button 2026-05-18 12:38:10 +03:00
Ilia Mashkov 76f5b269f8 refactor: use shadow theme tokens, remove ProjectCard translate-hover
Replace inline var(--blue) arbitrary shadow values with typed theme
tokens (shadow-brutal-xl, shadow-brutal-2xl). Remove translate on
ProjectCard hover — shadow-only interaction is less distracting in
a dense grid layout.
2026-05-16 19:04:37 +03:00
Ilia Mashkov b8b5e65497 feat: constrain section content width with max-w-section
Adds max-w-section (56rem via --container-section token) to the
experience, projects, and skills section wrappers for consistent
readable line length across all content areas.
2026-05-16 19:04:27 +03:00
Ilia Mashkov e63de14515 feat: apply RichText to content sections and experience cards
ExperienceCard description switches from a plain <p> to RichText so
rich-text HTML from PocketBase renders correctly. BioSection and
IntroSection drop the prose class overrides — RichText handles
typography consistently.
2026-05-16 19:04:18 +03:00
Ilia Mashkov dfc3ed4715 feat: editorial typography via RichText component
Always wraps content in .rich-text: max-width 65ch, onum figures,
hanging punctuation, pretty text-wrap, auto hyphens, 1.65 line-height,
and 1.2em paragraph spacing. className prop merges additonal classes.
2026-05-16 19:04:08 +03:00
Ilia Mashkov a77cd43749 feat: Button elevation hover/active effect with snap shadow
Variants now use brutal shadow tokens. On hover the button translates
up-left (−0.5px), on active down-right (+0.5px). Only transform animates
(130ms ease-out); shadow snaps instantly so the eye reads button movement
not shadow resize. Primary keeps rgba alpha shadow; secondary/outline use
solid brutal tokens.
2026-05-16 19:04:00 +03:00
Ilia Mashkov 8db4f81f70 refactor: simplify section body animation to hard-cut on navigation 2026-05-16 19:03:50 +03:00
Ilia Mashkov f1049624f7 refactor: design tokens — shadow scale, animation timing, section width
- Expand brutal shadow scale: xs (1px) through 2xl (12px)
- Add --ease-micro cubic-bezier for fast micro-interactions
- Tune --duration-normal 200ms→150ms, --duration-spring 380ms→220ms
- Add --section-content-width and register as --container-section in @theme inline
- Register all brutal shadow tokens in @theme inline for Tailwind utility generation
- Add .btn-transition utility (transform-only, shadow snaps instantly)
- Add .rich-text editorial typography class with magazine-quality settings
- Remove section-body blur-out/slide-in view transition animations
2026-05-16 19:03:43 +03:00
Ilia Mashkov 92e4a01641 refactor: group experience/ui components into subdirectories 2026-05-13 09:40:09 +03:00
Ilia Mashkov 9cf8caaead refactor: group project/ui components into subdirectories 2026-05-13 09:40:00 +03:00
Ilia Mashkov e518fc46a9 feat: section body animation with blur-out, delayed enter, and animation tokens
Add animation tokens to :root (--ease-spring, --ease-decelerate,
--ease-default, --duration-fast/normal/slow/spring). Apply spring easing
to section title enter. Add separate section-body transition: fast
blur-out exit (100ms), clean slide-in enter (350ms) delayed by 200ms so
content appears after the title animation completes.
2026-05-13 09:39:47 +03:00
Ilia Mashkov 481dda3c95 fix: resolve inactive section title hover opacity conflict
hover:opacity-60 on Link and opacity-30/group-hover:opacity-50 on h2
were multiplying (0.6 × 0.5 = 0.30 = base), making hover invisible.
Removed opacity from Link, consolidated to h2 only: opacity-30 base,
group-hover:opacity-60 on hover.
2026-05-13 09:39:08 +03:00
Ilia Mashkov d28343e22c feat: section open/close animations via ViewTransition and @starting-style
Enable experimental.viewTransition in Next.js config. Wrap active section
in ViewTransitionWrapper so the browser cross-fades between sections on
navigation. Replace animate-fadeIn keyframe with @starting-style + CSS
transition for the initial render enter animation.
2026-05-12 16:10:50 +03:00
Ilia Mashkov 7cba3053f4 feat: ViewTransitionWrapper shared component with stable react-dom fallback
Wraps children in React's ViewTransition (canary API) when available,
falling back to Fragment in environments where ViewTransition is undefined
(test env, stable react-dom). Add react/canary to tsconfig types to
expose the ViewTransition component type.
2026-05-12 16:10:37 +03:00
Ilia Mashkov 0090718869 fix: add outline to primary and secondary button variants 2026-05-12 13:58:29 +03:00
Ilia Mashkov 301e7a2555 feat: RichText component for safe PocketBase HTML rendering
Add html-react-parser-backed RichText component that converts HTML
strings from PocketBase rich-text fields into React elements without
dangerouslySetInnerHTML. Replace raw <p> render in IntroSection and
BioSection, and drop the invalid slug filters those collections lacked.
2026-05-12 13:58:17 +03:00
Ilia Mashkov 0a99a37bca fix: remove underline from collapsed section title links
Global a { border-bottom } was leaking onto the inactive section
nav links. Override with border-b-0 hover:border-b-0.
2026-05-12 13:57:39 +03:00
Ilia Mashkov e8bf8b502e fix: align PocketBase type definitions with actual schema
Remove slug field from PageContentRecord (intro/bio collections have none).
Remove number field from SectionRecord (not stored in PocketBase); derive
zero-padded display number from the order field at render time.
2026-05-12 13:57:25 +03:00
Ilia Mashkov 30f8e4be95 design: two-color palette — rename all tokens to --cream / --blue
Replace ochre-clay, carbon-black, burnt-oxide, slate-indigo with clean
two-color system: --cream (#f4f0e8) and --blue (#041cf3). Update every
component, utility class, and test assertion.
2026-05-11 12:59:32 +03:00
Ilia Mashkov fed9c97ddb feat: URL-driven catchall routing, drop sidebar nav, split export build
- app/[[...slug]]/page.tsx replaces app/page.tsx; activeSlug from URL params
- SidebarNav and MobileNav removed from main layout (sections accordion is the nav)
- next.config.ts: output:export controlled by STATIC_EXPORT env var instead of NODE_ENV
- package.json: yarn build is standard Next.js build; yarn export is STATIC_EXPORT=true
- Mock API route: force-static + generateStaticParams for output:export compatibility
2026-05-11 11:12:21 +03:00
Ilia Mashkov af165ec356 feat: MobileNav section items use Link, close menu on pathname change 2026-05-11 11:11:53 +03:00