├── .dockerignore ├── .editorconfig ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .vscode └── extensions.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── README.md ├── license.md ├── package.json ├── packages ├── blog-starter-kit │ └── themes │ │ ├── enterprise │ │ ├── .env.example │ │ ├── .eslintrc.js │ │ ├── .graphqlrc.yml │ │ ├── @types │ │ │ └── remark-html.d.ts │ │ ├── README.md │ │ ├── assets │ │ │ ├── PlusJakartaSans-Bold.ttf │ │ │ ├── PlusJakartaSans-ExtraBold.ttf │ │ │ ├── PlusJakartaSans-Medium.ttf │ │ │ ├── PlusJakartaSans-Regular.ttf │ │ │ └── PlusJakartaSans-SemiBold.ttf │ │ ├── codegen.yml │ │ ├── components │ │ │ ├── about-author.tsx │ │ │ ├── analytics.tsx │ │ │ ├── avatar.tsx │ │ │ ├── button.tsx │ │ │ ├── co-authors-modal.tsx │ │ │ ├── container.tsx │ │ │ ├── contexts │ │ │ │ └── appContext.tsx │ │ │ ├── cover-image.tsx │ │ │ ├── custom-image.tsx │ │ │ ├── date-formatter.tsx │ │ │ ├── footer.tsx │ │ │ ├── header.tsx │ │ │ ├── hero-post.tsx │ │ │ ├── icons │ │ │ │ ├── index.js │ │ │ │ └── svgs │ │ │ │ │ ├── ArticleSVG.js │ │ │ │ │ ├── BookOpenSVG.js │ │ │ │ │ ├── ChevronDownSVG.js │ │ │ │ │ ├── CloseSVG.js │ │ │ │ │ ├── ExternalArrowSVG.js │ │ │ │ │ ├── GithubSVG.js │ │ │ │ │ ├── HamburgerSVG.js │ │ │ │ │ ├── HashnodeSVG.js │ │ │ │ │ ├── LinkedinSVG.js │ │ │ │ │ ├── NewsletterPlusSVG.js │ │ │ │ │ ├── PlusCircleSVG.js │ │ │ │ │ ├── RssSVG.js │ │ │ │ │ ├── XSVG.js │ │ │ │ │ └── index.js │ │ │ ├── integrations.tsx │ │ │ ├── layout.tsx │ │ │ ├── markdown-styles.module.css │ │ │ ├── markdown-to-html.tsx │ │ │ ├── meta.tsx │ │ │ ├── more-posts.tsx │ │ │ ├── navbar.tsx │ │ │ ├── post-author-info.tsx │ │ │ ├── post-comments.tsx │ │ │ ├── post-header.tsx │ │ │ ├── post-preview.tsx │ │ │ ├── post-read-time-in-minutes.tsx │ │ │ ├── post-title.tsx │ │ │ ├── post-toc.tsx │ │ │ ├── profile-image.js │ │ │ ├── progressive-image.tsx │ │ │ ├── publication-logo.tsx │ │ │ ├── resizable-image.js │ │ │ ├── scripts.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── searchbar.tsx │ │ │ ├── secondary-post.tsx │ │ │ ├── section-separator.tsx │ │ │ ├── sidebar.tsx │ │ │ ├── social-links.tsx │ │ │ ├── subscribe-form.tsx │ │ │ └── subscribe.tsx │ │ ├── generated │ │ │ ├── graphql.ts │ │ │ └── schema.graphql │ │ ├── lib │ │ │ └── api │ │ │ │ ├── fragments │ │ │ │ ├── PageInfo.graphql │ │ │ │ ├── Post.graphql │ │ │ │ └── Publication.graphql │ │ │ │ ├── mutations │ │ │ │ └── SubscribeToNewsletter.graphql │ │ │ │ └── queries │ │ │ │ ├── DraftById.graphql │ │ │ │ ├── PageByPublication.graphql │ │ │ │ ├── PostsByPublication.graphql │ │ │ │ ├── PublicationByHost.graphql │ │ │ │ ├── RSSFeed.graphql │ │ │ │ ├── SearchPostsOfPublication.graphql │ │ │ │ ├── SeriesPostsByPublication.graphql │ │ │ │ ├── SinglePostByPublication.graphql │ │ │ │ ├── Sitemap.graphql │ │ │ │ ├── SlugPostsByPublication.graphql │ │ │ │ └── TagPostsByPublication.graphql │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── [slug].tsx │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ ├── api │ │ │ │ └── og │ │ │ │ │ ├── home.tsx │ │ │ │ │ └── post.tsx │ │ │ ├── dashboard.tsx │ │ │ ├── index.tsx │ │ │ ├── preview │ │ │ │ └── [id].tsx │ │ │ ├── robots.txt.tsx │ │ │ ├── rss.xml.tsx │ │ │ ├── series │ │ │ │ └── [slug].tsx │ │ │ ├── sitemap.xml.tsx │ │ │ └── tag │ │ │ │ └── [slug].tsx │ │ ├── postcss.config.js │ │ ├── process-env.d.ts │ │ ├── public │ │ │ ├── assets │ │ │ │ └── blog │ │ │ │ │ ├── authors │ │ │ │ │ ├── jj.jpeg │ │ │ │ │ ├── joe.jpeg │ │ │ │ │ └── tim.jpeg │ │ │ │ │ ├── dynamic-routing │ │ │ │ │ └── cover.jpg │ │ │ │ │ ├── hello-world │ │ │ │ │ └── cover.jpg │ │ │ │ │ └── preview │ │ │ │ │ └── cover.jpg │ │ │ ├── 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 │ │ │ └── js │ │ │ │ └── iframe-resizer.js │ │ ├── styles │ │ │ └── index.css │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── utils │ │ │ └── const │ │ │ │ └── index.ts │ │ └── vercel.json │ │ ├── hashnode │ │ ├── .env.example │ │ ├── .eslintrc.js │ │ ├── .graphqlrc.yml │ │ ├── @types │ │ │ └── remark-html.d.ts │ │ ├── README.md │ │ ├── assets │ │ │ ├── PlusJakartaSans-Bold.ttf │ │ │ ├── PlusJakartaSans-ExtraBold.ttf │ │ │ ├── PlusJakartaSans-Medium.ttf │ │ │ ├── PlusJakartaSans-Regular.ttf │ │ │ └── PlusJakartaSans-SemiBold.ttf │ │ ├── codegen.yml │ │ ├── components │ │ │ ├── about-author.tsx │ │ │ ├── analytics.tsx │ │ │ ├── blog-post-preview.tsx │ │ │ ├── co-authors-modal.tsx │ │ │ ├── comments-sheet.tsx │ │ │ ├── common-header-icon-btn.tsx │ │ │ ├── container.tsx │ │ │ ├── contexts │ │ │ │ └── appContext.tsx │ │ │ ├── custom-button.tsx │ │ │ ├── custom-image.tsx │ │ │ ├── draft-floating-menu.tsx │ │ │ ├── features-posts.tsx │ │ │ ├── fonts │ │ │ │ └── index.tsx │ │ │ ├── header-blog-search.tsx │ │ │ ├── header-left-sidebar.tsx │ │ │ ├── header-tooltip.tsx │ │ │ ├── header.tsx │ │ │ ├── hn-button.tsx │ │ │ ├── icons │ │ │ │ ├── index.js │ │ │ │ └── svgs │ │ │ │ │ ├── AlertSVG.js │ │ │ │ │ ├── ArticleSVG.js │ │ │ │ │ ├── BadgeDollarSVG.js │ │ │ │ │ ├── BarsSVG.js │ │ │ │ │ ├── BookOpenSVG.js │ │ │ │ │ ├── ChartMixedSVG.js │ │ │ │ │ ├── CheckSVG.js │ │ │ │ │ ├── ChevronDownSVG.js │ │ │ │ │ ├── ChevronDownSVGV2.js │ │ │ │ │ ├── ChevronDownSVG_16x16.js │ │ │ │ │ ├── ChevronLeftSVG.js │ │ │ │ │ ├── ChevronRightSVG_16x16.js │ │ │ │ │ ├── ChevronUpSVG_16x16.js │ │ │ │ │ ├── ClipboardSVG.js │ │ │ │ │ ├── CloseSVG.js │ │ │ │ │ ├── CommentSVGV2.js │ │ │ │ │ ├── EarthSVG.js │ │ │ │ │ ├── ExternalArrowSVG.js │ │ │ │ │ ├── ExternalLinkSVG.js │ │ │ │ │ ├── FacebookSVGRound.js │ │ │ │ │ ├── FeaturedStarV2SVG.js │ │ │ │ │ ├── FileLineChartSVG.js │ │ │ │ │ ├── GithubSVG.js │ │ │ │ │ ├── HackernewsSVGV2.js │ │ │ │ │ ├── HamburgerSVG.js │ │ │ │ │ ├── HashnodeLogoIconV2.js │ │ │ │ │ ├── HashnodeSVG.js │ │ │ │ │ ├── HeadphonesSVG.js │ │ │ │ │ ├── InstagramSVG.js │ │ │ │ │ ├── LinkAltSVG.js │ │ │ │ │ ├── LinkSVGV2.js │ │ │ │ │ ├── LinkedInSVGV2.js │ │ │ │ │ ├── LinkedinSVG.js │ │ │ │ │ ├── ListSVG.js │ │ │ │ │ ├── MastodonSVG.js │ │ │ │ │ ├── NewsletterPlusSVG.js │ │ │ │ │ ├── NoCommentsDarkSVG.js │ │ │ │ │ ├── NoCommentsLightSVG.js │ │ │ │ │ ├── PaperPlaneSVG.js │ │ │ │ │ ├── PencilSVG.js │ │ │ │ │ ├── PinSVG.js │ │ │ │ │ ├── PlusCircleSVG.js │ │ │ │ │ ├── RedditSVG.js │ │ │ │ │ ├── RedditSVGV2.js │ │ │ │ │ ├── RefreshSVG.js │ │ │ │ │ ├── RobotSVG.js │ │ │ │ │ ├── RssSVG.js │ │ │ │ │ ├── SearchSvg.js │ │ │ │ │ ├── ShareSVGV2.tsx │ │ │ │ │ ├── TwitterXSVG.js │ │ │ │ │ ├── WhatsappSVG.js │ │ │ │ │ ├── XSVG.js │ │ │ │ │ ├── YoutubeSVG.js │ │ │ │ │ └── index.js │ │ │ ├── integrations.tsx │ │ │ ├── layout.tsx │ │ │ ├── magazine-blog-post-preview.tsx │ │ │ ├── markdown-styles.module.css │ │ │ ├── meta.tsx │ │ │ ├── modern-layout-posts.tsx │ │ │ ├── other-posts-of-account.tsx │ │ │ ├── post-author-info.tsx │ │ │ ├── post-comments-sidebar.tsx │ │ │ ├── post-comments.tsx │ │ │ ├── post-floating-bar-tooltip-wrapper.tsx │ │ │ ├── post-floating-bar.tsx │ │ │ ├── post-header.tsx │ │ │ ├── post-page-navbar.tsx │ │ │ ├── post-share-widget.tsx │ │ │ ├── post-view.tsx │ │ │ ├── profile-image.js │ │ │ ├── progressive-image.tsx │ │ │ ├── pub-loader-component.tsx │ │ │ ├── publication-footer.tsx │ │ │ ├── publication-logo.tsx │ │ │ ├── publication-meta.tsx │ │ │ ├── publication-nav-links-dropdown.tsx │ │ │ ├── publication-nav-links.tsx │ │ │ ├── publication-posts.tsx │ │ │ ├── publication-search.tsx │ │ │ ├── publication-sidebar-nav-links.tsx │ │ │ ├── publication-sidebar.tsx │ │ │ ├── publication-social-link-item.tsx │ │ │ ├── publication-social-links.tsx │ │ │ ├── publication-subscribe-standout.tsx │ │ │ ├── resizable-image.js │ │ │ ├── response-footer.tsx │ │ │ ├── response-list.tsx │ │ │ ├── response-reply-card.tsx │ │ │ ├── scripts.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── section-separator.tsx │ │ │ ├── separator-root.js │ │ │ ├── static-page-content.tsx │ │ │ ├── toast.js │ │ │ ├── toc-render-design.tsx │ │ │ ├── toc-sheet.tsx │ │ │ └── use-sticky-nav-scroll.tsx │ │ ├── generated │ │ │ ├── graphql.ts │ │ │ └── schema.graphql │ │ ├── lib │ │ │ └── api │ │ │ │ ├── client.ts │ │ │ │ ├── fragments │ │ │ │ ├── Draft.graphql │ │ │ │ ├── PageInfo.graphql │ │ │ │ ├── Post.graphql │ │ │ │ ├── PostThumbnail.graphql │ │ │ │ ├── Publication.graphql │ │ │ │ └── StaticPage.graphql │ │ │ │ ├── mutations │ │ │ │ └── SubscribeToNewsletter.graphql │ │ │ │ └── queries │ │ │ │ ├── DraftById.graphql │ │ │ │ ├── HomePage.graphql │ │ │ │ ├── Newsletter.graphql │ │ │ │ ├── PageByPublication.graphql │ │ │ │ ├── PostsByPublication.graphql │ │ │ │ ├── PublicationByHost.graphql │ │ │ │ ├── RSSFeed.graphql │ │ │ │ ├── SearchPostsOfPublication.graphql │ │ │ │ ├── SeriesPageInitial.graphql │ │ │ │ ├── SeriesPostsByPublication.graphql │ │ │ │ ├── SinglePostByPublication.graphql │ │ │ │ ├── Sitemap.graphql │ │ │ │ ├── SlugPostsByPublication.graphql │ │ │ │ ├── Tag.graphql │ │ │ │ └── TagPostsByPublication.graphql │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── [slug].tsx │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ ├── api │ │ │ │ └── og │ │ │ │ │ ├── home.tsx │ │ │ │ │ └── post.tsx │ │ │ ├── dashboard.tsx │ │ │ ├── index.tsx │ │ │ ├── newsletter.tsx │ │ │ ├── preview │ │ │ │ └── [id].tsx │ │ │ ├── robots.txt.tsx │ │ │ ├── rss.xml.tsx │ │ │ ├── series │ │ │ │ └── [slug].tsx │ │ │ ├── sitemap.xml.tsx │ │ │ └── tag │ │ │ │ └── [slug].tsx │ │ ├── postcss.config.js │ │ ├── process-env.d.ts │ │ ├── public │ │ │ ├── assets │ │ │ │ └── blog │ │ │ │ │ ├── authors │ │ │ │ │ ├── jj.jpeg │ │ │ │ │ ├── joe.jpeg │ │ │ │ │ └── tim.jpeg │ │ │ │ │ ├── dynamic-routing │ │ │ │ │ └── cover.jpg │ │ │ │ │ ├── hello-world │ │ │ │ │ └── cover.jpg │ │ │ │ │ └── preview │ │ │ │ │ └── cover.jpg │ │ │ ├── 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 │ │ │ └── js │ │ │ │ └── iframe-resizer.js │ │ ├── styles │ │ │ └── index.css │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── types │ │ │ ├── Badge.ts │ │ │ ├── Page.ts │ │ │ ├── Post.ts │ │ │ ├── Publication.ts │ │ │ ├── Response.ts │ │ │ ├── Series.ts │ │ │ ├── User.ts │ │ │ ├── external │ │ │ │ └── mongodb.d.ts │ │ │ ├── extras.ts │ │ │ └── index.ts │ │ ├── utils │ │ │ ├── autolinker.js │ │ │ ├── commonUtils.ts │ │ │ ├── const │ │ │ │ ├── images.ts │ │ │ │ ├── index.ts │ │ │ │ └── styles.ts │ │ │ ├── getReadTime.js │ │ │ ├── gsspHelpers.ts │ │ │ ├── handle-math-jax.js │ │ │ ├── image.js │ │ │ ├── index.js │ │ │ ├── toast.tsx │ │ │ └── urls.ts │ │ └── vercel.json │ │ └── personal │ │ ├── .env.example │ │ ├── .eslintrc.js │ │ ├── .graphqlrc.yml │ │ ├── @types │ │ └── remark-html.d.ts │ │ ├── README.md │ │ ├── assets │ │ ├── PlusJakartaSans-Bold.ttf │ │ ├── PlusJakartaSans-ExtraBold.ttf │ │ ├── PlusJakartaSans-Medium.ttf │ │ ├── PlusJakartaSans-Regular.ttf │ │ └── PlusJakartaSans-SemiBold.ttf │ │ ├── codegen.yml │ │ ├── components │ │ ├── analytics.tsx │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ ├── container.tsx │ │ ├── contexts │ │ │ └── appContext.tsx │ │ ├── cover-image.tsx │ │ ├── date-formatter.tsx │ │ ├── footer.tsx │ │ ├── icons │ │ │ ├── index.js │ │ │ └── svgs │ │ │ │ ├── ArticleSVG.js │ │ │ │ ├── ChevronDownSVG.js │ │ │ │ ├── ExternalArrowSVG.js │ │ │ │ ├── GithubSVG.js │ │ │ │ ├── HamburgerSVG.js │ │ │ │ ├── HashnodeSVG.js │ │ │ │ ├── LinkedinSVG.js │ │ │ │ ├── Moon.js │ │ │ │ ├── NewsletterPlusSVG.js │ │ │ │ ├── PlusCircleSVG.js │ │ │ │ ├── RssSVG.js │ │ │ │ ├── Sun.js │ │ │ │ ├── XSVG.js │ │ │ │ └── index.js │ │ ├── integrations.tsx │ │ ├── layout.tsx │ │ ├── markdown-styles.module.css │ │ ├── markdown-to-html.tsx │ │ ├── meta.tsx │ │ ├── minimal-post-preview.tsx │ │ ├── minimal-posts.tsx │ │ ├── personal-theme-header.tsx │ │ ├── scripts.tsx │ │ ├── section-separator.tsx │ │ └── toggle-theme.tsx │ │ ├── generated │ │ ├── graphql.ts │ │ └── schema.graphql │ │ ├── lib │ │ └── api │ │ │ ├── fragments │ │ │ ├── PageInfo.graphql │ │ │ ├── Post.graphql │ │ │ └── Publication.graphql │ │ │ └── queries │ │ │ ├── DraftById.graphql │ │ │ ├── PageByPublication.graphql │ │ │ ├── PostsByPublication.graphql │ │ │ ├── PublicationByHost.graphql │ │ │ ├── RSSFeed.graphql │ │ │ ├── SinglePostByPublication.graphql │ │ │ ├── Sitemap.graphql │ │ │ ├── SlugPostsByPublication.graphql │ │ │ └── TagPostsByPublication.graphql │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ ├── [slug].tsx │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── api │ │ │ └── og │ │ │ │ ├── home.tsx │ │ │ │ └── post.tsx │ │ ├── dashboard.tsx │ │ ├── index.tsx │ │ ├── preview │ │ │ └── [id].tsx │ │ ├── robots.txt.tsx │ │ ├── rss.xml.tsx │ │ ├── sitemap.xml.tsx │ │ └── tag │ │ │ └── [slug].tsx │ │ ├── postcss.config.js │ │ ├── process-env.d.ts │ │ ├── public │ │ ├── assets │ │ │ └── blog │ │ │ │ ├── authors │ │ │ │ ├── jj.jpeg │ │ │ │ ├── joe.jpeg │ │ │ │ └── tim.jpeg │ │ │ │ ├── dynamic-routing │ │ │ │ └── cover.jpg │ │ │ │ ├── hello-world │ │ │ │ └── cover.jpg │ │ │ │ └── preview │ │ │ │ └── cover.jpg │ │ ├── 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 │ │ └── js │ │ │ └── iframe-resizer.js │ │ ├── styles │ │ └── index.css │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── utils │ │ └── const │ │ │ └── index.ts │ │ └── vercel.json ├── eslint-config-custom │ ├── index.js │ └── package.json ├── tsconfig │ ├── base.json │ ├── nextjs.json │ └── package.json └── utils │ ├── feed.ts │ ├── handle-math-jax.js │ ├── image.ts │ ├── package.json │ ├── renderer │ ├── consts │ │ └── images.ts │ ├── headingSlugger.ts │ ├── highlight.js │ ├── hooks │ │ └── useEmbeds.tsx │ ├── image.ts │ ├── markdownToHtml.ts │ ├── marked.js │ ├── sanitizeHTMLOptions.js │ └── services │ │ ├── HNRequest.ts │ │ └── embed.ts │ ├── seo │ ├── addArticleJsonLd.ts │ ├── addPublicationJsonLd.ts │ └── sitemap.ts │ ├── social │ └── og.ts │ └── trigger-custom-widget-embed.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── prettier.config.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | .gitignore -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_size = 2 7 | indent_style = tabs 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | # Markdown syntax specifies that trailing whitespaces can be meaningful, 12 | # so let’s not trim those. e.g. 2 trailing spaces = linebreak (
) 13 | # See https://daringfireball.net/projects/markdown/syntax#p 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.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 | **/node_modules 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | **/.next/ 14 | /.next/ 15 | /out/ 16 | 17 | # production 18 | /build 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env* 31 | !.env.example 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts 39 | 40 | # vscode 41 | .vscode/* 42 | !.vscode/extensions.json -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache 3 | .next 4 | */*.yml 5 | generated -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | COPY . /app 4 | 5 | # Set the working directory 6 | WORKDIR /app 7 | 8 | # Install pnpm 9 | RUN npm install -g pnpm 10 | 11 | # By default, use the enterprise theme 12 | ARG THEME=enterprise 13 | 14 | WORKDIR /app/packages/blog-starter-kit/themes/${THEME} 15 | RUN cp .env.example .env.local 16 | RUN pnpm install --frozen-lockfile 17 | 18 | RUN pnpm build 19 | 20 | # Expose the port Next.js runs on 21 | EXPOSE 3000 22 | 23 | # Run the Next.js start script 24 | CMD ["pnpm", "start"] 25 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Hashnode. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hashnode-starter-kit", 3 | "version": "1.0.0", 4 | "description": "An OSS Starter Kit to roll out frontends using Hashnode Public APIs", 5 | "keywords": [], 6 | "license": "MIT", 7 | "author": "", 8 | "scripts": { 9 | "format": "prettier --write \"**/*.{js,jsx,ts,tsx,md,json}\"", 10 | "preinstall": "npx only-allow pnpm" 11 | }, 12 | "dependencies": { 13 | "classnames": "^2.3.1", 14 | "next": "^13.4.19", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^18.0.3", 20 | "@types/react": "^18.0.15", 21 | "@types/react-dom": "^18.0.6", 22 | "prettier": "^3.0.3", 23 | "prettier-plugin-organize-imports": "^3.2.3", 24 | "prettier-plugin-packagejson": "^2.4.6", 25 | "prettier-plugin-tailwindcss": "^0.5.5", 26 | "tailwindcss": "^3.3.3", 27 | "typescript": "^5.2.2" 28 | }, 29 | "engines": { 30 | "node": ">=18.0.0", 31 | "pnpm": ">=8.0.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_HASHNODE_GQL_ENDPOINT=https://gql.hashnode.com 2 | NEXT_PUBLIC_HASHNODE_PUBLICATION_HOST=engineering.hashnode.com 3 | NEXT_PUBLIC_MODE=development -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@starter-kit/eslint-config-custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/.graphqlrc.yml: -------------------------------------------------------------------------------- 1 | schema: './generated/schema.graphql' 2 | documents: './{pages,components,lib}/**/*.{graphql,js,ts,jsx,tsx}' 3 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/@types/remark-html.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'remark-html'; 2 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/README.md: -------------------------------------------------------------------------------- 1 | # A statically generated blog example using Next.js, Markdown, and TypeScript with Hashnode 💫 2 | 3 | This is the existing [blog-starter](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) plus TypeScript, wired with [Hashnode](https://hashnode.com). 4 | 5 | We've used [Hashnode APIs](https://apidocs.hashnode.com) and integrated them with this blog starter kit. 6 | 7 | ## Want to have your own? 8 | 9 | Fork it and change the environment variable `NEXT_PUBLIC_HASHNODE_PUBLICATION_HOST` to your host (engineering.hashnode.dev is the host in the example) and deploy it to Vercel. That's it! You now have your own frontend. You can still use Hashnode for writing your Articles. 10 | 11 | Demo of the `enterprise` theme: [https://demo.hashnode.com/engineering](https://demo.hashnode.com/engineering). 12 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hashnode/starter-kit/b90275211c2cf594391b14e17771abb4837c5e84/packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Bold.ttf -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hashnode/starter-kit/b90275211c2cf594391b14e17771abb4837c5e84/packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-ExtraBold.ttf -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hashnode/starter-kit/b90275211c2cf594391b14e17771abb4837c5e84/packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Medium.ttf -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hashnode/starter-kit/b90275211c2cf594391b14e17771abb4837c5e84/packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-Regular.ttf -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hashnode/starter-kit/b90275211c2cf594391b14e17771abb4837c5e84/packages/blog-starter-kit/themes/enterprise/assets/PlusJakartaSans-SemiBold.ttf -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/codegen.yml: -------------------------------------------------------------------------------- 1 | schema: https://gql.hashnode.com 2 | documents: './**/*.graphql' 3 | generates: 4 | ./generated/schema.graphql: 5 | plugins: 6 | - schema-ast 7 | config: 8 | includeDirectives: true 9 | ./generated/graphql.ts: 10 | plugins: 11 | - typescript 12 | - typescript-operations 13 | - typed-document-node 14 | config: 15 | scalars: 16 | Date: string 17 | DateTime: string 18 | ObjectId: string 19 | JSONObject: Record 20 | Decimal: string 21 | CurrencyCode: string 22 | ImageContentType: string 23 | ImageUrl: string 24 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/about-author.tsx: -------------------------------------------------------------------------------- 1 | import PostAuthorInfo from './post-author-info'; 2 | import { useAppContext } from './contexts/appContext'; 3 | import { PostFullFragment } from '../generated/graphql'; 4 | 5 | function AboutAuthor() { 6 | const { post: _post } = useAppContext(); 7 | const post = _post as unknown as PostFullFragment; 8 | const { publication, author } = post; 9 | let coAuthors = post.coAuthors || []; 10 | 11 | const allAuthors = publication?.isTeam ? [author, ...coAuthors] : [author]; 12 | 13 | return ( 14 |
15 |
16 |
17 |

