├── .editorconfig ├── .env.example ├── .eslintrc.json ├── .github ├── .kodiak.toml ├── actions │ ├── cache-turbo │ │ └── action.yml │ ├── deploy │ │ └── action.yml │ ├── e2e │ │ └── action.yml │ ├── init │ │ └── action.yml │ ├── install │ │ └── action.yml │ ├── lint │ │ └── action.yml │ ├── release │ │ └── action.yml │ └── test │ │ └── action.yml ├── renovate.json └── workflows │ ├── pull.yml │ └── push.yml ├── .gitignore ├── .husky ├── pre-commit └── prepare-commit-msg ├── .lintstagedrc.mjs ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierignore_staged ├── .prettierrc.mjs ├── .syncpackrc.mjs ├── .vscode ├── extensions.json └── settings.default.json ├── LICENSE ├── README.md ├── changelog.config.mjs ├── config └── release-branch-types │ ├── ci.cjs │ ├── feature.cjs │ ├── fix.cjs │ ├── index.cjs │ ├── refactor.cjs │ └── release.cjs ├── eslint.config.mjs ├── index.d.ts ├── node-modules-inspector.config.ts ├── package.json ├── packages ├── design-system │ ├── .storybook │ │ ├── font.css │ │ ├── main.ts │ │ ├── manager.ts │ │ └── preview.ts │ ├── jest.config.js │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── static │ │ │ └── fonts │ │ │ └── inter │ │ │ ├── inter-4.0.0-beta9g-var.woff2 │ │ │ ├── inter-var-full.woff2 │ │ │ ├── inter-var-italic.woff2 │ │ │ ├── inter-var-latin.woff2 │ │ │ └── inter-var.woff2 │ ├── scripts │ │ └── copy.sh │ ├── src │ │ ├── components │ │ │ ├── Anchor │ │ │ │ ├── Anchor.tsx │ │ │ │ └── index.ts │ │ │ ├── Callout │ │ │ │ ├── Callout.tsx │ │ │ │ └── index.ts │ │ │ ├── Icon │ │ │ │ ├── Icon.stories.tsx │ │ │ │ ├── Icon.test.tsx │ │ │ │ ├── Icon.tsx │ │ │ │ ├── Icon.types.ts │ │ │ │ └── index.ts │ │ │ ├── Section │ │ │ │ ├── Section.Content.tsx │ │ │ │ ├── Section.Header.Content.tsx │ │ │ │ ├── Section.Header.Title.tsx │ │ │ │ ├── Section.Header.tsx │ │ │ │ ├── Section.Hero.tsx │ │ │ │ ├── Section.Wrapper.tsx │ │ │ │ ├── Section.test.ts │ │ │ │ ├── Tags.tsx │ │ │ │ └── index.ts │ │ │ ├── SkipNav │ │ │ │ ├── SkipNav.tsx │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── ui │ │ │ └── .gitkeep │ │ └── utils │ │ │ └── cx.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsup.config.ts ├── jest-config │ ├── jest.config.js │ ├── jest.setup.js │ └── package.json ├── jest-presets │ ├── jest │ │ └── node │ │ │ └── jest-preset.js │ └── package.json ├── lighthouse-config │ ├── .lighthouserc.cjs │ └── package.json ├── next-config │ ├── next.config.mjs │ ├── package.json │ └── src │ │ ├── build-info.mjs │ │ ├── env.client.mjs │ │ ├── env.server.mjs │ │ └── security-headers.mjs ├── next-notion │ ├── README.md │ ├── package.json │ ├── scripts │ │ └── copy.sh │ ├── src │ │ ├── Notion.Blocks.tsx │ │ ├── Notion.Config.tsx │ │ ├── Notion.constants.ts │ │ ├── Notion.types.ts │ │ ├── Notion.utils.tsx │ │ ├── blocks │ │ │ ├── Column.tsx │ │ │ ├── Divider.tsx │ │ │ ├── Emoji.client.tsx │ │ │ ├── Emoji.server.tsx │ │ │ ├── Emoji.tsx │ │ │ ├── ListBulleted.tsx │ │ │ ├── ListColumn.tsx │ │ │ └── RichText.tsx │ │ ├── helper.ts │ │ ├── index.ts │ │ ├── queries │ │ │ ├── getBlockChildrenData.ts │ │ │ ├── getBlockChildrenDataParent.ts │ │ │ ├── getColumnData.ts │ │ │ ├── getDatabaseQuery.ts │ │ │ ├── getPageData.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── getAwsImage.ts │ │ │ ├── getPropertyTypeData.ts │ │ │ ├── getSegmentInfo.ts │ │ │ ├── index.ts │ │ │ └── uuid.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── playwright-config │ ├── package.json │ └── playwright.config.ts ├── shared │ ├── package.json │ ├── scripts │ │ └── copy.sh │ ├── src │ │ ├── components │ │ │ ├── Analytics │ │ │ │ ├── Analytics.tsx │ │ │ │ ├── Fathom.tsx │ │ │ │ ├── Vercel.tsx │ │ │ │ └── index.ts │ │ │ ├── Navigation │ │ │ │ ├── Navigation.tsx │ │ │ │ └── index.ts │ │ │ └── Notion │ │ │ │ └── Blocks │ │ │ │ ├── Embed.Spotify.tsx │ │ │ │ ├── Embed.Twitter.tsx │ │ │ │ ├── Embed.tsx │ │ │ │ ├── Image.client.tsx │ │ │ │ ├── Image.tsx │ │ │ │ ├── Image.utils.ts │ │ │ │ ├── Video.YouTube.tsx │ │ │ │ └── Video.tsx │ │ ├── hooks │ │ │ ├── .gitkeep │ │ │ ├── index.ts │ │ │ ├── useSWRInfinitePages.ts │ │ │ ├── useThemeToggle.ts │ │ │ └── useThrottle.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── constants.ts │ │ │ ├── fetcher.ts │ │ │ └── index.ts │ │ ├── notion │ │ │ └── utils │ │ │ │ ├── getDataFromCache.ts │ │ │ │ ├── getDatabaseQuery.ts │ │ │ │ ├── getDatabaseQueryByDateRange.ts │ │ │ │ ├── getMetadata.ts │ │ │ │ ├── getPageDataFromNotion.ts │ │ │ │ ├── getSegmentInfo.ts │ │ │ │ ├── getSlugPreview.ts │ │ │ │ └── index.ts │ │ ├── plaiceholder │ │ │ ├── getImage.ts │ │ │ └── index.ts │ │ └── redis │ │ │ ├── getCache.ts │ │ │ ├── getKey.ts │ │ │ ├── index.ts │ │ │ ├── redis.ts │ │ │ └── setCache.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── storybook-config │ ├── main.config.ts │ ├── manager.config.ts │ ├── package.json │ ├── preview-head.html │ ├── preview.config.ts │ ├── preview.css │ ├── public │ │ └── .gitkeep │ ├── themes.ts │ └── withTailwindTheme.decorator.tsx └── tailwind-config │ ├── hocus.plugin.js │ ├── package.json │ ├── postcss.config.js │ ├── radix.plugin.js │ ├── src │ ├── backgrounds.js │ ├── buttons.js │ ├── colors.js │ ├── index.js │ └── notion.js │ ├── styles │ ├── chrome.css │ ├── fonts.css │ ├── globals.css │ ├── radix-themes-tw.css │ └── safari.css │ └── tailwind.config.ts ├── patches ├── .gitkeep └── @semantic-release__commit-analyzer@13.0.0.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── release.config.mjs ├── scripts └── clean.sh ├── sites ├── .gitignore ├── alexojerome.com │ └── .gitkeep ├── amidracula.com │ └── .gitkeep ├── ayemonthen.com │ └── .gitkeep ├── boohumbag.com │ └── .gitkeep ├── crimeimprov.com │ └── .gitkeep ├── dahriferks.com │ └── .gitkeep ├── fuckyoucandy.com │ └── .gitkeep ├── jerandky.com │ ├── next-env.d.ts │ ├── next.config.mjs │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── fonts │ │ │ └── inter │ │ │ │ ├── inter-4.0.0-beta9g-var.woff2 │ │ │ │ ├── inter-var-full.woff2 │ │ │ │ ├── inter-var-italic.woff2 │ │ │ │ ├── inter-var-latin.woff2 │ │ │ │ └── inter-var.woff2 │ │ ├── humans.txt │ │ ├── images │ │ │ └── favicon │ │ │ │ ├── android-chrome-192x192.png │ │ │ │ ├── android-chrome-512x512.png │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── browserconfig.xml │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── favicon.ico │ │ │ │ ├── mstile-150x150.png │ │ │ │ ├── safari-pinned-tab.svg │ │ │ │ └── site.webmanifest │ │ └── xml │ │ │ └── podcasts.xls │ ├── src │ │ ├── app │ │ │ ├── (notion) │ │ │ │ ├── _config │ │ │ │ │ ├── Episode.types.ts │ │ │ │ │ ├── Episode.utils.ts │ │ │ │ │ ├── Page.types.ts │ │ │ │ │ ├── Page.utils.ts │ │ │ │ │ ├── Person.types.ts │ │ │ │ │ ├── Person.utils.ts │ │ │ │ │ ├── Podcast.types.ts │ │ │ │ │ ├── Podcast.utils.ts │ │ │ │ │ ├── Venue.types.ts │ │ │ │ │ ├── Venue.utils.ts │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── temp │ │ │ │ │ │ └── generateMetadataCustom.ts │ │ │ │ └── podcasts │ │ │ │ │ └── [[...catchAll]] │ │ │ │ │ ├── _components │ │ │ │ │ ├── Episode.Slug.tsx │ │ │ │ │ ├── Image.tsx │ │ │ │ │ ├── Podcast.Episodes.tsx │ │ │ │ │ ├── Podcast.Listing.tsx │ │ │ │ │ └── Podcast.Slug.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── _errors │ │ │ │ └── 404.tsx │ │ │ ├── api │ │ │ │ └── rss │ │ │ │ │ └── podcasts │ │ │ │ │ ├── jer-and-ky-and-guest │ │ │ │ │ └── route.ts │ │ │ │ │ └── knockoffs │ │ │ │ │ └── route.ts │ │ │ ├── apple-icon.png │ │ │ ├── favicon.ico │ │ │ ├── icon.png │ │ │ ├── icon1.png │ │ │ ├── layout.tsx │ │ │ ├── not-found.tsx │ │ │ ├── page.tsx │ │ │ ├── robots.ts │ │ │ └── sitemap.ts │ │ ├── components │ │ │ ├── ErrorBoundary │ │ │ │ ├── ErrorBoundary.tsx │ │ │ │ └── index.ts │ │ │ ├── Footer │ │ │ │ ├── Footer.client.tsx │ │ │ │ ├── Footer.tsx │ │ │ │ └── index.ts │ │ │ ├── Notion │ │ │ │ ├── Notion.Config.ts │ │ │ │ ├── Notion.tsx │ │ │ │ └── index.ts │ │ │ ├── Providers │ │ │ │ ├── Providers.client.tsx │ │ │ │ ├── Providers.tsx │ │ │ │ ├── RouterEventProvider.Loading.client.tsx │ │ │ │ ├── RouterEventProvider.client.tsx │ │ │ │ ├── ThemeProvider.client.tsx │ │ │ │ └── index.ts │ │ │ └── Relations │ │ │ │ ├── Relations.Individual.tsx │ │ │ │ ├── Relations.Loading.tsx │ │ │ │ ├── Relations.tsx │ │ │ │ ├── Relations.utils.ts │ │ │ │ └── index.ts │ │ └── config │ │ │ └── .gitkeep │ ├── tsconfig.dev.json │ ├── tsconfig.json │ └── tsconfig.shared.json ├── jeromeand.com │ └── .gitkeep ├── jeromefitzgerald.com │ ├── .lighthouserc.cjs │ ├── drizzle.config.ts │ ├── jest.config.cjs │ ├── next-env.d.ts │ ├── next.config.ts │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.mjs │ ├── public │ │ ├── fonts │ │ │ ├── geist │ │ │ │ ├── GeistMonoVF--1.0.0.woff2 │ │ │ │ └── GeistVF--1.0.0.woff2 │ │ │ └── inter │ │ │ │ ├── inter-4.0.0-beta9g-var.woff2 │ │ │ │ ├── inter-var-full.woff2 │ │ │ │ ├── inter-var-italic.woff2 │ │ │ │ ├── inter-var-latin.woff2 │ │ │ │ └── inter-var.woff2 │ │ ├── humans.txt │ │ ├── images │ │ │ ├── cursors │ │ │ │ └── pink │ │ │ │ │ ├── cursor-arrow.svg │ │ │ │ │ ├── cursor-close.svg │ │ │ │ │ ├── cursor-grab.svg │ │ │ │ │ ├── cursor-grabbing.svg │ │ │ │ │ └── cursor-pointer.svg │ │ │ ├── favicon │ │ │ │ ├── android-chrome-192x192.png │ │ │ │ ├── android-chrome-512x512.png │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── browserconfig.xml │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── favicon.ico │ │ │ │ ├── mstile-150x150.png │ │ │ │ ├── safari-pinned-tab.svg │ │ │ │ └── site.webmanifest │ │ │ └── logos │ │ │ │ ├── arcade-comedy-theater.png │ │ │ │ ├── broadway-world--black.png │ │ │ │ ├── broadway-world--white.png │ │ │ │ ├── broadway-world.jpeg │ │ │ │ ├── broadway-world.png │ │ │ │ ├── pittsburgh-city-paper.png │ │ │ │ └── pittsburgh-magazine.png │ │ └── xml │ │ │ └── podcasts.xls │ ├── release.config.mjs │ ├── src │ │ ├── app │ │ │ ├── (pages) │ │ │ │ ├── about │ │ │ │ │ ├── _components │ │ │ │ │ │ ├── Section.Client.tsx │ │ │ │ │ │ └── Section.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── colophon │ │ │ │ │ └── page.tsx │ │ │ │ └── currently │ │ │ │ │ ├── listening-to │ │ │ │ │ ├── _components │ │ │ │ │ │ └── Music.client.tsx │ │ │ │ │ └── page.tsx │ │ │ │ │ └── reading │ │ │ │ │ ├── _components │ │ │ │ │ └── Book.client.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── (segments) │ │ │ │ ├── blog │ │ │ │ │ ├── [...key] │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ └── Blog.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── books │ │ │ │ │ ├── [key] │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ └── Book.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── events │ │ │ │ │ ├── [...key] │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ ├── Event.Data.List.tsx │ │ │ │ │ │ │ ├── Event.Slug.Header.Data.tsx │ │ │ │ │ │ │ └── Event.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ │ ├── List.Client.tsx │ │ │ │ │ │ ├── List.Deprecated.tsx │ │ │ │ │ │ ├── List.Temp.tsx │ │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── pages │ │ │ │ │ └── page.tsx │ │ │ │ ├── podcasts │ │ │ │ │ ├── [key] │ │ │ │ │ │ ├── [key-episode] │ │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ │ └── Episode.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ └── Podcast.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── shows │ │ │ │ │ ├── [key] │ │ │ │ │ │ ├── _components │ │ │ │ │ │ │ ├── Show.Slug.Header.Data.tsx │ │ │ │ │ │ │ └── Show.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── venues │ │ │ │ │ ├── [key] │ │ │ │ │ ├── _components │ │ │ │ │ │ └── Venue.tsx │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── _components │ │ │ │ │ └── List.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── _next │ │ │ │ ├── fonts.tsx │ │ │ │ ├── fonts │ │ │ │ │ ├── borogodo.tsx │ │ │ │ │ └── geist.tsx │ │ │ │ └── preload-resources.tsx │ │ │ ├── api │ │ │ │ └── v1 │ │ │ │ │ ├── music │ │ │ │ │ └── [slug] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── revalidate │ │ │ │ │ ├── actions.ts │ │ │ │ │ └── route.ts │ │ │ ├── apple-icon.png │ │ │ ├── favicon.ico │ │ │ ├── icon.png │ │ │ ├── icon1.png │ │ │ ├── layout.tsx │ │ │ ├── not-found.tsx │ │ │ ├── page.tsx │ │ │ ├── sitemap.ts │ │ │ ├── styles--globals.css │ │ │ └── styles--radix-themes-tw.css │ │ ├── components │ │ │ ├── Accordion │ │ │ │ ├── AccordionContent.tsx │ │ │ │ ├── AccordionItem.tsx │ │ │ │ ├── AccordionList.tsx │ │ │ │ ├── AccordionListItem.tsx │ │ │ │ ├── AccordionRoot.tsx │ │ │ │ ├── AccordionTrigger.tsx │ │ │ │ └── index.ts │ │ │ ├── Analytics │ │ │ │ ├── Analytics.tsx │ │ │ │ ├── Fathom.tsx │ │ │ │ ├── Vercel.tsx │ │ │ │ └── index.ts │ │ │ ├── Anchor │ │ │ │ ├── Anchor.tsx │ │ │ │ └── index.ts │ │ │ ├── Article │ │ │ │ ├── Article.Main.CTA.tsx │ │ │ │ └── Article.Main.tsx │ │ │ ├── Callout │ │ │ │ ├── Callout.tsx │ │ │ │ └── index.ts │ │ │ ├── Container │ │ │ │ ├── Container.Footer.Client.tsx │ │ │ │ ├── Container.Footer.tsx │ │ │ │ ├── Container.Gradient.tsx │ │ │ │ ├── Container.Main.tsx │ │ │ │ ├── Container.Navigation.tsx │ │ │ │ ├── Container.Section.tsx │ │ │ │ └── Container.Site.tsx │ │ │ ├── Credits │ │ │ │ ├── Credits.Header.tsx │ │ │ │ ├── Credits.Item.tsx │ │ │ │ ├── Credits.Items.tsx │ │ │ │ ├── Credits.Loading.tsx │ │ │ │ ├── Credits.tsx │ │ │ │ └── Credits.utils.ts │ │ │ ├── Currently │ │ │ │ ├── Currently.Event.tsx │ │ │ │ ├── Currently.Item.Wrapper.tsx │ │ │ │ ├── Currently.Item.tsx │ │ │ │ ├── Currently.Music.Client.tsx │ │ │ │ └── Currently.tsx │ │ │ ├── ErrorBoundary │ │ │ │ ├── ErrorBoundary.tsx │ │ │ │ └── index.ts │ │ │ ├── Header │ │ │ │ ├── Header.Full.tsx │ │ │ │ ├── Header.Sidebar.CTA.tsx │ │ │ │ └── Header.Sidebar.tsx │ │ │ ├── Icon │ │ │ │ ├── Icon.stories.tsx │ │ │ │ ├── Icon.test.tsx │ │ │ │ ├── Icon.tsx │ │ │ │ ├── Icon.types.ts │ │ │ │ └── index.ts │ │ │ ├── Image │ │ │ │ └── Image.Notion.tsx │ │ │ ├── List │ │ │ │ ├── LI.tsx │ │ │ │ ├── OL.tsx │ │ │ │ ├── UL.tsx │ │ │ │ └── index.ts │ │ │ ├── Navigation │ │ │ │ ├── Navigation.Button.Client.tsx │ │ │ │ ├── Navigation.Button.tsx │ │ │ │ ├── Navigation.Primary.tsx │ │ │ │ ├── Navigation.Secondary.tsx │ │ │ │ ├── Navigation.Separator.tsx │ │ │ │ ├── Navigation.Tertiary.tsx │ │ │ │ └── Navigation.tsx │ │ │ ├── Notion │ │ │ │ └── Blocks │ │ │ │ │ ├── Image.client.tsx │ │ │ │ │ ├── Image.tsx │ │ │ │ │ └── Image.utils.ts │ │ │ ├── Overlay │ │ │ │ └── Overlay.tsx │ │ │ ├── Providers │ │ │ │ ├── Providers.client.tsx │ │ │ │ ├── Providers.tsx │ │ │ │ ├── RouterEventProvider.Loading.client.tsx │ │ │ │ ├── RouterEventProvider.client.tsx │ │ │ │ ├── StoreInitEventsUpcoming.client.tsx │ │ │ │ ├── StoreProvider.client.tsx │ │ │ │ └── ThemeProvider.client.tsx │ │ │ ├── SkipNav │ │ │ │ ├── SkipNav.tsx │ │ │ │ └── index.ts │ │ │ └── Tags │ │ │ │ └── Tags.tsx │ │ ├── config │ │ │ ├── const.ts │ │ │ ├── next.config.env.client.mjs │ │ │ ├── next.config.env.server.mjs │ │ │ └── radix-themes-tw.css │ │ ├── data │ │ │ ├── bandcamps.ts │ │ │ ├── currently.tsx │ │ │ └── socials.tsx │ │ ├── e2e │ │ │ └── index.e2e.ts │ │ ├── hooks │ │ │ └── useSWRInfinitePages.ts │ │ ├── lib │ │ │ ├── constants.ts │ │ │ ├── drizzle │ │ │ │ ├── index.ts │ │ │ │ ├── init │ │ │ │ │ ├── migrate.ts │ │ │ │ │ ├── migrations │ │ │ │ │ │ ├── 0000_grey_hiroim.sql │ │ │ │ │ │ └── meta │ │ │ │ │ │ │ ├── 0000_snapshot.json │ │ │ │ │ │ │ └── _journal.json │ │ │ │ │ ├── seed.ts │ │ │ │ │ └── setup.ts │ │ │ │ ├── schemas │ │ │ │ │ ├── _notion │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-blocks │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-blogs │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-books │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-episodes │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-events │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-images │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-pages │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-podcasts │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-shows │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── cache-sites │ │ │ │ │ │ └── schemas.ts │ │ │ │ │ ├── cache-venues │ │ │ │ │ │ ├── queries.ts │ │ │ │ │ │ ├── schemas.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── helpers.ts │ │ │ │ │ ├── helpers.types.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── queries.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils │ │ │ │ │ ├── addItemToCache.ts │ │ │ │ │ ├── getImageKeySlug.ts │ │ │ │ │ ├── getKeyValue.ts │ │ │ │ │ ├── getKeyValues.ts │ │ │ │ │ └── index.ts │ │ │ ├── fetcher.ts │ │ │ ├── notion │ │ │ │ ├── Notion.Blocks.tsx │ │ │ │ ├── Notion.Component.tsx │ │ │ │ ├── Notion.utils.tsx │ │ │ │ ├── blocks │ │ │ │ │ ├── Column.tsx │ │ │ │ │ ├── Divider.tsx │ │ │ │ │ ├── Emoji.client.tsx │ │ │ │ │ ├── Emoji.server.tsx │ │ │ │ │ ├── Emoji.tsx │ │ │ │ │ ├── ListBulleted.tsx │ │ │ │ │ ├── ListColumn.tsx │ │ │ │ │ └── RichText.tsx │ │ │ │ ├── buildInitialCache.ts │ │ │ │ ├── config.default.ts │ │ │ │ ├── config.ts │ │ │ │ ├── getAwsImage.ts │ │ │ │ ├── getImageAlt.ts │ │ │ │ ├── index.ts │ │ │ │ └── notion.ts │ │ │ ├── plaiceholder │ │ │ │ ├── getImage.ts │ │ │ │ └── index.ts │ │ │ └── upstash │ │ │ │ ├── getCache.ts │ │ │ │ ├── getKey.ts │ │ │ │ ├── index.ts │ │ │ │ ├── redis.ts │ │ │ │ └── setCache.ts │ │ ├── store │ │ │ └── index.tsx │ │ └── utils │ │ │ ├── cx.ts │ │ │ ├── getBySegment.ts │ │ │ ├── getKey.ts │ │ │ ├── getKeySpotify.ts │ │ │ ├── getPlaceholder.ts │ │ │ ├── getPlaiceholder.ts │ │ │ ├── getTitleData.ts │ │ │ ├── isEmpty.ts │ │ │ ├── isObjectEmpty.ts │ │ │ ├── next │ │ │ └── getSegmentsForGenerateStaticParams.ts │ │ │ └── uuid.ts │ ├── tsconfig.json │ └── vercel.json ├── justinandjerome.com │ └── .gitkeep ├── nicegroupofpeople.com │ └── .gitkeep ├── nicerec.com │ └── .gitkeep ├── sarahfitzgerald.me │ └── .gitkeep ├── theeparodybros.com │ └── .gitkeep └── wkspizza.com │ └── .gitkeep ├── tsconfig.json ├── tsup.config.ts └── turbo.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | tab_width = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.js] 16 | quote_type = single 17 | 18 | [{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.d,*.cs,*.swift}] 19 | curly_bracket_next_line = false 20 | spaces_around_operators = true 21 | spaces_around_brackets = outside 22 | # close enough to 1TB 23 | indent_brace_style = K&R 24 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | TURBO_TEAM= 2 | TURBO_TOKEN= 3 | TZ=UTC 4 | VERCEL_ENV= 5 | # @note(husky) 🚩 Feature Flags: Opt-out by setting to 0 6 | HUSKY__PRE_COMMIT__LINT_STAGED=1 7 | HUSKY__PREPARE_COMMITMSG__CONVENTIONAL=1 8 | # @note(next) 🔐 Required for: jeromefitzgerald.com 9 | GH_TOKEN= 10 | LHCI_GITHUB_APP_TOKEN= 11 | NEXT_PUBLIC__FATHOM_SITE_ID= 12 | NEXT_PUBLIC__SITE= 13 | NOTION_API_KEY= 14 | OCTOKIT_TOKEN= 15 | OG_API_KEY= 16 | PREVIEW_TOKEN= 17 | REVALIDATE_TOKEN= 18 | SPOTIFY_CLIENT_ID= 19 | SPOTIFY_CLIENT_SECRET= 20 | SPOTIFY_REFRESH_TOKEN= 21 | UPSTASH_REDIS_REST_URL= 22 | UPSTASH_REDIS_REST_TOKEN= 23 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | # .kodiak.toml 2 | # docs: https://kodiakhq.com/docs/config-reference 3 | 4 | version = 1 5 | 6 | [approve] 7 | #auto_approve_usernames = ["renovate"] 8 | 9 | [merge] 10 | automerge_label = [" 🥳️ LGTM", "🥳️ LGTM","🥳️ LGTM","LGTM"] 11 | blocking_labels = [" 🚧️ WIP", "🚧️ WIP","🚧️ WIP","WIP"] 12 | delete_branch_on_merge = true 13 | method = "squash" 14 | optimistic_updates = true 15 | prioritize_ready_to_merge = true 16 | require_automerge_label = true 17 | 18 | [merge.automerge_dependencies] 19 | #usernames=["renovate","renovate[bot]","renovate%5Bbot%5D"] 20 | #versions=["minor", "patch"] 21 | 22 | [merge.message] 23 | body = "pull_request_body" 24 | body_type = "markdown" 25 | cut_body_after = "" 26 | cut_body_and_text = true 27 | cut_body_before = "" 28 | include_pr_number = true 29 | strip_html_comments = true 30 | title = "pull_request_title" 31 | 32 | [update] 33 | always = true 34 | #ignored_usernames = ["renovate"] 35 | autoupdate_label = "🔄️ Conflict" 36 | -------------------------------------------------------------------------------- /.github/actions/init/action.yml: -------------------------------------------------------------------------------- 1 | # name: 'Init' 2 | name: '💽️ ' 3 | description: 'Localized Init' 4 | author: 'JeromeFitz' 5 | 6 | inputs: 7 | node-version: 8 | default: '22' 9 | description: '🔢 Node version' 10 | required: true 11 | 12 | runs: 13 | using: 'composite' 14 | steps: 15 | - name: '🔧 pnpm: Install' 16 | id: pnpm-setup 17 | uses: pnpm/action-setup@v4 18 | with: 19 | run_install: false 20 | 21 | - name: '💽️ Node ${{ inputs.node-version }}' 22 | id: node-setup 23 | uses: actions/setup-node@v4 24 | with: 25 | cache-dependency-path: pnpm-lock.yaml 26 | cache: 'pnpm' 27 | node-version: ${{ inputs.node-version }} 28 | -------------------------------------------------------------------------------- /.github/actions/install/action.yml: -------------------------------------------------------------------------------- 1 | # name: 'Install' 2 | name: '📦️ ' 3 | description: 'Localized Install' 4 | author: 'JeromeFitz' 5 | 6 | runs: 7 | using: 'composite' 8 | steps: 9 | - name: '📦️ Dependencies' 10 | id: dependencies 11 | shell: bash 12 | run: | 13 | pnpm install --frozen-lockfile 14 | -------------------------------------------------------------------------------- /.github/actions/lint/action.yml: -------------------------------------------------------------------------------- 1 | # name: 'Lint' 2 | name: '🚨️ ' 3 | description: 'Localized Lint' 4 | author: 'JeromeFitz' 5 | 6 | inputs: 7 | TURBO_TEAM: 8 | description: 'Provide Team ID for Turbo' 9 | required: true 10 | type: string 11 | TURBO_TOKEN: 12 | description: 'Provide Token for Turbo' 13 | required: true 14 | type: string 15 | 16 | runs: 17 | using: 'composite' 18 | steps: 19 | # @todo(gh-actions) Separate `main` from PR 20 | - name: '🎨 Format' 21 | id: format 22 | shell: bash 23 | env: 24 | TURBO_TEAM: ${{ inputs.TURBO_TEAM }} 25 | TURBO_TOKEN: ${{ inputs.TURBO_TOKEN }} 26 | run: | 27 | pnpm run format:prettier:check 28 | 29 | # @todo(gh-actions) Separate `main` from PR 30 | - name: '🚨️ Lint' 31 | id: lint 32 | shell: bash 33 | env: 34 | TURBO_TEAM: ${{ inputs.TURBO_TEAM }} 35 | TURBO_TOKEN: ${{ inputs.TURBO_TOKEN }} 36 | run: | 37 | pnpm turbo run lint --cache-dir=".cache-turbo" 38 | -------------------------------------------------------------------------------- /.github/actions/release/action.yml: -------------------------------------------------------------------------------- 1 | # name: 'Release' 2 | name: '🏷️ ' 3 | description: 'Localized Release' 4 | author: 'JeromeFitz' 5 | 6 | inputs: 7 | GH_TOKEN: 8 | descirption: 'Provide GitHub Token' 9 | required: true 10 | type: string 11 | 12 | runs: 13 | using: 'composite' 14 | steps: 15 | - name: '🏷️ Release' 16 | id: release 17 | shell: bash 18 | env: 19 | GH_TOKEN: ${{ inputs.GH_TOKEN }} 20 | run: | 21 | pnpm semantic-release 22 | -------------------------------------------------------------------------------- /.github/actions/test/action.yml: -------------------------------------------------------------------------------- 1 | # name: 'Test' 2 | name: '🧪 ' 3 | description: 'Localized Test' 4 | author: 'JeromeFitz' 5 | 6 | inputs: 7 | TURBO_TEAM: 8 | description: 'Provide Team ID for Turbo' 9 | required: true 10 | type: string 11 | TURBO_TOKEN: 12 | description: 'Provide Token for Turbo' 13 | required: true 14 | type: string 15 | WEBSITE: 16 | description: 'Provide Website for Lighthouse' 17 | required: true 18 | type: string 19 | default: 'jeromefitzgerald.com' 20 | 21 | runs: 22 | using: 'composite' 23 | steps: 24 | - name: '🃏 Jest: unit' 25 | id: test-jest 26 | shell: bash 27 | run: pnpm turbo run test:unit --filter="${{ inputs.WEBSITE }}" --cache-dir=".cache-turbo" 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # vercel 12 | .next 13 | .turbo 14 | 15 | # next-pwa 16 | /public/fallback-*.js 17 | /public/sw.js 18 | /public/workbox-*.js 19 | 20 | # production 21 | dist 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | 32 | # local env files 33 | .env 34 | .env.* 35 | !.env.example 36 | # .env.build 37 | # .env.local 38 | # .env.development.local 39 | # .env.test.local 40 | # .env.production.local 41 | 42 | # vercel 43 | .vercel 44 | 45 | ## Custom 46 | .cache 47 | .cache-turbo 48 | .idea 49 | .lighthouseci 50 | .swc 51 | .tsbuildinfo 52 | build-info.json 53 | coverage 54 | e2e-report 55 | e2e-results 56 | out 57 | robots.txt 58 | sitemap.xml 59 | sitemap-*.xml 60 | storybook-static 61 | tsconfig.tsbuildinfo 62 | tsconfig.*.tsbuildinfo 63 | .vscode/** 64 | !.vscode/extensions.json 65 | !.vscode/settings.default.json 66 | 67 | ## ZZZ 68 | zzz 69 | 70 | # next 71 | sites/**/src/styles/output.css 72 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -n "$CI" ] && exit 0 3 | 4 | FILE_ENV=.env 5 | if [ -f "$FILE_ENV" ]; then 6 | # shellcheck disable=SC2046 7 | [ ! -f "$FILE_ENV" ] || export $(grep -v '^#' $FILE_ENV | xargs) 8 | fi 9 | 10 | # @todo(husky) In POSIX sh, [[ ]] is undefined. 11 | # shellcheck disable=SC3010 12 | # shellcheck disable=SC2009 13 | if ps -o args= $PPID | grep -E -q ' --no-verify| -n | -n$' ; then 14 | exit 0 15 | fi 16 | 17 | if [ "$HUSKY" = "0" ]; then 18 | exit 0 19 | fi 20 | 21 | if [ ! "$HUSKY__PRE_COMMIT__LINT_STAGED" = "0" ]; then 22 | pnpm lint-staged 23 | pnpm run lint:packages 24 | fi 25 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -n "$CI" ] && exit 0 3 | 4 | FILE_ENV=.env 5 | if [ -f "$FILE_ENV" ]; then 6 | # shellcheck disable=SC2046 7 | [ ! -f "$FILE_ENV" ] || export $(grep -v '^#' $FILE_ENV | xargs) 8 | fi 9 | 10 | if [ "$HUSKY" = "0" ]; then 11 | exit 0 12 | fi 13 | 14 | if [ ! "$HUSKY__PREPARE_COMMITMSG__CONVENTIONAL" = "0" ]; then 15 | exec < /dev/tty 16 | pnpm ccommit --hook || true 17 | fi 18 | -------------------------------------------------------------------------------- /.lintstagedrc.mjs: -------------------------------------------------------------------------------- 1 | import config from '@jeromefitz/lint-staged' 2 | 3 | export default config 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=false 2 | dedupe-peer-dependents=false 3 | ignore-dep-scripts=false 4 | enable-pre-post-scripts=true # next-sitemap requirement 5 | lockfile=true 6 | registry=https://registry.npmjs.org/ 7 | save-exact=true 8 | strict-peer-dependencies=false 9 | tag-version-prefix="" 10 | # https://pnpm.io/npmrc#public-hoist-pattern 11 | public-hoist-pattern[]=*ccommit* 12 | public-hoist-pattern[]=*eslint* 13 | public-hoist-pattern[]=*jest* 14 | public-hoist-pattern[]=*lint-staged* 15 | public-hoist-pattern[]=*playwright* 16 | public-hoist-pattern[]=*prettier* 17 | public-hoist-pattern[]=*semantic* 18 | public-hoist-pattern[]=*storybook* 19 | public-hoist-pattern[]=*testing-library* 20 | public-hoist-pattern[]=*types* 21 | # @note(pnpm) avoid if possible 22 | # shamefully-hoist=true 23 | 24 | # # # # # 25 | # # 26 | # # @hack(turbopack) for localized development (not ci) 27 | # # does not work yet, please keep using webpack 28 | # # 29 | # # -arch=arm64 --platform=darwin turbo 30 | # # reference: https://pnpm.io/pnpm-cli#differences-vs-npm 31 | # # 32 | # # npm_config_target_arch=arm64 33 | # # npm_config_target_platform=darwin 34 | # # 35 | # # pnpm install --config.target_arch=arm64 --config.target_platform=darwin --force 36 | # # 37 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | /.yarn 4 | .yarn 5 | **/_next/** 6 | **/.cache/** 7 | **/.cache-turbo/** 8 | **/.dist/** 9 | **/.lighthouseci/** 10 | **/.next/** 11 | **/.now/** 12 | **/.swc/** 13 | **/.types/** 14 | **/.vercel/** 15 | **/.vercel*/** 16 | **/bundles/** 17 | **/coverage/** 18 | **/dist/** 19 | **/e2e-report/** 20 | **/e2e-results/** 21 | **/out/** 22 | **/storybook-static/** 23 | 24 | **/deprecated/** 25 | **/fonts/** 26 | !/styles/fonts/** 27 | **/zzz--do-not-use/** 28 | **/zzz/** 29 | 30 | public/scripts/** 31 | next-env.d.ts 32 | 33 | # next-pwa 34 | /public/fallback-*.js 35 | /public/sw.js 36 | /public/workbox-*.js 37 | 38 | # transition 39 | todo/** 40 | 41 | # lock 42 | package-lock.json 43 | pnpm-lock.yaml 44 | yarn.lock 45 | .pnpm-store 46 | -------------------------------------------------------------------------------- /.prettierignore_staged: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | /.yarn 4 | .yarn 5 | **/_next/** 6 | **/.cache/** 7 | **/.cache-turbo/** 8 | **/.dist/** 9 | **/.lighthouseci/** 10 | **/.next/** 11 | **/.now/** 12 | **/.swc/** 13 | **/.types/** 14 | **/.vercel/** 15 | **/.vercel*/** 16 | **/bundles/** 17 | **/coverage/** 18 | **/dist/** 19 | **/e2e-report/** 20 | **/e2e-results/** 21 | **/out/** 22 | **/storybook-static/** 23 | 24 | **/deprecated/** 25 | **/fonts/** 26 | **/zzz--do-not-use/** 27 | **/zzz/** 28 | 29 | public/scripts/** 30 | next-env.d.ts 31 | 32 | # next-pwa 33 | /public/fallback-*.js 34 | /public/sw.js 35 | /public/workbox-*.js 36 | 37 | # transition 38 | todo/** 39 | 40 | # lock 41 | package-lock.json 42 | pnpm-lock.yaml 43 | yarn.lock 44 | .pnpm-store 45 | -------------------------------------------------------------------------------- /.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | import config from '@jeromefitz/prettier-config/tailwind' 2 | 3 | export default config 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "davidanson.vscode-markdownlint", 4 | "dbaeumer.vscode-eslint", 5 | "eamodio.gitlens", 6 | "editorconfig.editorconfig", 7 | "esbenp.prettier-vscode", 8 | "mgmcdermott.vscode-language-babel", 9 | "dangmai.workspace-default-settings" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2024 Nice Group of People, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /changelog.config.mjs: -------------------------------------------------------------------------------- 1 | import isCI from 'is-ci' 2 | 3 | if (!isCI) { 4 | const dotenv = await import('dotenv') 5 | dotenv.config({ path: './.env' }) 6 | } 7 | 8 | const isOverride = process.env.GIT_CZ__OVERRIDE_TEST || false 9 | 10 | const enabled = isOverride 11 | 12 | const _types = {} 13 | 14 | const commit = isOverride 15 | ? { 16 | after: { branchName: ' ', emoji: ' ', scope: ') ' }, 17 | before: { branchName: '', emoji: '', scope: '(' }, 18 | format: '{emoji}{scope}{branchName}{subject}', 19 | maxMessageLength: 64, 20 | minMessageLength: 3, 21 | questions: [ 22 | 'branchFlag', 23 | 'commitBreakingFlag', 24 | 'commitBreaking', 25 | // 'commitScopes', 26 | 'commitTypes', 27 | 'commitSubject', 28 | 'commitBodyFlag', 29 | 'commitBody', 30 | ], 31 | scopes: [], 32 | } 33 | : {} 34 | 35 | const branch = {} 36 | 37 | const types = isOverride ? _types : {} 38 | 39 | const changelog = { branch, commit, enabled, types } 40 | 41 | export default changelog 42 | -------------------------------------------------------------------------------- /config/release-branch-types/ci.cjs: -------------------------------------------------------------------------------- 1 | const ci = [] 2 | 3 | module.exports = ci 4 | -------------------------------------------------------------------------------- /config/release-branch-types/feature.cjs: -------------------------------------------------------------------------------- 1 | const feature = [] 2 | 3 | module.exports = feature 4 | -------------------------------------------------------------------------------- /config/release-branch-types/fix.cjs: -------------------------------------------------------------------------------- 1 | const fix = [] 2 | 3 | module.exports = fix 4 | -------------------------------------------------------------------------------- /config/release-branch-types/index.cjs: -------------------------------------------------------------------------------- 1 | const ci = require('./ci.cjs') 2 | const feature = require('./feature.cjs') 3 | const fix = require('./fix.cjs') 4 | const refactor = require('./refactor.cjs') 5 | const release = require('./release.cjs') 6 | 7 | /** 8 | * @todo To get a `prerelease` name these cannot be passed as RegEx. 9 | * With Node we can dynamically determine if it meets a RegEx 10 | * requirement and pass statically though (down the line). 11 | * 12 | * @todo We can "tell" what branch we are on prior to generation 13 | * and may be able to pass `feature/xyz` directly without 14 | * needing this set list to be the same for each branch in gitflow 15 | */ 16 | const releaseBranchTypes = { 17 | ci, 18 | feature, 19 | fix, 20 | release, 21 | refactor, 22 | } 23 | 24 | module.exports = releaseBranchTypes 25 | -------------------------------------------------------------------------------- /config/release-branch-types/refactor.cjs: -------------------------------------------------------------------------------- 1 | const refactor = [] 2 | 3 | module.exports = refactor 4 | -------------------------------------------------------------------------------- /config/release-branch-types/release.cjs: -------------------------------------------------------------------------------- 1 | const release = [] 2 | 3 | module.exports = release 4 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: string 3 | export default value 4 | } 5 | 6 | declare module '*.svg' { 7 | const value: string 8 | export default value 9 | } 10 | 11 | type Format = 'png' | 'jpeg' 12 | type Theme = 'light' | 'dark' 13 | 14 | interface Image { 15 | src: string 16 | width: string 17 | height: string 18 | } 19 | -------------------------------------------------------------------------------- /node-modules-inspector.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'node-modules-inspector' 2 | 3 | export default defineConfig({ 4 | defaultFilters: { 5 | excludeDts: true, 6 | excludes: ['*eslint*', '*lint-staged*', '*prettier*', '*semantic*'], 7 | excludeWorkspace: true, 8 | }, 9 | defaultSettings: { 10 | moduleTypeSimple: true, 11 | }, 12 | 13 | publint: true, 14 | }) 15 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-display: swap; 3 | font-family: 'Inter'; 4 | font-style: normal; 5 | font-weight: 100 900; 6 | src: url('/public/static/fonts/inter/inter-4.0.0-beta9g-var.woff2') format('woff2'); 7 | } 8 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | export { default } from '@jeromefitz/storybook-config/main.config' 2 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import '@jeromefitz/storybook-config/manager.config' 2 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import './font.css' 2 | 3 | import '@jeromefitz/tailwind-config/styles/globals.css' 4 | 5 | import '@radix-ui/themes/styles.css' 6 | 7 | export { default } from '@jeromefitz/storybook-config/preview.config' 8 | -------------------------------------------------------------------------------- /packages/design-system/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@jeromefitz/jest-config/jest.config.js') 2 | -------------------------------------------------------------------------------- /packages/design-system/next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path') 2 | 3 | const isCI = require('is-ci') 4 | !isCI && require('dotenv').config({ path: './.env' }) 5 | 6 | const buildInfoConfig = { 7 | owner: 'jeromefitz', 8 | repo: 'jeromefitzgerald.com', 9 | } 10 | 11 | const serverComponentsExternalPackages = [] 12 | const transpilePackages = [] 13 | 14 | module.exports = require('@jeromefitz/next-config')({ 15 | basePath: '', 16 | buildInfoConfig, 17 | pathDirName: path.join(__dirname), 18 | serverComponentsExternalPackages, 19 | transpilePackages, 20 | }) 21 | -------------------------------------------------------------------------------- /packages/design-system/postcss.config.js: -------------------------------------------------------------------------------- 1 | import configPostcss from '@jeromefitz/tailwind-config/postcss.config.js' 2 | 3 | export default configPostcss 4 | -------------------------------------------------------------------------------- /packages/design-system/public/static/fonts/inter/inter-4.0.0-beta9g-var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/public/static/fonts/inter/inter-4.0.0-beta9g-var.woff2 -------------------------------------------------------------------------------- /packages/design-system/public/static/fonts/inter/inter-var-full.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/public/static/fonts/inter/inter-var-full.woff2 -------------------------------------------------------------------------------- /packages/design-system/public/static/fonts/inter/inter-var-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/public/static/fonts/inter/inter-var-italic.woff2 -------------------------------------------------------------------------------- /packages/design-system/public/static/fonts/inter/inter-var-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/public/static/fonts/inter/inter-var-latin.woff2 -------------------------------------------------------------------------------- /packages/design-system/public/static/fonts/inter/inter-var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/public/static/fonts/inter/inter-var.woff2 -------------------------------------------------------------------------------- /packages/design-system/scripts/copy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### 4 | # @note(build): NPM Publishes from `./dist` 5 | ### 6 | 7 | cp package.json ./dist/ 8 | # cp README.md ./dist/ 9 | # cp ../../LICENSE ./dist/ 10 | 11 | ### 12 | # @note(build): Replace `dist/index` w/ `index` 13 | ### 14 | 15 | if [[ "$OSTYPE" == "darwin"* ]]; then 16 | sed -i "" "s|dist/index|index|g" dist/package.json 17 | else 18 | sed -i -e "s|dist/index|index|g" dist/package.json 19 | fi 20 | 21 | ### 22 | # @custom(build) 23 | ### 24 | 25 | if [[ "$OSTYPE" == "darwin"* ]]; then 26 | if [[ "$OSTYPE" == "darwin"* ]]; then 27 | sed -i "" "s|dist/||g" dist/package.json 28 | else 29 | sed -i -e "s|dist/||g" dist/package.json 30 | fi 31 | else 32 | sed -i -e "s|dist/||g" dist/package.json 33 | fi 34 | 35 | if [[ "$OSTYPE" == "darwin"* ]]; then 36 | if [[ "$OSTYPE" == "darwin"* ]]; then 37 | sed -i "" "s|src/||g" dist/package.json 38 | else 39 | sed -i -e "s|src/||g" dist/package.json 40 | fi 41 | else 42 | sed -i -e "s|src/||g" dist/package.json 43 | fi 44 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Anchor/index.ts: -------------------------------------------------------------------------------- 1 | export { Anchor } from './Anchor' 2 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Callout/Callout.tsx: -------------------------------------------------------------------------------- 1 | import type { RootProps as CalloutRootProps } from '@radix-ui/themes/dist/esm/components/callout.js' 2 | import type { ReactNode } from 'react' 3 | 4 | import { 5 | Icon as CalloutIcon, 6 | Root as CalloutRoot, 7 | Text as CalloutText, 8 | } from '@radix-ui/themes/dist/esm/components/callout.js' 9 | 10 | import { cx } from '../../utils/cx' 11 | import { FileTextIcon } from '../Icon/index' 12 | 13 | interface AdditionalProps { 14 | children?: ReactNode 15 | className?: string 16 | classNameText?: string 17 | color?: string 18 | icon?: any 19 | } 20 | type CalloutRootPropsImpl = AdditionalProps & CalloutRootProps 21 | 22 | function CalloutImpl({ 23 | children = <>This page is in the process of being updated., 24 | className = '', 25 | classNameText = '', 26 | color = 'pink', 27 | icon: Icon = FileTextIcon, 28 | size = '2', 29 | variant = 'soft', 30 | }: CalloutRootPropsImpl) { 31 | return ( 32 | 38 | 39 | 40 | 41 | {children} 42 | 43 | ) 44 | } 45 | 46 | export { CalloutImpl as Callout } 47 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Callout/index.ts: -------------------------------------------------------------------------------- 1 | export { Callout } from './Callout' 2 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Icon/Icon.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react' 2 | 3 | import { cx } from '../../utils/cx' 4 | import { MapIcon } from './Icon' 5 | 6 | const meta = { 7 | component: MapIcon, 8 | // @todo(eslint) storybook/no-title-property-in-meta 9 | title: 'Components/Icon', 10 | } satisfies Meta 11 | 12 | export default meta 13 | 14 | type Story = StoryObj 15 | 16 | export const Default: Story = { 17 | args: { 18 | className: cx(), 19 | }, 20 | argTypes: {}, 21 | } 22 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Icon/Icon.test.tsx: -------------------------------------------------------------------------------- 1 | import { expect } from '@jest/globals' 2 | import { composeStories } from '@storybook/react' 3 | import { render, screen } from '@testing-library/react' 4 | 5 | import * as stories from './Icon.stories' 6 | 7 | const IconStories = composeStories(stories) 8 | 9 | describe('Icon', () => { 10 | it('should contain a svg', () => { 11 | render() 12 | 13 | const icon = screen.getByRole('info', { hidden: true }) 14 | 15 | expect(icon).toBeInTheDocument() 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Icon/Icon.types.ts: -------------------------------------------------------------------------------- 1 | import { SVGAttributes } from 'react' 2 | 3 | /** 4 | * ref: https://github.com/radix-ui/icons/blob/master/packages/radix-icons/src/types.tsx 5 | */ 6 | interface IconProps extends SVGAttributes { 7 | children?: never 8 | color?: string 9 | label?: string 10 | style?: any 11 | } 12 | 13 | export type { IconProps } 14 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Content.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function SectionContent({ children, className = '' }) { 4 | return ( 5 |
24 |
27 | {children} 28 |
29 |
30 | ) 31 | } 32 | 33 | export { SectionContent } 34 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Header.Content.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function SectionHeaderContent({ children, className = '' }) { 4 | return ( 5 |
13 | {children} 14 |
15 | ) 16 | } 17 | 18 | export { SectionHeaderContent } 19 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Header.Title.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function SectionHeaderTitle({ children, className = '', isTitle = false }) { 4 | return ( 5 |

18 | {children} 19 |

20 | ) 21 | } 22 | 23 | export { SectionHeaderTitle } 24 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Header.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function SectionHeader({ children, className = '' }) { 4 | return ( 5 | <> 6 |
29 | {children} 30 |
31 | 32 | ) 33 | } 34 | 35 | export { SectionHeader } 36 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Hero.tsx: -------------------------------------------------------------------------------- 1 | function SectionHero({ title }) { 2 | return ( 3 |
4 |

{title}

5 |
6 | ) 7 | } 8 | 9 | export { SectionHero } 10 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.Wrapper.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function SectionWrapper({ children }) { 4 | return ( 5 |
6 |
16 | {children} 17 |
18 |
19 | ) 20 | } 21 | 22 | export { SectionWrapper } 23 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Section.test.ts: -------------------------------------------------------------------------------- 1 | describe('Section', () => { 2 | it('placeholder: moved to @jeromefitz/ds', () => { 3 | expect(true).toBe(true) 4 | }) 5 | }) 6 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/Tags.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '../../utils/cx' 2 | 3 | function Tags({ className = '', classNameTag = '', tags }) { 4 | // console.dir(`> tags:`) 5 | // console.dir(tags) 6 | return ( 7 |
    14 | {tags?.map((tag) => { 15 | const { color, id, name } = tag 16 | return ( 17 |
  • 36 | {name} 37 |
  • 38 | ) 39 | })} 40 |
41 | ) 42 | } 43 | 44 | export { Tags } 45 | -------------------------------------------------------------------------------- /packages/design-system/src/components/Section/index.ts: -------------------------------------------------------------------------------- 1 | export { SectionContent } from './Section.Content' 2 | export { SectionHeader } from './Section.Header' 3 | export { SectionHeaderContent } from './Section.Header.Content' 4 | export { SectionHeaderTitle } from './Section.Header.Title' 5 | export { SectionHero } from './Section.Hero' 6 | export { SectionWrapper } from './Section.Wrapper' 7 | export { Tags } from './Tags' 8 | -------------------------------------------------------------------------------- /packages/design-system/src/components/SkipNav/index.ts: -------------------------------------------------------------------------------- 1 | export { SkipNavContent, SkipNavLink } from './SkipNav' 2 | -------------------------------------------------------------------------------- /packages/design-system/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Anchor } from './Anchor/index' 2 | export { Callout } from './Callout/index' 3 | export { Icon } from './Icon/index' 4 | export { SkipNavContent, SkipNavLink } from './SkipNav/index' 5 | -------------------------------------------------------------------------------- /packages/design-system/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/index' 2 | -------------------------------------------------------------------------------- /packages/design-system/src/ui/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeromeFitz/websites/d4f1db1cfd7688eb468bcb8aeb707fd719844569/packages/design-system/src/ui/.gitkeep -------------------------------------------------------------------------------- /packages/design-system/src/utils/cx.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | function cx(...inputs: ClassValue[]) { 5 | // return twMerge(clsx(inputs)) 6 | return clsx(inputs) 7 | } 8 | 9 | export { cx, twMerge } 10 | -------------------------------------------------------------------------------- /packages/design-system/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "preserveSymlinks": true, 7 | // "rootDir": "src", 8 | 9 | "plugins": [ 10 | { 11 | "name": "next" 12 | } 13 | ], 14 | "strict": true, 15 | "strictNullChecks": true, 16 | "paths": { 17 | "@jeromefitz/next-config/*": ["../../packages/next-config/src/*"] 18 | } 19 | }, 20 | "include": ["src"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/design-system/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from 'tsup' 2 | 3 | import { defineConfig } from 'tsup' 4 | 5 | import { config as _config } from '../../tsup.config' 6 | 7 | const entry = ['src/**'] 8 | const config: Options = { 9 | ..._config, 10 | entry, 11 | tsconfig: './tsconfig.build.json', 12 | } 13 | 14 | export default defineConfig({ 15 | ...config, 16 | }) 17 | -------------------------------------------------------------------------------- /packages/jest-config/jest.config.js: -------------------------------------------------------------------------------- 1 | const jestNode = require('@jeromefitz/jest-presets/jest/node/jest-preset') 2 | const jestNext = require('next/jest') 3 | 4 | /** @type {import('jest').Config} */ 5 | const config = { 6 | coverageReporters: ['text', 'html'], 7 | // preset: '@jeromefitz/jest-presets/jest/node', 8 | setupFilesAfterEnv: ['@jeromefitz/jest-config/jest.setup.js'], 9 | testEnvironment: 'jest-environment-jsdom', 10 | watchman: false, 11 | ...jestNode, 12 | } 13 | 14 | const defineConfig = jestNext({ dir: './' }) 15 | module.exports = defineConfig(config) 16 | -------------------------------------------------------------------------------- /packages/jest-config/jest.setup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @note(jest) 6.x !extend expect 3 | * @ref https://github.com/testing-library/jest-dom/releases/tag/v6.0.0 4 | */ 5 | // import '@testing-library/jest-dom/jest-globals' 6 | // import '@testing-library/jest-dom' 7 | -------------------------------------------------------------------------------- /packages/jest-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jeromefitz/jest-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "devDependencies": { 6 | "@jeromefitz/jest-presets": "workspace:*", 7 | "@testing-library/dom": "10.4.0", 8 | "@testing-library/jest-dom": "6.6.3", 9 | "@testing-library/react": "16.3.0", 10 | "@testing-library/user-event": "14.6.1", 11 | "@types/jest": "29.5.14", 12 | "jest": "29.7.0", 13 | "jest-environment-jsdom": "29.7.0", 14 | "next": "15.3.3", 15 | "react": "19.1.0", 16 | "react-dom": "19.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/jest-presets/jest/node/jest-preset.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 3 | modulePathIgnorePatterns: [ 4 | '/test/__fixtures__', 5 | '/node_modules', 6 | '/dist', 7 | ], 8 | preset: 'ts-jest', 9 | roots: [''], 10 | transform: { 11 | '^.+\\.tsx?$': 'ts-jest', 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/jest-presets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jeromefitz/jest-presets", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./jest/node/jest-preset.js", 6 | "devDependencies": { 7 | "jest": "29.7.0", 8 | "ts-jest": "29.3.4" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/lighthouse-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jeromefitz/lighthouse-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./.lighthouserc.cjs" 6 | } 7 | -------------------------------------------------------------------------------- /packages/next-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jeromefitz/next-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./next.config.mjs", 6 | "devDependencies": { 7 | "@jeromefitz/prettier-config": "2.1.9", 8 | "@next/bundle-analyzer": "15.3.3", 9 | "@octokit/core": "7.0.2", 10 | "@plaiceholder/next": "3.0.0", 11 | "fast-json-stable-stringify": "2.1.0", 12 | "lodash": "4.17.21", 13 | "next": "15.3.3", 14 | "plaiceholder": "3.0.0", 15 | "react": "19.1.0", 16 | "react-dom": "19.1.0", 17 | "sharp": "0.34.1", 18 | "zod": "3.25.48" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/next-notion/README.md: -------------------------------------------------------------------------------- 1 | # next-notion 2 | 3 | README needs to be re-written. 4 | -------------------------------------------------------------------------------- /packages/next-notion/scripts/copy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### 4 | # @note(build): NPM Publishes from `./dist` 5 | ### 6 | 7 | cp package.json ./dist/ 8 | cp README.md ./dist/ 9 | cp ../../LICENSE ./dist/ 10 | 11 | ### 12 | # @note(build): Replace `dist/index` w/ `index` 13 | ### 14 | 15 | if [[ "$OSTYPE" == "darwin"* ]]; then 16 | sed -i "" "s|dist/index|index|g" dist/package.json 17 | else 18 | sed -i -e "s|dist/index|index|g" dist/package.json 19 | fi 20 | 21 | 22 | ### 23 | # @custom(build) 24 | ### 25 | 26 | if [[ "$OSTYPE" == "darwin"* ]]; then 27 | if [[ "$OSTYPE" == "darwin"* ]]; then 28 | sed -i "" "s|dist/||g" dist/package.json 29 | else 30 | sed -i -e "s|dist/||g" dist/package.json 31 | fi 32 | else 33 | sed -i -e "s|dist/||g" dist/package.json 34 | fi 35 | 36 | if [[ "$OSTYPE" == "darwin"* ]]; then 37 | if [[ "$OSTYPE" == "darwin"* ]]; then 38 | sed -i "" "s|src/||g" dist/package.json 39 | else 40 | sed -i -e "s|src/||g" dist/package.json 41 | fi 42 | else 43 | sed -i -e "s|src/||g" dist/package.json 44 | fi 45 | -------------------------------------------------------------------------------- /packages/next-notion/src/Notion.constants.ts: -------------------------------------------------------------------------------- 1 | import ms from 'ms' 2 | 3 | /** 4 | * @redis is in seconds not ms 5 | */ 6 | const getTimeInSeconds = (time: number) => (!time ? 0 : time / 1000) 7 | 8 | /** 9 | * @note in seconds 10 | * ...probably could be hard-coded 11 | */ 12 | const TIME = { 13 | DAY: getTimeInSeconds(ms('1d')), 14 | HOUR: getTimeInSeconds(ms('1h')), 15 | MINUTE: getTimeInSeconds(ms('1m')), 16 | MONTH: getTimeInSeconds(ms('30d')), 17 | YEAR: getTimeInSeconds(ms('1y')), 18 | } 19 | 20 | export { TIME } 21 | -------------------------------------------------------------------------------- /packages/next-notion/src/blocks/Column.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | BulletedListItemBlockObjectResponse, 3 | NumberedListItemBlockObjectResponse, 4 | } from '@notionhq/client/build/src/api-endpoints.js' 5 | 6 | import { forwardRef } from 'react' 7 | 8 | import { NotionBlocks as Blocks } from '../Notion.Blocks' 9 | import { getBlockKey } from '../Notion.utils' 10 | 11 | const Column = forwardRef(function Column(props: any, ref: any) { 12 | const { 13 | block, 14 | order, 15 | }: { 16 | block: BulletedListItemBlockObjectResponse | NumberedListItemBlockObjectResponse 17 | order: number 18 | } = props 19 | const key = getBlockKey(block.id, block.type, order) 20 | // const items = block[block.type][block.type] 21 | const items = block[block.type]?.results 22 | 23 | const Component = props?.as ?? 'div' 24 | const componentProps = { 25 | className: props?.className ?? undefined, 26 | } 27 | 28 | return ( 29 | 30 | {items.map((item, order) => { 31 | const blocksKey = `${key}--${order}` 32 | return 33 | })} 34 | 35 | ) 36 | }) 37 | 38 | export { Column } 39 | export default Column 40 | -------------------------------------------------------------------------------- /packages/next-notion/src/blocks/Divider.tsx: -------------------------------------------------------------------------------- 1 | import type { DividerBlockObjectResponse } from '@notionhq/client/build/src/api-endpoints.js' 2 | 3 | import { forwardRef } from 'react' 4 | 5 | import { getBlockKey } from '../Notion.utils' 6 | 7 | const Divider = forwardRef(function Divider(props: any, ref: any) { 8 | const { block, order }: { block: DividerBlockObjectResponse; order: number } = 9 | props 10 | const key = getBlockKey(block.id, block.type, order) 11 | 12 | const Component = props?.as ?? 'p' 13 | const componentProps = { 14 | className: props?.className ?? undefined, 15 | } 16 | 17 | return 18 | }) 19 | 20 | export { Divider } 21 | export default Divider 22 | -------------------------------------------------------------------------------- /packages/next-notion/src/blocks/Emoji.tsx: -------------------------------------------------------------------------------- 1 | import { EmojiWrapper } from './Emoji.server' 2 | // import { lazy, Suspense } from 'react' 3 | 4 | // // @note(next) outside of page.tsx, need to ignore 5 | // // eslint-disable-next-line @typescript-eslint/ban-ts-comment 6 | // // @ts-ignore 7 | // const EmojiWrapper = lazy(() => import('./Emoji.client')) 8 | 9 | // function NotionEmoji({ id, text }) { 10 | // return ( 11 | // <> 12 | // {text}}> 13 | // 14 | // 15 | // 16 | // ) 17 | // } 18 | 19 | function NotionEmoji({ id, text }) { 20 | return 21 | } 22 | 23 | export { NotionEmoji } 24 | -------------------------------------------------------------------------------- /packages/next-notion/src/blocks/ListBulleted.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | BulletedListItemBlockObjectResponse, 3 | NumberedListItemBlockObjectResponse, 4 | } from '@notionhq/client/build/src/api-endpoints.js' 5 | 6 | import { forwardRef } from 'react' 7 | 8 | import { NotionBlocks as Blocks } from '../Notion.Blocks' 9 | import { getBlockKey } from '../Notion.utils' 10 | 11 | const ListBulleted = forwardRef(function ListBulleted(props: any, ref: any) { 12 | const { 13 | block, 14 | order, 15 | }: { 16 | block: BulletedListItemBlockObjectResponse | NumberedListItemBlockObjectResponse 17 | order: number 18 | } = props 19 | const key = getBlockKey(block.id, block.type, order) 20 | const items = block[block.type][block.type] 21 | 22 | const Component = props?.as ?? 'ul' 23 | const componentProps = { 24 | className: props?.className ?? undefined, 25 | } 26 | 27 | return ( 28 | 29 | {items.map((item, order) => { 30 | const blocksKey = `${key}--${order}` 31 | return 32 | })} 33 | 34 | ) 35 | }) 36 | 37 | export { ListBulleted } 38 | export default ListBulleted 39 | -------------------------------------------------------------------------------- /packages/next-notion/src/helper.ts: -------------------------------------------------------------------------------- 1 | import { envServer as env } from '@jeromefitz/next-config/env.server.mjs' 2 | 3 | import { Client } from '@notionhq/client' 4 | 5 | const notion = new Client({ 6 | auth: env.NOTION_API_KEY, 7 | }) 8 | 9 | export { notion } 10 | -------------------------------------------------------------------------------- /packages/next-notion/src/index.ts: -------------------------------------------------------------------------------- 1 | import { uuidConverter, uuidValidate } from './utils/uuid' 2 | 3 | const strings = [ 4 | '27360d9b5f274dc2ac19ad09837b6860', 5 | '27360d9b5f274dc2ac19ad09837b6860a', 6 | '27360d9b-5f27-4dc2-ac19-ad09837b6860', 7 | '27360d9b-5f27-4dc2-ac19-ad09837b6860a', 8 | ] 9 | 10 | function foo() { 11 | strings.map((str) => { 12 | console.dir(`--- ---`) 13 | console.dir(`${str}: `) 14 | const isValid = uuidValidate(str) 15 | console.dir(`- [${isValid ? 'x' : ' '}] uuidValidate`) 16 | if (!isValid) { 17 | const _str = uuidConverter(str) 18 | console.dir(`- [${_str ? 'x' : ' '}] ${_str}`) 19 | } else { 20 | console.dir(`- [${isValid ? 'x' : ' '}] ${str}`) 21 | } 22 | }) 23 | } 24 | 25 | foo() 26 | 27 | export default foo 28 | -------------------------------------------------------------------------------- /packages/next-notion/src/queries/getBlockChildrenData.ts: -------------------------------------------------------------------------------- 1 | import 'server-only' 2 | 3 | import { notion } from '../helper' 4 | 5 | /** 6 | * @todo(error-handling) 7 | */ 8 | async function getBlockChildrenData(block_id) { 9 | const response = await notion.blocks.children.list({ 10 | block_id, 11 | page_size: 50, 12 | }) 13 | return response 14 | } 15 | 16 | export { getBlockChildrenData } 17 | -------------------------------------------------------------------------------- /packages/next-notion/src/queries/getColumnData.ts: -------------------------------------------------------------------------------- 1 | import 'server-only' 2 | 3 | import { asyncForEach } from '@jeromefitz/utils' 4 | 5 | import _noop from 'lodash/noop.js' 6 | 7 | import { getBlockChildrenData } from './getBlockChildrenData' 8 | 9 | async function getColumnData(columnListData) { 10 | const columnResults: any = [] 11 | await asyncForEach(columnListData.results, async (columnData: any) => { 12 | const columnDataColumn = await getBlockChildrenData(columnData.id) 13 | const column = { 14 | ...columnData, 15 | columnDataColumn, 16 | } 17 | columnResults.push(column) 18 | }).catch(_noop) 19 | const columnList = { 20 | column_list: { 21 | ...columnListData, 22 | results: columnResults, 23 | }, 24 | } 25 | return columnList 26 | } 27 | 28 | export { getColumnData } 29 | -------------------------------------------------------------------------------- /packages/next-notion/src/queries/getPageData.ts: -------------------------------------------------------------------------------- 1 | import 'server-only' 2 | 3 | // import { cache } from 'react' 4 | // import type { GetPageResponse } from '@notionhq/client/build/src/api-endpoints.js' 5 | // import type { PageObjectResponseShow } from '../../shows/[[...catchAll]]/Show.types' 6 | import { notion } from '../helper' 7 | 8 | type PageData = any 9 | 10 | async function getPageData(page_id) { 11 | // const getPageData = cache(async (page_id) => { 12 | // console.dir(`(2) page_id: ${page_id}`) 13 | // // if ((_startsWith(page_id), '/events') || page_id === undefined) return null 14 | // console.dir(`(3) page_id: ${page_id}`) 15 | // // return {} 16 | const response: PageData = await notion.pages.retrieve({ 17 | page_id, 18 | }) 19 | // console.dir(`(4) response: ${response?.id}`) 20 | // console.dir(response) 21 | return response 22 | } 23 | // ) 24 | 25 | export { getPageData } 26 | -------------------------------------------------------------------------------- /packages/next-notion/src/queries/index.ts: -------------------------------------------------------------------------------- 1 | export { getBlockChildrenData } from './getBlockChildrenData' 2 | export { getBlockChildrenDataParent } from './getBlockChildrenDataParent' 3 | export { getColumnData } from './getColumnData' 4 | export { getDatabaseQuery, getDatabaseQueryByDateRange } from './getDatabaseQuery' 5 | export { getPageData } from './getPageData' 6 | -------------------------------------------------------------------------------- /packages/next-notion/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // export { isAwsImage, isAwsImageExpired, isImageExpired } from './getAwsImage' 2 | export { isAwsImage, isImageExpired } from './getAwsImage' 3 | export { getPropertyTypeData } from './getPropertyTypeData' 4 | export { getSegmentInfo } from './getSegmentInfo' 5 | -------------------------------------------------------------------------------- /packages/next-notion/src/utils/uuid.ts: -------------------------------------------------------------------------------- 1 | import { validate as uuidValidate } from 'uuid' 2 | 3 | const delimiter = '-' 4 | const indexes = [8, 13, 18, 23] 5 | 6 | function insertString(str: string, index: number, value: string) { 7 | return str.substr(0, index) + value + str.substr(index) 8 | } 9 | 10 | function setDelimeter(_uuid: string) { 11 | indexes.map((idx) => { 12 | _uuid = insertString(_uuid, idx, delimiter) 13 | }) 14 | return _uuid 15 | } 16 | 17 | function uuidConverter(_uuid: string) { 18 | if (uuidValidate(_uuid)) return _uuid 19 | if (_uuid.length === 32) return setDelimeter(_uuid) 20 | return null 21 | } 22 | 23 | export { uuidConverter, uuidValidate } 24 | -------------------------------------------------------------------------------- /packages/next-notion/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from 'tsup' 2 | 3 | import { defineConfig } from 'tsup' 4 | 5 | import { config as _config } from '../../tsup.config' 6 | 7 | const entry = ['src/**'] 8 | const config: Options = { 9 | ..._config, 10 | entry, 11 | format: ['esm'], 12 | } 13 | 14 | export default defineConfig({ 15 | ...config, 16 | }) 17 | -------------------------------------------------------------------------------- /packages/playwright-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jeromefitz/playwright-config", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "main": "./playwright.config.ts", 7 | "devDependencies": { 8 | "@playwright/test": "1.52.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/shared/scripts/copy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### 4 | # @note(build): NPM Publishes from `./dist` 5 | ### 6 | 7 | cp package.json ./dist/ 8 | # cp README.md ./dist/ 9 | # cp ../../LICENSE ./dist/ 10 | 11 | ### 12 | # @note(build): Replace `dist/index` w/ `index` 13 | ### 14 | 15 | if [[ "$OSTYPE" == "darwin"* ]]; then 16 | sed -i "" "s|dist/index|index|g" dist/package.json 17 | else 18 | sed -i -e "s|dist/index|index|g" dist/package.json 19 | fi 20 | 21 | ### 22 | # @custom(build) 23 | ### 24 | 25 | if [[ "$OSTYPE" == "darwin"* ]]; then 26 | if [[ "$OSTYPE" == "darwin"* ]]; then 27 | sed -i "" "s|dist/||g" dist/package.json 28 | else 29 | sed -i -e "s|dist/||g" dist/package.json 30 | fi 31 | else 32 | sed -i -e "s|dist/||g" dist/package.json 33 | fi 34 | 35 | if [[ "$OSTYPE" == "darwin"* ]]; then 36 | if [[ "$OSTYPE" == "darwin"* ]]; then 37 | sed -i "" "s|src/||g" dist/package.json 38 | else 39 | sed -i -e "s|src/||g" dist/package.json 40 | fi 41 | else 42 | sed -i -e "s|src/||g" dist/package.json 43 | fi 44 | -------------------------------------------------------------------------------- /packages/shared/src/components/Analytics/Analytics.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react' 2 | 3 | import { FathomAnalytics } from './Fathom' 4 | import { VercelAnalytics, VercelSpeedInsights } from './Vercel' 5 | 6 | function Analytics() { 7 | return ( 8 | <> 9 | 10 | 11 | 12 | 13 | 14 | 15 | ) 16 | } 17 | 18 | export { Analytics } 19 | -------------------------------------------------------------------------------- /packages/shared/src/components/Analytics/Fathom.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { envClient as env } from '@jeromefitz/next-config/env.client.mjs' 3 | 4 | import { load, trackPageview } from 'fathom-client' 5 | import { usePathname, useSearchParams } from 'next/navigation.js' 6 | import { useEffect } from 'react' 7 | 8 | function FathomAnalytics() { 9 | const pathname = usePathname() 10 | const searchParams = useSearchParams() 11 | useEffect(() => { 12 | if (env.IS_PRODUCTION) { 13 | load(env.NEXT_PUBLIC__FATHOM_SITE_ID, { 14 | honorDNT: true, 15 | includedDomains: [env.NEXT_PUBLIC__SITE], 16 | url: `https://cdn.usefathom.com/script.js`, 17 | }) 18 | } 19 | }, []) 20 | 21 | useEffect(() => { 22 | if (!pathname) return 23 | trackPageview({ 24 | referrer: document.referrer, 25 | url: pathname + searchParams.toString(), 26 | }) 27 | }, [pathname, searchParams]) 28 | 29 | return null 30 | } 31 | 32 | export { FathomAnalytics } 33 | -------------------------------------------------------------------------------- /packages/shared/src/components/Analytics/Vercel.tsx: -------------------------------------------------------------------------------- 1 | import { envClient as env } from '@jeromefitz/next-config/env.client.mjs' 2 | 3 | import { Analytics } from '@vercel/analytics/react' 4 | import { SpeedInsights } from '@vercel/speed-insights/next' 5 | 6 | function VercelAnalytics() { 7 | return env.IS_VERCEL ? : null 8 | } 9 | 10 | function VercelSpeedInsights() { 11 | return env.IS_VERCEL ? : null 12 | } 13 | 14 | export { VercelAnalytics, VercelSpeedInsights } 15 | -------------------------------------------------------------------------------- /packages/shared/src/components/Analytics/index.ts: -------------------------------------------------------------------------------- 1 | export { Analytics } from './Analytics' 2 | export { FathomAnalytics } from './Fathom' 3 | export { VercelAnalytics, VercelSpeedInsights } from './Vercel' 4 | -------------------------------------------------------------------------------- /packages/shared/src/components/Navigation/Navigation.tsx: -------------------------------------------------------------------------------- 1 | function Navigation() { 2 | return ( 3 | <> 4 | <> 5 | 6 | ) 7 | } 8 | 9 | export { Navigation } 10 | -------------------------------------------------------------------------------- /packages/shared/src/components/Navigation/index.ts: -------------------------------------------------------------------------------- 1 | export { Navigation } from './Navigation' 2 | -------------------------------------------------------------------------------- /packages/shared/src/components/Notion/Blocks/Embed.Spotify.tsx: -------------------------------------------------------------------------------- 1 | function EmbedSpotify({ id }) { 2 | return ( 3 |
4 |