{"id":20932914,"url":"https://github.com/jferrl/codingtales","last_synced_at":"2026-04-19T19:01:31.464Z","repository":{"id":198893413,"uuid":"701743363","full_name":"jferrl/codingtales","owner":"jferrl","description":"CodingTales blog code.","archived":false,"fork":false,"pushed_at":"2024-03-30T18:08:52.000Z","size":4300,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-13T02:24:29.744Z","etag":null,"topics":["blog","nextjs"],"latest_commit_sha":null,"homepage":"https://codingtales.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jferrl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"timlrx"}},"created_at":"2023-10-07T12:38:50.000Z","updated_at":"2023-10-13T10:30:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"776c20ec-c93a-4dcb-ac4e-e792662843f4","html_url":"https://github.com/jferrl/codingtales","commit_stats":null,"previous_names":["jferrl/codingtales"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jferrl/codingtales","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jferrl%2Fcodingtales","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jferrl%2Fcodingtales/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jferrl%2Fcodingtales/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jferrl%2Fcodingtales/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jferrl","download_url":"https://codeload.github.com/jferrl/codingtales/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jferrl%2Fcodingtales/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265846883,"owners_count":23838160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blog","nextjs"],"created_at":"2024-11-18T21:53:45.128Z","updated_at":"2026-04-19T19:01:26.402Z","avatar_url":"https://github.com/jferrl.png","language":"TypeScript","funding_links":["https://github.com/sponsors/timlrx"],"categories":[],"sub_categories":[],"readme":"# CodingTales Blog\n\n## Quick Start Guide\n\n1. Clone the repo\n2. Personalize `siteMetadata.js` (site related information)\n3. Modify the content security policy in `next.config.js` if you want to use\n   other analytics provider or a commenting solution other than giscus.\n4. Personalize `authors/default.md` (main author)\n5. Modify `projectsData.js`\n6. Modify `headerNavLinks.js` to customize navigation links\n7. Add blog posts\n8. Deploy on Vercel\n\n## Installation\n\n```bash\nyarn\n```\n\n## Development\n\nFirst, run the development server:\n\n```bash\nyarn dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nEdit the layout in `app` or content in `data`. With live reloading, the pages auto-updates as you edit them.\n\n## Extend / Customize\n\n`data/siteMetadata.js` - contains most of the site related information which should be modified for a user's need.\n\n`data/authors/default.md` - default author information (required). Additional authors can be added as files in `data/authors`.\n\n`data/projectsData.js` - data used to generate styled card on the projects page.\n\n`data/headerNavLinks.js` - navigation links.\n\n`data/logo.svg` - replace with your own logo.\n\n`data/blog` - replace with your own blog posts.\n\n`public/static` - store assets such as images and favicons.\n\n`tailwind.config.js` and `css/tailwind.css` - tailwind configuration and stylesheet which can be modified to change the overall look and feel of the site.\n\n`css/prism.css` - controls the styles associated with the code blocks. Feel free to customize it and use your preferred prismjs theme e.g. [prism themes](https://github.com/PrismJS/prism-themes).\n\n`contentlayer.config.ts` - configuration for Contentlayer, including definition of content sources and MDX plugins used. See [Contentlayer documentation](https://www.contentlayer.dev/docs/getting-started) for more information.\n\n`components/MDXComponents.js` - pass your own JSX code or React component by specifying it over here. You can then use them directly in the `.mdx` or `.md` file. By default, a custom link, `next/image` component, table of contents component and Newsletter form are passed down. Note that the components should be default exported to avoid [existing issues with Next.js](https://github.com/vercel/next.js/issues/51593).\n\n`layouts` - main templates used in pages:\n\n- There are currently 3 post layouts available: `PostLayout`, `PostSimple` and `PostBanner`. `PostLayout` is the default 2 column layout with meta and author information. `PostSimple` is a simplified version of `PostLayout`, while `PostBanner` features a banner image.\n- There are 2 blog listing layouts: `ListLayout`, the layout used in version 1 of the template with a search bar and `ListLayoutWithTags`, currently used in version 2, which omits the search bar but includes a sidebar with information on the tags.\n\n`app` - pages to route to. Read the [Next.js documentation](https://nextjs.org/docs/app) for more information.\n\n`next.config.js` - configuration related to Next.js. You need to adapt the Content Security Policy if you want to load scripts, images etc. from other domains.\n\n## Post\n\nContent is modelled using [Contentlayer](https://www.contentlayer.dev/), which allows you to define your own content schema and use it to generate typed content objects. See [Contentlayer documentation](https://www.contentlayer.dev/docs/getting-started) for more information.\n\n### Frontmatter\n\nFrontmatter follows [Hugo's standards](https://gohugo.io/content-management/front-matter/).\n\nPlease refer to `contentlayer.config.ts` for an up to date list of supported fields. The following fields are supported:\n\n```\ntitle (required)\ndate (required)\ntags (optional)\nlastmod (optional)\ndraft (optional)\nsummary (optional)\nimages (optional)\nauthors (optional list which should correspond to the file names in `data/authors`. Uses `default` if none is specified)\nlayout (optional list which should correspond to the file names in `data/layouts`)\ncanonicalUrl (optional, canonical url for the post for SEO)\n```\n\nHere's an example of a post's frontmatter:\n\n```\n---\ntitle: 'Introducing Tailwind Nexjs Starter Blog'\ndate: '2021-01-12'\nlastmod: '2021-01-18'\ntags: ['next-js', 'tailwind', 'guide']\ndraft: false\nsummary: 'Looking for a performant, out of the box template, with all the best in web technology to support your blogging needs? Checkout the Tailwind Nextjs Starter Blog template.'\nimages: ['/static/images/canada/mountains.jpg', '/static/images/canada/toronto.jpg']\nauthors: ['default', 'sparrowhawk']\nlayout: PostLayout\ncanonicalUrl: https://tailwind-nextjs-starter-blog.vercel.app/blog/introducing-tailwind-nextjs-starter-blog\n---\n```\n\n## Deploy\n\n**Vercel**  \nThe easiest way to deploy the template is to deploy on [Vercel](https://vercel.com). Check out the [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.\n\n**Netlify**\n[Netlify](https://www.netlify.com/)’s Next.js runtime configures enables key Next.js functionality on your website without the need for additional configurations. Netlify generates serverless functions that will handle Next.js functionalities such as server-side rendered (SSR) pages, incremental static regeneration (ISR), `next/images`, etc.\n\nSee [Next.js on Netlify](https://docs.netlify.com/integrations/frameworks/next-js/overview/#next-js-runtime) for suggested configuration values and more details.\n\n**Static hosting services / GitHub Pages / S3 / Firebase etc.**\n\n1. Add `output: 'export'` in `next.config.js`. See [static exports documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#configuration) for more information.\n2. Comment out `headers()` from `next.config.js`.\n3. Change `components/Image.tsx` to use a standard `\u003cimg\u003e` tag instead of `next/image`:\n\n   ```ts\n   /* eslint-disable jsx-a11y/alt-text */\n   /* eslint-disable @next/next/no-img-element */\n   import NextImage, { ImageProps } from 'next/image'\n\n   // @ts-ignore\n   const Image = ({ ...rest }: ImageProps) =\u003e \u003cimg {...rest} /\u003e\n\n   export default Image\n   ```\n\n   Alternatively, to continue using `next/image`, you can use an alternative image optimization provider such as Imgix, Cloudinary or Akamai. See [image optimization documentation](https://nextjs.org/docs/app/building-your-application/deploying/static-exports#image-optimization) for more details.\n\n4. Remove `api` folder and components which call the server-side function such as the Newsletter component. Not technically required and the site will build successfully, but the APIs cannot be used as they are server-side functions.\n5. Run `yarn build`. The generated static content is in the `out` folder.\n6. Deploy the `out` folder to your hosting service of choice or run `npx serve out` to view the website locally.\n\n## Frequently Asked Questions\n\n### How can I add a custom MDX component?\n\nHere's an example on how to create a donut chart from Chart.js (assuming you already have the dependencies installed) and use it in MDX posts. First, create a new `DonutChart.tsx` component in `components`:\n\n```tsx\n'use client'\n\nimport { Doughnut } from 'react-chartjs-2'\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'\n\nChartJS.register(ArcElement, Tooltip, Legend)\n\nconst DonutChart = ({ data }) =\u003e {\n  return \u003cDoughnut data={data} /\u003e\n}\n\nexport default Doughnut\n```\n\nSince the underlying `Doughnut` component uses React hooks, we add the `'use client'` directive to specify that it is a client side component. Also, there is an existing issue which prevents named components from being used, so we need to export the component as the default export.\n\nNext, add the component to `MDXComponents.tsx`:\n\n```diff\n...\n+ import DonutChart from './DonutChart'\n\nexport const components: MDXComponents = {\n  Image,\n  TOCInline,\n  a: CustomLink,\n  pre: Pre,\n+  DonutChart,\n  BlogNewsletterForm,\n}\n```\n\nYou can now use the component in `.mdx` files:\n\n```mdx\n## Example Donut Chart\n\nexport const data = {\n  labels: ['Red', 'Blue', 'Yellow'],\n  datasets: [\n    {\n      label: '# of Votes',\n      data: [12, 19, 3],\n      backgroundColor: [\n        'rgba(255, 99, 132, 0.2)',\n        'rgba(54, 162, 235, 0.2)',\n        'rgba(255, 206, 86, 0.2)',\n      ],\n      borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'],\n      borderWidth: 1,\n    },\n  ],\n}\n\n\u003cDonutChart data={data} /\u003e\n```\n### How can I customize the `kbar` search?\nAdd a `SearchProvider` component such as the one shown below and use it in place of the default `SearchProvider` component in `app/layout.tsx`.\n`defaultActions` are the initial list of actions.\n`onSearchDocumentsLoad` is a callback function that is called when the documents specified by `searchDocumentsPath` are loaded. Set `searchDocumentsPath` to `false` to disable the dynamically loaded search feature.\n```tsx\n'use client'\n\nimport { KBarSearchProvider } from 'pliny/search/KBar'\nimport { useRouter } from 'next/navigation'\nimport { CoreContent } from 'pliny/utils/contentlayer'\nimport { Blog } from 'contentlayer/generated'\n\nexport const SearchProvider = ({ children }) =\u003e {\n  const router = useRouter()\n  return (\n    \u003cKBarSearchProvider\n      kbarConfig={{\n        searchDocumentsPath: 'search.json',\n        defaultActions: [\n          {\n            id: 'homepage',\n            name: 'Homepage',\n            keywords: '',\n            shortcut: ['h', 'h'],\n            section: 'Home',\n            perform: () =\u003e router.push('/'),\n          },\n          {\n            id: 'projects',\n            name: 'Projects',\n            keywords: '',\n            shortcut: ['p'],\n            section: 'Home',\n            perform: () =\u003e router.push('/projects'),\n          },\n        ],\n        onSearchDocumentsLoad(json) {\n          return json.map((post: CoreContent\u003cBlog\u003e) =\u003e ({\n            id: post.path,\n            name: post.title,\n            keywords: post?.summary || '',\n            section: 'Blog',\n            subtitle: post.tags.join(', '),\n            perform: () =\u003e router.push(post.path),\n          }))\n        },\n      }}\n    \u003e\n      {children}\n    \u003c/KBarSearchProvider\u003e\n  )\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjferrl%2Fcodingtales","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjferrl%2Fcodingtales","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjferrl%2Fcodingtales/lists"}