18 | Written by 19 |

20 |
21 | {allAuthors.map((_author) => { 22 | return ( 23 | 27 | ); 28 | })} 29 |
30 |
31 |
32 |
33 | ); 34 | } 35 | 36 | export default AboutAuthor; -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/avatar.tsx: -------------------------------------------------------------------------------- 1 | import { resizeImage } from '@starter-kit/utils/image'; 2 | import { DEFAULT_AVATAR } from '../utils/const'; 3 | 4 | type Props = { 5 | username: string; 6 | name: string; 7 | picture: string | null | undefined; 8 | size: number; 9 | }; 10 | 11 | export const Avatar = ({ username, name, picture, size }: Props) => { 12 | return ( 13 |
14 | 24 | {name} 29 | 30 |
31 | 32 | {name} 33 | 34 |
35 |
36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/container.tsx: -------------------------------------------------------------------------------- 1 | type Props = { 2 | children?: React.ReactNode; 3 | className?: string; 4 | }; 5 | 6 | export const Container = ({ children, className }: Props) => { 7 | return
{children}
; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/contexts/appContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext } from 'react'; 2 | import { 3 | PostFullFragment, 4 | PublicationFragment, 5 | SeriesPostsByPublicationQuery, 6 | StaticPageFragment, 7 | } from '../../generated/graphql'; 8 | 9 | type AppContext = { 10 | publication: PublicationFragment; 11 | post: PostFullFragment | null; 12 | page: StaticPageFragment | null; 13 | series: NonNullable['series']; 14 | }; 15 | 16 | const AppContext = createContext(null); 17 | 18 | const AppProvider = ({ 19 | children, 20 | publication, 21 | post, 22 | page, 23 | series, 24 | }: { 25 | children: React.ReactNode; 26 | publication: PublicationFragment; 27 | post?: PostFullFragment | null; 28 | page?: StaticPageFragment | null; 29 | series?: NonNullable['series']; 30 | }) => { 31 | return ( 32 | 40 | {children} 41 | 42 | ); 43 | }; 44 | 45 | const useAppContext = () => { 46 | const context = useContext(AppContext); 47 | 48 | if (!context) { 49 | throw new Error('useAppContext must be used within a '); 50 | } 51 | 52 | return context; 53 | }; 54 | export { AppProvider, useAppContext }; 55 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/cover-image.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import Link from 'next/link'; 3 | 4 | type Props = { 5 | title: string; 6 | src: string; 7 | slug?: string; 8 | priority?: boolean; 9 | }; 10 | 11 | export const CoverImage = ({ title, src, slug, priority = false }: Props) => { 12 | const postURL = `/${slug}`; 13 | 14 | const image = ( 15 |
16 | {`Cover 24 |
25 | ); 26 | return ( 27 |
28 | {slug ? ( 29 | 30 | {image} 31 | 32 | ) : ( 33 | image 34 | )} 35 |
36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/date-formatter.tsx: -------------------------------------------------------------------------------- 1 | import { format, parseISO } from 'date-fns'; 2 | 3 | type Props = { 4 | dateString: string; 5 | }; 6 | 7 | export const DateFormatter = ({ dateString }: Props) => { 8 | if (!dateString) return <>; 9 | const date = parseISO(dateString); 10 | 11 | return ( 12 | <> 13 | 14 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/index.js: -------------------------------------------------------------------------------- 1 | export * from './svgs'; 2 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/ArticleSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ArticleSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/BookOpenSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class BookOpenSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/ChevronDownSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ChevronDownSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/CloseSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class CloseSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/ExternalArrowSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class ExternalArrowSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/GithubSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class GithubSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/HamburgerSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class HamburgerSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/HashnodeSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class HashnodeSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 12 | 17 | 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/LinkedinSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class LinkedinSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/PlusCircleSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class PlusCircleSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/RssSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class RssSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 14 | 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/XSVG.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class XSVG extends React.Component { 4 | render() { 5 | return ( 6 | 7 | 13 | 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/icons/svgs/index.js: -------------------------------------------------------------------------------- 1 | import ArticleSVG from './ArticleSVG'; 2 | import ChevronDownSVG from './ChevronDownSVG'; 3 | import ExternalArrowSVG from './ExternalArrowSVG'; 4 | import GithubSVG from './GithubSVG'; 5 | import HashnodeSVG from './HashnodeSVG'; 6 | import LinkedinSVG from './LinkedinSVG'; 7 | import NewsletterPlusSVG from './NewsletterPlusSVG'; 8 | import PlusCircleSVG from './PlusCircleSVG'; 9 | import RssSVG from './RssSVG'; 10 | import XSVG from './XSVG'; 11 | 12 | export { 13 | ArticleSVG, 14 | ChevronDownSVG, 15 | ExternalArrowSVG, 16 | GithubSVG, 17 | HashnodeSVG, 18 | LinkedinSVG, 19 | NewsletterPlusSVG, 20 | PlusCircleSVG, 21 | RssSVG, 22 | XSVG, 23 | }; 24 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Analytics } from './analytics'; 2 | import { Integrations } from './integrations'; 3 | import { Meta } from './meta'; 4 | import { Scripts } from './scripts'; 5 | 6 | type Props = { 7 | children: React.ReactNode; 8 | }; 9 | 10 | export const Layout = ({ children }: Props) => { 11 | return ( 12 | <> 13 | 14 | 15 |
16 |
{children}
17 |
18 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/markdown-styles.module.css: -------------------------------------------------------------------------------- 1 | .markdown { 2 | @apply text-lg leading-relaxed; 3 | } 4 | 5 | .markdown p, 6 | .markdown ul, 7 | .markdown ol, 8 | .markdown blockquote { 9 | @apply my-6; 10 | } 11 | 12 | .markdown h2 { 13 | @apply text-3xl mt-12 mb-4 leading-snug; 14 | } 15 | 16 | .markdown h3 { 17 | @apply text-2xl mt-8 mb-4 leading-snug; 18 | } 19 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/markdown-to-html.tsx: -------------------------------------------------------------------------------- 1 | import { useEmbeds } from '@starter-kit/utils/renderer/hooks/useEmbeds'; 2 | import { markdownToHtml } from '@starter-kit/utils/renderer/markdownToHtml'; 3 | import { memo } from 'react'; 4 | 5 | type Props = { 6 | contentMarkdown: string; 7 | }; 8 | 9 | const _MarkdownToHtml = ({ contentMarkdown }: Props) => { 10 | const content = markdownToHtml(contentMarkdown); 11 | useEmbeds({ enabled: true }); 12 | 13 | return ( 14 |
18 | ); 19 | }; 20 | 21 | export const MarkdownToHtml = memo(_MarkdownToHtml); 22 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/meta.tsx: -------------------------------------------------------------------------------- 1 | import parse from 'html-react-parser'; 2 | import Head from 'next/head'; 3 | import { useAppContext } from './contexts/appContext'; 4 | 5 | export const Meta = () => { 6 | const { publication } = useAppContext(); 7 | const { metaTags, favicon } = publication; 8 | const defaultFavicons = ( 9 | <> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | 19 | return ( 20 | 21 | {favicon ? : defaultFavicons} 22 | 23 | 24 | {metaTags && parse(metaTags)} 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/more-posts.tsx: -------------------------------------------------------------------------------- 1 | import { PostFragment } from '../generated/graphql'; 2 | import { PostPreview } from './post-preview'; 3 | 4 | type Props = { 5 | posts: PostFragment[]; 6 | context: 'home' | 'series' | 'tag'; 7 | }; 8 | 9 | export const MorePosts = ({ posts, context }: Props) => { 10 | return ( 11 |
12 | {context === 'home' && ( 13 |

14 | More Posts 15 |

16 | )} 17 |
18 | {posts.map((post) => ( 19 | 31 | ))} 32 |
33 |
34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/navbar.tsx: -------------------------------------------------------------------------------- 1 | import { Search } from './searchbar'; 2 | import { SocialLinks } from './social-links'; 3 | 4 | export const Navbar = () => { 5 | return ( 6 |
7 | 8 | 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/post-read-time-in-minutes.tsx: -------------------------------------------------------------------------------- 1 | import BookOpenSVG from './icons/svgs/BookOpenSVG'; 2 | 3 | type Props = { readTimeInMinutes: number }; 4 | 5 | export const ReadTimeInMinutes = ({ readTimeInMinutes }: Props) => { 6 | return ( 7 | <> 8 |

9 | 10 | {readTimeInMinutes} min read 11 |

12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/post-title.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | type Props = { 4 | children?: ReactNode; 5 | }; 6 | 7 | export const PostTitle = ({ children }: Props) => { 8 | return ( 9 |
10 |

{children}

11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/publication-logo.tsx: -------------------------------------------------------------------------------- 1 | import { resizeImage } from '@starter-kit/utils/image'; 2 | import Link from 'next/link'; 3 | import { useAppContext } from './contexts/appContext'; 4 | import { PublicationFragment } from '../generated/graphql'; 5 | 6 | const getPublicationLogo = (publication: PublicationFragment, isSidebar?: boolean) => { 7 | if (isSidebar) { 8 | return publication.preferences.logo; // Always display light mode logo in sidebar 9 | } 10 | return publication.preferences.darkMode?.logo || publication.preferences.logo; 11 | } 12 | 13 | export const PublicationLogo = ({ isSidebar }: { isSidebar?: boolean }) => { 14 | const { publication } = useAppContext(); 15 | const PUBLICATION_LOGO = getPublicationLogo(publication, isSidebar); 16 | 17 | return ( 18 |

19 | 24 | {PUBLICATION_LOGO ? ( 25 | <> 26 | {publication.title} 31 | Blog 32 | 33 | ) : ( 34 | 39 | {publication.title} 40 | 41 | )} 42 | 43 |

44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/resizable-image.js: -------------------------------------------------------------------------------- 1 | import { ProgressiveImage } from './progressive-image'; 2 | 3 | function ResizableImage(props) { 4 | const { src, alt, resize, className, ...restOfTheProps } = props; 5 | 6 | return ( 7 | 8 | ); 9 | } 10 | 11 | export default ResizableImage; 12 | export { ResizableImage }; -------------------------------------------------------------------------------- /packages/blog-starter-kit/themes/enterprise/components/scripts.tsx: -------------------------------------------------------------------------------- 1 | export const Scripts = () => { 2 | const googleAnalytics = ` 3 | window.dataLayer = window.dataLayer || []; 4 | function gtag(){window.dataLayer.push(arguments);} 5 | gtag('js', new Date());`; 6 | return ( 7 | <> 8 |