From f39ff829e8c9b69ba741ab15d7e02f391233a640 Mon Sep 17 00:00:00 2001 From: Christian Cito <30470476+chrcit@users.noreply.github.com> Date: Mon, 23 Dec 2024 13:49:01 +0100 Subject: [PATCH] refactor: wip remix port --- .gitignore | 2 + app/components/ErrorBoundary.tsx | 111 + app/components/Footer.tsx | 32 + app/components/Header.tsx | 74 + app/components/Particles.tsx | 85 + app/components/RelatedContent.tsx | 55 + app/components/SocialIcon.tsx | 69 + app/components/SocialLinks.tsx | 33 + app/components/Toast.tsx | 113 + app/components/embeds/EmbedOverlay.tsx | 57 + app/components/embeds/InstagramEmbed.tsx | 83 + app/components/embeds/RedditEmbed.tsx | 49 + app/components/embeds/TwitterEmbed.tsx | 58 + app/components/embeds/YouTubeEmbed.tsx | 32 + app/components/embeds/index.ts | 4 + app/components/layouts/ArticleLayout.tsx | 105 + app/components/layouts/ArticleListLayout.tsx | 66 + app/components/layouts/BaseLayout.tsx | 24 + app/components/layouts/BookLayout.tsx | 126 + app/components/layouts/BookListLayout.tsx | 93 + app/components/layouts/ProjectLayout.tsx | 84 + app/components/layouts/ProjectListLayout.tsx | 75 + app/components/layouts/RootLayout.tsx | 79 + app/components/mdx/index.tsx | 133 + app/data/socials.ts | 25 + app/entry.client.tsx | 7 + app/entry.server.tsx | 129 + app/hooks/useFocusManagement.ts | 65 + app/hooks/useKeyboardNavigation.ts | 71 + app/root.tsx | 118 + app/routes/_index.tsx | 35 + app/routes/api.embed-consent.ts | 27 + app/routes/articles.$slug.tsx | 33 + app/routes/articles._index.tsx | 14 + app/routes/books.$slug.tsx | 39 + app/routes/books._index.tsx | 14 + app/routes/feed[.]xml.ts | 41 + app/routes/projects.$slug.tsx | 34 + app/routes/projects._index.tsx | 14 + app/routes/sitemap[.]xml.ts | 74 + app/styles/tailwind.css | 13 + app/utils/content-relations.ts | 92 + app/utils/content.ts | 38 + app/utils/embed-consent.ts | 47 + app/utils/navigation.ts | 19 + app/utils/structured-data.ts | 85 + app/utils/theme.server.ts | 30 + .../astro.config.mjs | 0 .../package-lock.json | 0 .../src}/components/BackButton.astro | 0 .../src}/components/ExternalLink.astro | 0 .../src}/components/Footer.astro | 0 .../src}/components/Header.astro | 0 .../src}/components/ListHeader.astro | 0 .../src}/components/Particles.astro | 0 .../src}/components/ReadMoreButton.astro | 0 .../src}/components/SkipToContent.astro | 0 .../src}/components/SocialIcon.astro | 0 .../src}/components/SocialLinks.astro | 0 .../src}/components/TableOfContents.astro | 0 .../components/TableOfContentsHeading.astro | 0 .../embeds/AndererseitsInstagram.astro | 0 .../src}/components/icons/ArrowLeft.astro | 0 .../src}/components/icons/ArrowRight.astro | 0 .../src}/components/particles.json | 0 .../content/articles/2023-year-in-review.mdx | 0 .../der-wanderer-ueber-dem-nebelmeer.jpg | Bin .../src}/content/books/a-liberated-mind.md | 0 .../src}/content/books/antifragile.md | 0 .../src}/content/books/black-swan.md | 0 .../src}/content/books/brave-new-world.md | 0 .../books/breaking-out-of-homeostasis.md | 0 .../src}/content/books/capitalist-realism.md | 0 .../books/covers/a-liberated-mind-cover.jpg | Bin .../books/covers/antifragile-cover.jpg | Bin .../books/covers/brave-new-world-cover.jpeg | Bin .../breaking-out-of-homeostasis-cover.jpg | Bin .../books/covers/capitalist-realism-cover.jpg | Bin .../books/covers/dark-money-cover.jpeg | Bin .../debt-the-first-5000-years-cover.jpg | Bin .../src}/content/books/covers/flow-cover.jpg | Bin .../covers/fooled-by-randomness-cover.jpg | Bin .../content/books/covers/gateless-cover.jpg | Bin ...ote-this-book-because-i-love-you-cover.jpg | Bin ...die-ideologie-des-werbekoerpers-cover.webp | Bin .../books/covers/kill-all-normies-cover.webp | Bin .../books/covers/less-is-more-cover.webp | Bin .../covers/mans-search-for-meaning-cover.jpg | Bin .../books/covers/of-mice-and-men-cover.jpg | Bin .../books/covers/seeing-that-frees-cover.jpg | Bin .../books/covers/skin-in-the-game-cover.jpg | Bin .../covers/survival-of-the-richest-cover.jpg | Bin .../covers/the-art-of-learning-cover.jpg | Bin .../books/covers/the-black-swan-cover.webp | Bin .../the-count-of-monte-cristo-cover.jpg | Bin .../content/books/covers/the-divide-cover.jpg | Bin .../covers/the-mind-illuminated-cover.jpg | Bin .../covers/the-paleo-manifesto-cover.jpg | Bin .../the-science-of-enlightenment-cover.jpg | Bin .../books/covers/vagabonding-cover.jpg | Bin .../books/covers/we-learn-nothing-cover.jpg | Bin .../books/covers/winners-take-all-cover.jpg | Bin .../src}/content/books/dark-money.md | 0 .../books/debt-the-first-5000-years.md | 0 {src => astro-site/src}/content/books/flow.md | 0 .../content/books/fooled-by-randomness.md | 0 .../src}/content/books/gateless.md | 0 .../i-wrote-this-book-because-i-love-you.md | 0 ...luencer-die-ideologie-des-werbekoerpers.md | 0 .../src}/content/books/kill-all-normies.md | 0 .../src}/content/books/less-is-more.md | 0 .../content/books/mans-search-for-meaning.md | 0 .../src}/content/books/of-mice-and-men.md | 0 .../src}/content/books/seeing-that-frees.md | 0 .../src}/content/books/skin-in-the-game.md | 0 .../content/books/survival-of-the-richest.md | 0 .../src}/content/books/the-art-of-learning.md | 0 .../books/the-count-of-monte-cristo.md | 0 .../src}/content/books/the-divide.md | 0 .../content/books/the-mind-illuminated.md | 0 .../src}/content/books/the-paleo-manifesto.md | 0 .../books/the-science-of-enlightenment.md | 0 .../src}/content/books/vagabonding.md | 0 .../src}/content/books/we-learn-nothing.md | 0 .../src}/content/books/winner-takes-all.md | 0 {src => astro-site/src}/content/config.ts | 0 .../src}/content/films/palm-springs.md | 0 .../src}/content/musicians/ski-aggu.md | 0 .../src}/content/pages/colophon.mdx | 0 .../src}/content/pages/imprint.md | 0 .../src}/content/pages/privacy-policy.md | 0 {src => astro-site/src}/content/pages/uses.md | 0 .../src}/content/projects/hasanhub-com.mdx | 0 .../src}/content/projects/hausgemacht.mdx | 0 .../hasanhub-plausible-april-may-2022.png | Bin .../images/hasanhub-plausible-august-2022.png | Bin .../hasanhub-plausible-december-2022.png | Bin .../projects/images/hasanhub-screenshot.png | Bin .../images/hausgemacht-screenshot.png | Bin .../hausgemacht-vibechecker-screenshots.png | Bin .../images/mitentscheiden-kabine-clip.gif | Bin .../mitentscheiden-kabine-screenshot.png | Bin .../images/mitentscheiden-results.png | Bin .../images/mitentscheiden-screenshot.png | Bin .../images/mitentscheiden-screenshots.jpg | Bin .../images/mitentscheiden-shareables.jpg | Bin .../preismonitor-plausible-may-july.png | Bin .../images/preismonitor-screenshot.png | Bin .../content/projects/mitentscheiden-at.mdx | 0 .../src}/content/projects/preismonitor-at.mdx | 0 .../src}/content/quotes/write-in-blood.md | 0 .../src}/content/shows/bojack-horseman.md | 0 {src => astro-site/src}/data/socials.ts | 0 {src => astro-site/src}/env.d.ts | 0 .../src}/images/chrcit-favicon.png | Bin {src => astro-site/src}/images/cut-out.png | Bin .../src}/images/home-profile-camera.jpg | Bin .../src}/images/home-profile.jpg | Bin .../src}/images/profile-frontal.jpg | Bin .../src}/layouts/ArticleLayout.astro | 0 .../src}/layouts/BaseLayout.astro | 0 .../src}/layouts/ListLayout.astro | 0 .../src}/layouts/RootLayout.astro | 0 {src => astro-site/src}/pages/[slug].astro | 0 {src => astro-site/src}/pages/articles.astro | 0 .../src}/pages/articles/[slug].astro | 0 {src => astro-site/src}/pages/books.astro | 0 .../src}/pages/books/[slug].astro | 0 {src => astro-site/src}/pages/index.astro | 0 {src => astro-site/src}/pages/projects.astro | 0 .../src}/pages/projects/[slug].astro | 0 .../tailwind.config.mjs | 0 content/articles/2023-year-in-review.mdx | 283 + content/articles/hello-world.mdx | 10 + .../der-wanderer-ueber-dem-nebelmeer.jpg | Bin 0 -> 434154 bytes content/books/a-liberated-mind.md | 11 + content/books/antifragile.md | 11 + content/books/black-swan.md | 11 + content/books/brave-new-world.md | 11 + content/books/breaking-out-of-homeostasis.md | 11 + content/books/capitalist-realism.md | 11 + .../books/covers/a-liberated-mind-cover.jpg | Bin 0 -> 666224 bytes content/books/covers/antifragile-cover.jpg | Bin 0 -> 131148 bytes .../books/covers/brave-new-world-cover.jpeg | Bin 0 -> 352599 bytes .../breaking-out-of-homeostasis-cover.jpg | Bin 0 -> 43721 bytes .../books/covers/capitalist-realism-cover.jpg | Bin 0 -> 203510 bytes content/books/covers/dark-money-cover.jpeg | Bin 0 -> 278463 bytes .../debt-the-first-5000-years-cover.jpg | Bin 0 -> 355209 bytes content/books/covers/flow-cover.jpg | Bin 0 -> 209713 bytes .../covers/fooled-by-randomness-cover.jpg | Bin 0 -> 128481 bytes content/books/covers/gateless-cover.jpg | Bin 0 -> 35598 bytes ...ote-this-book-because-i-love-you-cover.jpg | Bin 0 -> 253315 bytes ...die-ideologie-des-werbekoerpers-cover.webp | Bin 0 -> 79410 bytes .../books/covers/kill-all-normies-cover.webp | Bin 0 -> 115598 bytes content/books/covers/less-is-more-cover.webp | Bin 0 -> 42316 bytes .../covers/mans-search-for-meaning-cover.jpg | Bin 0 -> 139758 bytes .../books/covers/of-mice-and-men-cover.jpg | Bin 0 -> 149443 bytes .../books/covers/seeing-that-frees-cover.jpg | Bin 0 -> 95761 bytes .../books/covers/skin-in-the-game-cover.jpg | Bin 0 -> 515708 bytes .../covers/survival-of-the-richest-cover.jpg | Bin 0 -> 1373886 bytes .../covers/the-art-of-learning-cover.jpg | Bin 0 -> 98123 bytes .../books/covers/the-black-swan-cover.webp | Bin 0 -> 51328 bytes .../the-count-of-monte-cristo-cover.jpg | Bin 0 -> 190004 bytes content/books/covers/the-divide-cover.jpg | Bin 0 -> 35713 bytes .../covers/the-mind-illuminated-cover.jpg | Bin 0 -> 77551 bytes .../covers/the-paleo-manifesto-cover.jpg | Bin 0 -> 160081 bytes .../the-science-of-enlightenment-cover.jpg | Bin 0 -> 148918 bytes content/books/covers/vagabonding-cover.jpg | Bin 0 -> 96479 bytes .../books/covers/we-learn-nothing-cover.jpg | Bin 0 -> 46499 bytes .../books/covers/winners-take-all-cover.jpg | Bin 0 -> 74554 bytes content/books/dark-money.md | 11 + content/books/debt-the-first-5000-years.md | 11 + content/books/flow.md | 11 + content/books/fooled-by-randomness.md | 13 + content/books/gateless.md | 11 + .../i-wrote-this-book-because-i-love-you.md | 11 + ...luencer-die-ideologie-des-werbekoerpers.md | 11 + content/books/kill-all-normies.md | 11 + content/books/less-is-more.md | 11 + content/books/mans-search-for-meaning.md | 11 + content/books/of-mice-and-men.md | 13 + content/books/seeing-that-frees.md | 11 + content/books/skin-in-the-game.md | 11 + content/books/survival-of-the-richest.md | 11 + content/books/the-art-of-learning.md | 11 + content/books/the-count-of-monte-cristo.md | 11 + content/books/the-divide.md | 11 + content/books/the-mind-illuminated.md | 11 + content/books/the-paleo-manifesto.md | 11 + content/books/the-science-of-enlightenment.md | 13 + content/books/vagabonding.md | 11 + content/books/we-learn-nothing.md | 11 + content/books/winner-takes-all.md | 11 + content/config.ts | 100 + content/films/palm-springs.md | 5 + content/musicians/ski-aggu.md | 4 + content/pages/colophon.mdx | 26 + content/pages/imprint.md | 10 + content/pages/privacy-policy.md | 104 + content/pages/uses.md | 73 + content/projects/hasanhub-com.mdx | 112 + content/projects/hausgemacht.mdx | 80 + .../hasanhub-plausible-april-may-2022.png | Bin 0 -> 166567 bytes .../images/hasanhub-plausible-august-2022.png | Bin 0 -> 160545 bytes .../hasanhub-plausible-december-2022.png | Bin 0 -> 196052 bytes .../projects/images/hasanhub-screenshot.png | Bin 0 -> 1702434 bytes .../images/hausgemacht-screenshot.png | Bin 0 -> 379044 bytes .../hausgemacht-vibechecker-screenshots.png | Bin 0 -> 322183 bytes .../images/mitentscheiden-kabine-clip.gif | Bin 0 -> 960476 bytes .../mitentscheiden-kabine-screenshot.png | Bin 0 -> 276592 bytes .../images/mitentscheiden-results.png | Bin 0 -> 108296 bytes .../images/mitentscheiden-screenshot.png | Bin 0 -> 255100 bytes .../images/mitentscheiden-screenshots.jpg | Bin 0 -> 280141 bytes .../images/mitentscheiden-shareables.jpg | Bin 0 -> 250214 bytes .../preismonitor-plausible-may-july.png | Bin 0 -> 161346 bytes .../images/preismonitor-screenshot.png | Bin 0 -> 260784 bytes content/projects/mitentscheiden-at.mdx | 94 + content/projects/preismonitor-at.mdx | 68 + content/quotes/write-in-blood.md | 4 + content/shows/bojack-horseman.md | 5 + contentlayer.config.ts | 70 + package.json | 47 +- pnpm-lock.yaml | 9966 +++++++++++++++++ postcss.config.cjs | 6 + tailwind.config.ts | 99 + tsconfig.json | 30 +- vite.config.ts | 24 + 267 files changed, 14234 insertions(+), 17 deletions(-) create mode 100644 app/components/ErrorBoundary.tsx create mode 100644 app/components/Footer.tsx create mode 100644 app/components/Header.tsx create mode 100644 app/components/Particles.tsx create mode 100644 app/components/RelatedContent.tsx create mode 100644 app/components/SocialIcon.tsx create mode 100644 app/components/SocialLinks.tsx create mode 100644 app/components/Toast.tsx create mode 100644 app/components/embeds/EmbedOverlay.tsx create mode 100644 app/components/embeds/InstagramEmbed.tsx create mode 100644 app/components/embeds/RedditEmbed.tsx create mode 100644 app/components/embeds/TwitterEmbed.tsx create mode 100644 app/components/embeds/YouTubeEmbed.tsx create mode 100644 app/components/embeds/index.ts create mode 100644 app/components/layouts/ArticleLayout.tsx create mode 100644 app/components/layouts/ArticleListLayout.tsx create mode 100644 app/components/layouts/BaseLayout.tsx create mode 100644 app/components/layouts/BookLayout.tsx create mode 100644 app/components/layouts/BookListLayout.tsx create mode 100644 app/components/layouts/ProjectLayout.tsx create mode 100644 app/components/layouts/ProjectListLayout.tsx create mode 100644 app/components/layouts/RootLayout.tsx create mode 100644 app/components/mdx/index.tsx create mode 100644 app/data/socials.ts create mode 100644 app/entry.client.tsx create mode 100644 app/entry.server.tsx create mode 100644 app/hooks/useFocusManagement.ts create mode 100644 app/hooks/useKeyboardNavigation.ts create mode 100644 app/root.tsx create mode 100644 app/routes/_index.tsx create mode 100644 app/routes/api.embed-consent.ts create mode 100644 app/routes/articles.$slug.tsx create mode 100644 app/routes/articles._index.tsx create mode 100644 app/routes/books.$slug.tsx create mode 100644 app/routes/books._index.tsx create mode 100644 app/routes/feed[.]xml.ts create mode 100644 app/routes/projects.$slug.tsx create mode 100644 app/routes/projects._index.tsx create mode 100644 app/routes/sitemap[.]xml.ts create mode 100644 app/styles/tailwind.css create mode 100644 app/utils/content-relations.ts create mode 100644 app/utils/content.ts create mode 100644 app/utils/embed-consent.ts create mode 100644 app/utils/navigation.ts create mode 100644 app/utils/structured-data.ts create mode 100644 app/utils/theme.server.ts rename astro.config.mjs => astro-site/astro.config.mjs (100%) rename package-lock.json => astro-site/package-lock.json (100%) rename {src => astro-site/src}/components/BackButton.astro (100%) rename {src => astro-site/src}/components/ExternalLink.astro (100%) rename {src => astro-site/src}/components/Footer.astro (100%) rename {src => astro-site/src}/components/Header.astro (100%) rename {src => astro-site/src}/components/ListHeader.astro (100%) rename {src => astro-site/src}/components/Particles.astro (100%) rename {src => astro-site/src}/components/ReadMoreButton.astro (100%) rename {src => astro-site/src}/components/SkipToContent.astro (100%) rename {src => astro-site/src}/components/SocialIcon.astro (100%) rename {src => astro-site/src}/components/SocialLinks.astro (100%) rename {src => astro-site/src}/components/TableOfContents.astro (100%) rename {src => astro-site/src}/components/TableOfContentsHeading.astro (100%) rename {src => astro-site/src}/components/embeds/AndererseitsInstagram.astro (100%) rename {src => astro-site/src}/components/icons/ArrowLeft.astro (100%) rename {src => astro-site/src}/components/icons/ArrowRight.astro (100%) rename {src => astro-site/src}/components/particles.json (100%) rename {src => astro-site/src}/content/articles/2023-year-in-review.mdx (100%) rename {src => astro-site/src}/content/articles/images/der-wanderer-ueber-dem-nebelmeer.jpg (100%) rename {src => astro-site/src}/content/books/a-liberated-mind.md (100%) rename {src => astro-site/src}/content/books/antifragile.md (100%) rename {src => astro-site/src}/content/books/black-swan.md (100%) rename {src => astro-site/src}/content/books/brave-new-world.md (100%) rename {src => astro-site/src}/content/books/breaking-out-of-homeostasis.md (100%) rename {src => astro-site/src}/content/books/capitalist-realism.md (100%) rename {src => astro-site/src}/content/books/covers/a-liberated-mind-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/antifragile-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/brave-new-world-cover.jpeg (100%) rename {src => astro-site/src}/content/books/covers/breaking-out-of-homeostasis-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/capitalist-realism-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/dark-money-cover.jpeg (100%) rename {src => astro-site/src}/content/books/covers/debt-the-first-5000-years-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/flow-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/fooled-by-randomness-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/gateless-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/i-wrote-this-book-because-i-love-you-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/influencer-die-ideologie-des-werbekoerpers-cover.webp (100%) rename {src => astro-site/src}/content/books/covers/kill-all-normies-cover.webp (100%) rename {src => astro-site/src}/content/books/covers/less-is-more-cover.webp (100%) rename {src => astro-site/src}/content/books/covers/mans-search-for-meaning-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/of-mice-and-men-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/seeing-that-frees-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/skin-in-the-game-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/survival-of-the-richest-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-art-of-learning-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-black-swan-cover.webp (100%) rename {src => astro-site/src}/content/books/covers/the-count-of-monte-cristo-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-divide-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-mind-illuminated-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-paleo-manifesto-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/the-science-of-enlightenment-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/vagabonding-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/we-learn-nothing-cover.jpg (100%) rename {src => astro-site/src}/content/books/covers/winners-take-all-cover.jpg (100%) rename {src => astro-site/src}/content/books/dark-money.md (100%) rename {src => astro-site/src}/content/books/debt-the-first-5000-years.md (100%) rename {src => astro-site/src}/content/books/flow.md (100%) rename {src => astro-site/src}/content/books/fooled-by-randomness.md (100%) rename {src => astro-site/src}/content/books/gateless.md (100%) rename {src => astro-site/src}/content/books/i-wrote-this-book-because-i-love-you.md (100%) rename {src => astro-site/src}/content/books/influencer-die-ideologie-des-werbekoerpers.md (100%) rename {src => astro-site/src}/content/books/kill-all-normies.md (100%) rename {src => astro-site/src}/content/books/less-is-more.md (100%) rename {src => astro-site/src}/content/books/mans-search-for-meaning.md (100%) rename {src => astro-site/src}/content/books/of-mice-and-men.md (100%) rename {src => astro-site/src}/content/books/seeing-that-frees.md (100%) rename {src => astro-site/src}/content/books/skin-in-the-game.md (100%) rename {src => astro-site/src}/content/books/survival-of-the-richest.md (100%) rename {src => astro-site/src}/content/books/the-art-of-learning.md (100%) rename {src => astro-site/src}/content/books/the-count-of-monte-cristo.md (100%) rename {src => astro-site/src}/content/books/the-divide.md (100%) rename {src => astro-site/src}/content/books/the-mind-illuminated.md (100%) rename {src => astro-site/src}/content/books/the-paleo-manifesto.md (100%) rename {src => astro-site/src}/content/books/the-science-of-enlightenment.md (100%) rename {src => astro-site/src}/content/books/vagabonding.md (100%) rename {src => astro-site/src}/content/books/we-learn-nothing.md (100%) rename {src => astro-site/src}/content/books/winner-takes-all.md (100%) rename {src => astro-site/src}/content/config.ts (100%) rename {src => astro-site/src}/content/films/palm-springs.md (100%) rename {src => astro-site/src}/content/musicians/ski-aggu.md (100%) rename {src => astro-site/src}/content/pages/colophon.mdx (100%) rename {src => astro-site/src}/content/pages/imprint.md (100%) rename {src => astro-site/src}/content/pages/privacy-policy.md (100%) rename {src => astro-site/src}/content/pages/uses.md (100%) rename {src => astro-site/src}/content/projects/hasanhub-com.mdx (100%) rename {src => astro-site/src}/content/projects/hausgemacht.mdx (100%) rename {src => astro-site/src}/content/projects/images/hasanhub-plausible-april-may-2022.png (100%) rename {src => astro-site/src}/content/projects/images/hasanhub-plausible-august-2022.png (100%) rename {src => astro-site/src}/content/projects/images/hasanhub-plausible-december-2022.png (100%) rename {src => astro-site/src}/content/projects/images/hasanhub-screenshot.png (100%) rename {src => astro-site/src}/content/projects/images/hausgemacht-screenshot.png (100%) rename {src => astro-site/src}/content/projects/images/hausgemacht-vibechecker-screenshots.png (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-kabine-clip.gif (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-kabine-screenshot.png (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-results.png (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-screenshot.png (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-screenshots.jpg (100%) rename {src => astro-site/src}/content/projects/images/mitentscheiden-shareables.jpg (100%) rename {src => astro-site/src}/content/projects/images/preismonitor-plausible-may-july.png (100%) rename {src => astro-site/src}/content/projects/images/preismonitor-screenshot.png (100%) rename {src => astro-site/src}/content/projects/mitentscheiden-at.mdx (100%) rename {src => astro-site/src}/content/projects/preismonitor-at.mdx (100%) rename {src => astro-site/src}/content/quotes/write-in-blood.md (100%) rename {src => astro-site/src}/content/shows/bojack-horseman.md (100%) rename {src => astro-site/src}/data/socials.ts (100%) rename {src => astro-site/src}/env.d.ts (100%) rename {src => astro-site/src}/images/chrcit-favicon.png (100%) rename {src => astro-site/src}/images/cut-out.png (100%) rename {src => astro-site/src}/images/home-profile-camera.jpg (100%) rename {src => astro-site/src}/images/home-profile.jpg (100%) rename {src => astro-site/src}/images/profile-frontal.jpg (100%) rename {src => astro-site/src}/layouts/ArticleLayout.astro (100%) rename {src => astro-site/src}/layouts/BaseLayout.astro (100%) rename {src => astro-site/src}/layouts/ListLayout.astro (100%) rename {src => astro-site/src}/layouts/RootLayout.astro (100%) rename {src => astro-site/src}/pages/[slug].astro (100%) rename {src => astro-site/src}/pages/articles.astro (100%) rename {src => astro-site/src}/pages/articles/[slug].astro (100%) rename {src => astro-site/src}/pages/books.astro (100%) rename {src => astro-site/src}/pages/books/[slug].astro (100%) rename {src => astro-site/src}/pages/index.astro (100%) rename {src => astro-site/src}/pages/projects.astro (100%) rename {src => astro-site/src}/pages/projects/[slug].astro (100%) rename tailwind.config.mjs => astro-site/tailwind.config.mjs (100%) create mode 100644 content/articles/2023-year-in-review.mdx create mode 100644 content/articles/hello-world.mdx create mode 100644 content/articles/images/der-wanderer-ueber-dem-nebelmeer.jpg create mode 100644 content/books/a-liberated-mind.md create mode 100644 content/books/antifragile.md create mode 100644 content/books/black-swan.md create mode 100644 content/books/brave-new-world.md create mode 100644 content/books/breaking-out-of-homeostasis.md create mode 100644 content/books/capitalist-realism.md create mode 100644 content/books/covers/a-liberated-mind-cover.jpg create mode 100644 content/books/covers/antifragile-cover.jpg create mode 100644 content/books/covers/brave-new-world-cover.jpeg create mode 100644 content/books/covers/breaking-out-of-homeostasis-cover.jpg create mode 100644 content/books/covers/capitalist-realism-cover.jpg create mode 100644 content/books/covers/dark-money-cover.jpeg create mode 100644 content/books/covers/debt-the-first-5000-years-cover.jpg create mode 100644 content/books/covers/flow-cover.jpg create mode 100644 content/books/covers/fooled-by-randomness-cover.jpg create mode 100644 content/books/covers/gateless-cover.jpg create mode 100644 content/books/covers/i-wrote-this-book-because-i-love-you-cover.jpg create mode 100644 content/books/covers/influencer-die-ideologie-des-werbekoerpers-cover.webp create mode 100644 content/books/covers/kill-all-normies-cover.webp create mode 100644 content/books/covers/less-is-more-cover.webp create mode 100644 content/books/covers/mans-search-for-meaning-cover.jpg create mode 100644 content/books/covers/of-mice-and-men-cover.jpg create mode 100644 content/books/covers/seeing-that-frees-cover.jpg create mode 100644 content/books/covers/skin-in-the-game-cover.jpg create mode 100644 content/books/covers/survival-of-the-richest-cover.jpg create mode 100644 content/books/covers/the-art-of-learning-cover.jpg create mode 100644 content/books/covers/the-black-swan-cover.webp create mode 100644 content/books/covers/the-count-of-monte-cristo-cover.jpg create mode 100644 content/books/covers/the-divide-cover.jpg create mode 100644 content/books/covers/the-mind-illuminated-cover.jpg create mode 100644 content/books/covers/the-paleo-manifesto-cover.jpg create mode 100644 content/books/covers/the-science-of-enlightenment-cover.jpg create mode 100644 content/books/covers/vagabonding-cover.jpg create mode 100644 content/books/covers/we-learn-nothing-cover.jpg create mode 100644 content/books/covers/winners-take-all-cover.jpg create mode 100644 content/books/dark-money.md create mode 100644 content/books/debt-the-first-5000-years.md create mode 100644 content/books/flow.md create mode 100644 content/books/fooled-by-randomness.md create mode 100644 content/books/gateless.md create mode 100644 content/books/i-wrote-this-book-because-i-love-you.md create mode 100644 content/books/influencer-die-ideologie-des-werbekoerpers.md create mode 100644 content/books/kill-all-normies.md create mode 100644 content/books/less-is-more.md create mode 100644 content/books/mans-search-for-meaning.md create mode 100644 content/books/of-mice-and-men.md create mode 100644 content/books/seeing-that-frees.md create mode 100644 content/books/skin-in-the-game.md create mode 100644 content/books/survival-of-the-richest.md create mode 100644 content/books/the-art-of-learning.md create mode 100644 content/books/the-count-of-monte-cristo.md create mode 100644 content/books/the-divide.md create mode 100644 content/books/the-mind-illuminated.md create mode 100644 content/books/the-paleo-manifesto.md create mode 100644 content/books/the-science-of-enlightenment.md create mode 100644 content/books/vagabonding.md create mode 100644 content/books/we-learn-nothing.md create mode 100644 content/books/winner-takes-all.md create mode 100644 content/config.ts create mode 100644 content/films/palm-springs.md create mode 100644 content/musicians/ski-aggu.md create mode 100644 content/pages/colophon.mdx create mode 100644 content/pages/imprint.md create mode 100644 content/pages/privacy-policy.md create mode 100644 content/pages/uses.md create mode 100644 content/projects/hasanhub-com.mdx create mode 100644 content/projects/hausgemacht.mdx create mode 100644 content/projects/images/hasanhub-plausible-april-may-2022.png create mode 100644 content/projects/images/hasanhub-plausible-august-2022.png create mode 100644 content/projects/images/hasanhub-plausible-december-2022.png create mode 100644 content/projects/images/hasanhub-screenshot.png create mode 100644 content/projects/images/hausgemacht-screenshot.png create mode 100644 content/projects/images/hausgemacht-vibechecker-screenshots.png create mode 100644 content/projects/images/mitentscheiden-kabine-clip.gif create mode 100644 content/projects/images/mitentscheiden-kabine-screenshot.png create mode 100644 content/projects/images/mitentscheiden-results.png create mode 100644 content/projects/images/mitentscheiden-screenshot.png create mode 100644 content/projects/images/mitentscheiden-screenshots.jpg create mode 100644 content/projects/images/mitentscheiden-shareables.jpg create mode 100644 content/projects/images/preismonitor-plausible-may-july.png create mode 100644 content/projects/images/preismonitor-screenshot.png create mode 100644 content/projects/mitentscheiden-at.mdx create mode 100644 content/projects/preismonitor-at.mdx create mode 100644 content/quotes/write-in-blood.md create mode 100644 content/shows/bojack-horseman.md create mode 100644 contentlayer.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 postcss.config.cjs create mode 100644 tailwind.config.ts create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index 6d4c0aa..50c7030 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ pnpm-debug.log* # macOS-specific files .DS_Store + +.contentlayer/ \ No newline at end of file diff --git a/app/components/ErrorBoundary.tsx b/app/components/ErrorBoundary.tsx new file mode 100644 index 0000000..17a921c --- /dev/null +++ b/app/components/ErrorBoundary.tsx @@ -0,0 +1,111 @@ +import { isRouteErrorResponse, useRouteError } from "@remix-run/react"; +import { RootLayout } from "./layouts/RootLayout"; + +export function ErrorBoundary() { + const error = useRouteError(); + + if (isRouteErrorResponse(error)) { + switch (error.status) { + case 404: + return ( + +
+
+

Page Not Found

+

+ The page you're looking for doesn't exist. Please check the + URL and try again. +

+

+ + ← Go back home + +

+
+
+
+ ); + case 401: + return ( + +
+
+

Unauthorized

+

+ You don't have permission to access this page. Please log in + and try again. +

+

+ + ← Go back home + +

+
+
+
+ ); + default: + return ( + +
+
+

Error

+

+ Something went wrong. Please try again later. If the problem + persists, please contact support. +

+

+ + ← Go back home + +

+ {process.env.NODE_ENV === "development" && ( +
+                    {error.data.message || JSON.stringify(error.data, null, 2)}
+                  
+ )} +
+
+
+ ); + } + } + + return ( + +
+
+

Error

+

+ Something went wrong. Please try again later. If the problem + persists, please contact support. +

+

+ + ← Go back home + +

+ {process.env.NODE_ENV === "development" && ( +
+              {error instanceof Error
+                ? error.message
+                : "Unknown error occurred"}
+            
+ )} +
+
+
+ ); +} diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx new file mode 100644 index 0000000..3523b98 --- /dev/null +++ b/app/components/Footer.tsx @@ -0,0 +1,32 @@ +import { Link } from "@remix-run/react"; +import { SocialLinks } from "./SocialLinks"; + +const footerLinks = [ + { name: "Colophon", href: "/colophon" }, + { name: "Privacy Policy", href: "/privacy-policy" }, + { name: "Imprint", href: "/imprint" }, +] as const; + +export function Footer() { + return ( + + ); +} diff --git a/app/components/Header.tsx b/app/components/Header.tsx new file mode 100644 index 0000000..1cd6d10 --- /dev/null +++ b/app/components/Header.tsx @@ -0,0 +1,74 @@ +import { Link, useLocation } from "@remix-run/react"; +import { type ActiveTabType, navigationLinks } from "~/utils/navigation"; +import { SocialLinks } from "./SocialLinks"; +import clsx from "clsx"; + +interface HeaderProps { + activeTab?: ActiveTabType; +} + +export function Header({ activeTab }: HeaderProps) { + const location = useLocation(); + + return ( +
+ + Image of Christian Cito, a 26 year old white man. I'm wearing a loose blue shirt and am looking to the side. + + + +
+ ); +} diff --git a/app/components/Particles.tsx b/app/components/Particles.tsx new file mode 100644 index 0000000..5966cc1 --- /dev/null +++ b/app/components/Particles.tsx @@ -0,0 +1,85 @@ +import { useCallback } from "react"; +import type { Container, Engine } from "tsparticles-engine"; +import { loadFull } from "tsparticles"; +import Particles from "react-tsparticles"; + +export function Particles({ className }: { className?: string }) { + const particlesInit = useCallback(async (engine: Engine) => { + await loadFull(engine); + }, []); + + const particlesLoaded = useCallback( + async (container: Container | undefined) => { + await container?.refresh(); + }, + [], + ); + + return ( + + ); +} diff --git a/app/components/RelatedContent.tsx b/app/components/RelatedContent.tsx new file mode 100644 index 0000000..118e993 --- /dev/null +++ b/app/components/RelatedContent.tsx @@ -0,0 +1,55 @@ +import { Link } from "@remix-run/react"; + +interface RelatedContentItem { + title: string; + description: string; + slug: string; + type: "article" | "book" | "project"; + tags: string[]; +} + +interface RelatedContentProps { + items: RelatedContentItem[]; + title?: string; +} + +export function RelatedContent({ + items, + title = "Related Content", +}: RelatedContentProps) { + if (items.length === 0) return null; + + return ( +
+

{title}

+ +
+ ); +} diff --git a/app/components/SocialIcon.tsx b/app/components/SocialIcon.tsx new file mode 100644 index 0000000..3fc50c9 --- /dev/null +++ b/app/components/SocialIcon.tsx @@ -0,0 +1,69 @@ +import { type SocialType } from "~/data/socials"; +import clsx from "clsx"; + +interface SocialIconProps { + type: SocialType; + size: number; + className?: string; +} + +export function SocialIcon({ type, size, className }: SocialIconProps) { + const iconProps = { + className: clsx("lucide", `lucide-${type}`, className), + xmlns: "http://www.w3.org/2000/svg", + width: size, + height: size, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round", + strokeLinejoin: "round", + }; + + switch (type) { + case "github": + return ( + + + + + ); + + case "twitter": + return ( + + + + ); + + case "linkedin": + return ( + + + + + + ); + + case "youtube": + return ( + + + + + ); + + case "instagram": + return ( + + + + + + ); + + default: + return null; + } +} diff --git a/app/components/SocialLinks.tsx b/app/components/SocialLinks.tsx new file mode 100644 index 0000000..d177570 --- /dev/null +++ b/app/components/SocialLinks.tsx @@ -0,0 +1,33 @@ +import { socialLinks } from "~/data/socials"; +import { SocialIcon } from "./SocialIcon"; +import clsx from "clsx"; + +interface SocialLinksProps { + size?: number; + className?: string; +} + +export function SocialLinks({ size = 16, className }: SocialLinksProps) { + return ( + + ); +} diff --git a/app/components/Toast.tsx b/app/components/Toast.tsx new file mode 100644 index 0000000..a6a4906 --- /dev/null +++ b/app/components/Toast.tsx @@ -0,0 +1,113 @@ +import { useEffect, useState } from "react"; + +interface ToastProps { + message: string; + type?: "success" | "error" | "info"; + duration?: number; + onClose?: () => void; +} + +export function Toast({ + message, + type = "info", + duration = 3000, + onClose, +}: ToastProps) { + const [isVisible, setIsVisible] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(false); + onClose?.(); + }, duration); + + return () => clearTimeout(timer); + }, [duration, onClose]); + + if (!isVisible) return null; + + const bgColor = { + success: "bg-green-500", + error: "bg-red-500", + info: "bg-blue-500", + }[type]; + + return ( +
+
+ {message} + +
+
+ ); +} + +interface ToastManagerProps { + children: React.ReactNode; +} + +interface ToastState { + id: number; + message: string; + type?: "success" | "error" | "info"; + duration?: number; +} + +export function ToastManager({ children }: ToastManagerProps) { + const [toasts, setToasts] = useState([]); + + const addToast = ( + message: string, + type: "success" | "error" | "info" = "info", + duration = 3000, + ) => { + const id = Date.now(); + setToasts((prev) => [...prev, { id, message, type, duration }]); + }; + + const removeToast = (id: number) => { + setToasts((prev) => prev.filter((toast) => toast.id !== id)); + }; + + return ( + <> + {children} +
+ {toasts.map((toast) => ( + removeToast(toast.id)} + /> + ))} +
+ + ); +} diff --git a/app/components/embeds/EmbedOverlay.tsx b/app/components/embeds/EmbedOverlay.tsx new file mode 100644 index 0000000..39a90d6 --- /dev/null +++ b/app/components/embeds/EmbedOverlay.tsx @@ -0,0 +1,57 @@ +import { useFetcher } from "@remix-run/react"; +import { type EmbedType } from "~/utils/embed-consent"; +import clsx from "clsx"; + +interface EmbedOverlayProps { + type: EmbedType; + title: string; + description: string; + hasConsent: boolean; + children: React.ReactNode; +} + +export function EmbedOverlay({ + type, + title, + description, + hasConsent, + children, +}: EmbedOverlayProps) { + const fetcher = useFetcher(); + const isLoading = fetcher.state !== "idle"; + + if (hasConsent) { + return <>{children}; + } + + return ( +
+
+

{title}

+

{description}

+
+ + + + + + + +

+ By clicking "Load Embed", you consent to loading content from{" "} + {type}. This setting + will be remembered for future embeds. +

+
+ ); +} diff --git a/app/components/embeds/InstagramEmbed.tsx b/app/components/embeds/InstagramEmbed.tsx new file mode 100644 index 0000000..5fc93f4 --- /dev/null +++ b/app/components/embeds/InstagramEmbed.tsx @@ -0,0 +1,83 @@ +import { useEffect, useRef } from "react"; +import { EmbedOverlay } from "./EmbedOverlay"; + +interface InstagramEmbedProps { + postId: string; + hasConsent: boolean; +} + +declare global { + interface Window { + instgrm?: { + Embeds: { + process: () => void; + }; + }; + } +} + +export function InstagramEmbed({ postId, hasConsent }: InstagramEmbedProps) { + const containerRef = useRef(null); + + useEffect(() => { + if (!hasConsent) return; + + // Load Instagram embed script if not already loaded + if (!window.instgrm) { + const script = document.createElement("script"); + script.src = "//www.instagram.com/embed.js"; + script.async = true; + document.body.appendChild(script); + } else { + // If script is already loaded, process the embed + window.instgrm.Embeds.process(); + } + }, [hasConsent]); + + return ( + +
+
+ +
+
+
+ ); +} diff --git a/app/components/embeds/RedditEmbed.tsx b/app/components/embeds/RedditEmbed.tsx new file mode 100644 index 0000000..15817d1 --- /dev/null +++ b/app/components/embeds/RedditEmbed.tsx @@ -0,0 +1,49 @@ +import { useEffect, useRef } from "react"; +import { EmbedOverlay } from "./EmbedOverlay"; + +interface RedditEmbedProps { + postUrl: string; + hasConsent: boolean; +} + +declare global { + interface Window { + rembeddit?: { + init: () => void; + }; + } +} + +export function RedditEmbed({ postUrl, hasConsent }: RedditEmbedProps) { + const containerRef = useRef(null); + + useEffect(() => { + if (!hasConsent) return; + + // Load Reddit embed script if not already loaded + if (!window.rembeddit) { + const script = document.createElement("script"); + script.src = "https://embed.reddit.com/widgets.js"; + script.async = true; + document.body.appendChild(script); + } else { + // If script is already loaded, initialize the embed + window.rembeddit.init(); + } + }, [hasConsent]); + + return ( + + + + ); +} diff --git a/app/components/embeds/TwitterEmbed.tsx b/app/components/embeds/TwitterEmbed.tsx new file mode 100644 index 0000000..240c421 --- /dev/null +++ b/app/components/embeds/TwitterEmbed.tsx @@ -0,0 +1,58 @@ +import { useEffect, useRef } from "react"; +import { EmbedOverlay } from "./EmbedOverlay"; + +interface TwitterEmbedProps { + tweetId: string; + hasConsent: boolean; +} + +declare global { + interface Window { + twttr?: { + widgets: { + load: (element?: HTMLElement) => void; + }; + }; + } +} + +export function TwitterEmbed({ tweetId, hasConsent }: TwitterEmbedProps) { + const containerRef = useRef(null); + + useEffect(() => { + if (!hasConsent) return; + + // Load Twitter widget script if not already loaded + if (!window.twttr) { + const script = document.createElement("script"); + script.src = "https://platform.twitter.com/widgets.js"; + script.async = true; + document.body.appendChild(script); + } else { + // If script is already loaded, render the tweet + window.twttr.widgets.load(containerRef.current); + } + }, [hasConsent]); + + return ( + + + + ); +} diff --git a/app/components/embeds/YouTubeEmbed.tsx b/app/components/embeds/YouTubeEmbed.tsx new file mode 100644 index 0000000..26d9838 --- /dev/null +++ b/app/components/embeds/YouTubeEmbed.tsx @@ -0,0 +1,32 @@ +import { EmbedOverlay } from "./EmbedOverlay"; + +interface YouTubeEmbedProps { + videoId: string; + hasConsent: boolean; + title?: string; +} + +export function YouTubeEmbed({ + videoId, + hasConsent, + title, +}: YouTubeEmbedProps) { + return ( + +
+