{"id":20696083,"url":"https://github.com/haliphax/haliphax-dot-dev","last_synced_at":"2025-07-23T12:34:27.680Z","repository":{"id":37381338,"uuid":"373414842","full_name":"haliphax/haliphax-dot-dev","owner":"haliphax","description":"https://haliphax.dev source code and content, built with 🎈 Eleventy","archived":false,"fork":false,"pushed_at":"2025-06-19T18:16:46.000Z","size":1972,"stargazers_count":2,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-19T18:44:04.629Z","etag":null,"topics":["blog","eleventy","eleventy-website","feather-icons","github-pages","halfmoon","nodejs","site-generator","static-site","typescript"],"latest_commit_sha":null,"homepage":"https://haliphax.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/haliphax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-03T07:11:46.000Z","updated_at":"2025-06-19T18:16:50.000Z","dependencies_parsed_at":"2023-10-03T03:29:35.172Z","dependency_job_id":"58b6642c-8d89-40bb-84da-ee7eb0db0184","html_url":"https://github.com/haliphax/haliphax-dot-dev","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/haliphax/haliphax-dot-dev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haliphax%2Fhaliphax-dot-dev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haliphax%2Fhaliphax-dot-dev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haliphax%2Fhaliphax-dot-dev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haliphax%2Fhaliphax-dot-dev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haliphax","download_url":"https://codeload.github.com/haliphax/haliphax-dot-dev/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haliphax%2Fhaliphax-dot-dev/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266680274,"owners_count":23967791,"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","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","eleventy","eleventy-website","feather-icons","github-pages","halfmoon","nodejs","site-generator","static-site","typescript"],"created_at":"2024-11-17T00:12:30.168Z","updated_at":"2025-07-23T12:34:27.656Z","avatar_url":"https://github.com/haliphax.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# haliphax.dev\n\nThe source code for https://haliphax.dev and its accompanying processes;\nproudly built with [🎈 Eleventy][]!\n\n## 🌳 Directory structure\n\nThe directory structure used by this site may be considered \"nonstandard\" when\ncompared to the Eleventy documentation and various starter site templates, but\nI personally find it much easier to reason with.\n\n- `.github` Definitions for GitHub actions\n- `11ty` Eleventy code and data\n  - `data` Global data\n    - `external` Data from external sources\n  - `events` Eleventy engine event handlers\n  - `functions` Global functions (filters)\n  - `layouts` Template layouts\n  - `libraries` Libraries used by the engine\n  - `plugins` Plugins used by the engine\n  - `transforms` Transforms for content manipulation\n- `content` Renderable site content\n  - `pages` Content pages\n  - `posts` Blog posts\n- `static` Static files, copied verbatim\n  - `css` Stylesheets\n  - `img` Images\n- `tasks` Node scripts for out-of-band tasks\n\n## 🛠️ Configuration structure\n\nIn addition to a nonstandard directory structure, I have built my own\nconfiguration structure in an effort to wrangle the many pieces'\nresponsibilities.\n\nThe various pieces Eleventy needs to consume during\nits configuration phase are all divided into their own categorical folders\nbeneath the `11ty` directory. Each of these folders contains a `_config.ts`\nfile (with the exception of the `data` folder, which is automatically parsed by\nEleventy).\n\nThe `_config.ts` file is used to collate all of that category's members\ntogether and to expose a single function to the main Eleventy configuration\nfunction. In this way, the complexity of the category's setup is abstracted\nfrom the main configuration and it makes for less clutter.\n\n\u003cdetails\u003e\n\u003csummary\u003eModular configuration example\u003c/summary\u003e\n\n\u003e **Example:** All of your layout templates are under `layouts`, and a single\n\u003e function in `layouts/_config.ts` is used by the main Eleventy configuration\n\u003e function to assign each of them an alias. They are loaded in the main\n\u003e [`.eleventy.ts`](eleventy.ts) entrypoint. Here is a (simplified) example:\n\n```ts\nexport = (cfg: UserConfig) =\u003e {\n  require(\"./11ty/layouts/_config\")(cfg);\n  // ...\n};\n```\n\n\u003e When you need to make modifications to your layout setup, you will be working\n\u003e strictly with the files contained in this directory. Similar mechanisms exist\n\u003e for each of the other categories, though their configuration functions'\n\u003e content may differ slightly.\n\n\u003c/details\u003e\n\n## 🎉 Features\n\n### 🖼️ Layouts\n\n\u003e 🔍 Source folder: [`11ty/layouts`](11ty/layouts/)\n\nAll layout templates are built using the [11ty.js][] (JavaScript) template\nlanguage.\n\n| Key          | Parent       | Description                                                                  |\n| ------------ | ------------ | ---------------------------------------------------------------------------- |\n| `base`       | _none_       | The base layout, which includes the outer document shell and site navigation |\n| `withHeader` | `base`       | Reads `data.header` for use in an `\u003ch1\u003e` element                             |\n| `page`       | `withHeader` | Used for Markdown pages; includes reading time, edit link, etc.              |\n| `post`       | `withHeader` | Like `page`, but includes posted timestamp                                   |\n\n### 🔖 Special tags\n\nSome tags may confer special behavior to the post they are attached to.\n\n| Key        | Description                                                                                                    |\n| ---------- | -------------------------------------------------------------------------------------------------------------- |\n| `archived` | Removes the post from tag lists and displays a notice explaining to the viewer that the page has been archived |\n\n### 🗒 Data\n\n\u003e 🔍 Source folder: [`11ty/data`](11ty/data/)\n\n#### css\n\n\u003e 🔍 Source: [`11ty/data/css.ts`](11ty/data/css.ts)\n\nCSS combine/minify configuration\n\n| Field                 | Description                                                             |\n| --------------------- | ----------------------------------------------------------------------- |\n| `externalStylesheets` | List of external stylesheet files to pull during build                  |\n| `fontDestination`     | Destination folder (relative to output folder) for font resources       |\n| `fontSources`         | List of folders that should be copied to `fontDestination` during build |\n| `localStylesheets`    | List of CSS files from the local filesystem to incoroporate             |\n\n#### ignoreTags\n\n\u003e 🔍 Source: [`11ty/data/ignoreTags.ts`](11ty/data/ignoreTags.ts)\n\nList of post tags that should be ignored when building tag pages or displaying\na post's associated tags\n\n#### links\n\n\u003e 🔍 Source: [`11ty/data/links.ts`](11ty/data/links.ts)\n\nList of objects for use in the **Site** navigation menu. Their format is as\nfollows:\n\n| Field  | Description                                 |\n| ------ | ------------------------------------------- |\n| `name` | Name to display in the menu                 |\n| `url`  | URL for the generated link tag              |\n| `icon` | CSS classes for the link's FontAwesome icon |\n\n#### metaDefaults\n\n\u003e 🔍 Source: [`11ty/data/metaDefaults.ts`](11ty/data/metaDefaults.ts)\n\nDefault values for page metadata\n\n| Field               | Description                             |\n| ------------------- | --------------------------------------- |\n| `author`            | Author of the post/page                 |\n| `description`       | Meta description                        |\n| `generator`         | Eleventy package name and version       |\n| `openGraphImageUrl` | URL to use for `og:image` OpenGraph tag |\n| `openGraphType`     | Type of page for `og:type` tag          |\n\n#### misc\n\n\u003e 🔍 Source: [`11ty/data/misc.ts`](11ty/data/misc.ts)\n\nMiscellaneous values that don't belong elsewhere\n\n| Field              | Description                                          |\n| ------------------ | ---------------------------------------------------- |\n| `blurbLength`      | Maximum length allowed for post blurbs               |\n| `githubRoot`       | GitHub project root for \"Suggest an edit\" post links |\n| `jumboBlurbLength` | Maximum length allowed for primary post's blurb      |\n| `readingTimeWpm`   | Words-per-minute for calculating reading time        |\n| `siteRoot`         | Root URL of the site                                 |\n| `ytPlaylistId`     | YouTube playlist ID for retrieving latest video      |\n\n#### socials\n\n\u003e 🔍 Source: [`11ty/data/socials.ts`](11ty/data/links.ts)\n\nList of links for populating the **Social** navigation menu. Object format is\nthe same as that of [links](#links).\n\n#### strings\n\n\u003e 🔍 Source: [`11ty/data/strings.ts`](11ty/data/strings.ts)\n\nList of string values used throughout the site and its templates\n\n| Field              | Description                                |\n| ------------------ | ------------------------------------------ |\n| `aboutMe`          | HTML for the \"About me\" section            |\n| `header`           | Text for site header                       |\n| `siteMenuHeader`   | Text for **Site** navigation menu header   |\n| `siteName`         | Text for site name (used in `\u003ctitle\u003e`)     |\n| `socialMenuHeader` | Text for **Social** navigation menu header |\n\n### ⚡ Functions\n\n\u003e 🔍 Source folder: [`11ty/functions`](11ty/functions/)\n\nThese are equivalent to _filters_ in other templating languages (e.g. nunjucks).\n\n| Function                                     | Description                                                                            |\n| -------------------------------------------- | -------------------------------------------------------------------------------------- |\n| `getDescription(content, limit)`             | Produce a trimmed blurb for the given content                                          |\n| `getHashRef()`                               | Get the hash ref of the latest commit in the repository                                |\n| `getMetaDescription(content, limit)`         | Same as getDescription, but encoded for \u0026lt;meta /\u0026gt; usage                           |\n| `htmlEntities(text)`                         | Replace certain character combinations with HTML entity equivalents                    |\n| `inlineScript(...paths)`                     | Return an auto-executing anonymous method for the given Javascript file for inline use |\n| `metaEncode(text)`                           | Replace illegal characters to produce usable text for meta tags                        |\n| `renderArchivedNotice(tags)`                 | Used by the `post` layout to display an archived notice (if applicable)                |\n| `renderCollection(items, limit, jumboFirst)` | Render a collection of pages                                                           |\n| `renderGitHubLink(data)`                     | Render link to GitHub for editing the current page                                     |\n| `renderIcon(icon)`                           | Render the provided [Feather Icons][] sprite                                           |\n| `renderLazyImage(html)`                      | Render a lazy loaded image of the provided \u0026lt;img\u0026gt; element                         |\n| `renderReadingTime(data)`                    | Render the reading time information for a page/post                                    |\n| `renderTags(tags)`                           | Render a collection of tags                                                            |\n\n### ⏰ Event handlers\n\n\u003e 🔍 Source folder: [`11ty/events`](11ty/events/)\n\n| Handler     | Event            | Description                                                                                 |\n| ----------- | ---------------- | ------------------------------------------------------------------------------------------- |\n| `cssTidy`   | `eleventy.after` | Purges unused rules with [purgecss][], minifies and combines stylesheets with [clean-css][] |\n| `iconPurge` | `eleventy.after` | Removes unused SVG icons from `feather-icons.svg` sprite sheet                              |\n\n### 🤖 Transforms\n\n\u003e 🔍 Source folder: [`11ty/transforms`](11ty/transforms/)\n\n| Name         | Description                                                  |\n| ------------ | ------------------------------------------------------------ |\n| `htmlMinify` | Minifies HTML output using [html-minifier][] and [esbuild][] |\n\n### 📚 Libraries\n\n\u003e 🔍 Source folder: [`11ty/libraries`](11ty/libraries/)\n\n| ID              | Description                                          |\n| --------------- | ---------------------------------------------------- |\n| [markdown-it][] | Used for generating HTML content from Markdown files |\n\n### 🔌 Plugins\n\n\u003e 🔍 Source folder: [`11ty/plugins`](11ty/plugins/)\n\n| ID                                        | Description                                       |\n| ----------------------------------------- | ------------------------------------------------- |\n| [@11ty/eleventy-plugin-syntaxhighlight][] | Syntax highlighting for code blocks in blog posts |\n\n## 🌐 Environment variables\n\nThere are several environment variables required for the site to operate. These\nmay be exposed as GitHub environment secrets, standard environment variables,\nor by creating a `.env` file in the root of the project.\n\n| Name                   | Description              |\n| ---------------------- | ------------------------ |\n| `TWITCH_USERNAME`      | Your Twitch username     |\n| `TWITCH_CLIENT_ID`     | Twitch API client ID     |\n| `TWITCH_CLIENT_SECRET` | Twitch API client secret |\n| `YT_API_KEY`           | YouTube Data API key     |\n\n## ⏯️ Tasks\n\n\u003e 🔍 Source folder: [`tasks`](tasks/)\n\nThere are tasks which are run directly with `node`, outside of the scope of the\nthe Eleventy system. These will each output a JSON file in the\n`11ty/data/external` directory corresponding to the external data source they\nrepresent.\n\nThe scripts compare their external data against the file's previous contents\n(if any). If the file is identical to the external data, they will end with\nan exit code of `0`. If there are differences, they will end with an exit code\nof `1`. This is used to chain them together with an early exit in the GitHub\nworkflow responsible for polling external data sources so that a publish action\ndoes not take place if there is nothing to update.\n\n\u003e **Note:** Because they will end with an exit code of `1` when there are\n\u003e differences, this must be accounted for when running them individually in a\n\u003e workflow. See examples below.\n\n\u003cdetails\u003e\n\u003csummary\u003eTask execution examples\u003c/summary\u003e\n\n```shell\n# this could fail and end your workflow early\nnpm run check:twitch\n```\n\n```shell\n# this will always proceed to the next step\nnpm run check:twitch || true\n```\n\n```shell\n# this will set the shell variable DIFF to 1 if there are differences while\n# also proceeding to the next step\nnpm run check:twitch || DIFF=1\n```\n\n```shell\n# this will run *all* checks; return code behavior is the same\nnpm run check\n```\n\n\u003c/details\u003e\n\n| Task            | Description                                      |\n| --------------- | ------------------------------------------------ |\n| `check`         | Runs all `check:*` tasks                         |\n| `check:twitch`  | Retrieves Twitch live stream and VOD information |\n| `check:youtube` | Retrieves YouTube latest video information       |\n\n## 🏭 Workflows\n\n\u003e 🔍 Source folder: [`.github/workflows`](.github/workflows/)\n\nThis site is hosted entirely on [GitHub Pages][]. Both its main publishing and\nperiodic update methods make use of [GitHub Actions][] workflows to update the\nlive site automatically when new content or data is available.\n\n### Automatic publish on merge\n\n\u003e 🔍 Source: [`.github/workflows/publish-site.yml`](.github/workflows/publish-site.yml)\n\nWhen the `main` branch of this repository is updated, a GitHub workflow\nregenerates the site and delivers the artifact to a GitHub Pages publishing action,\nwhich will update the live site with any new content. External data is also\nrefreshed as part of this process.\n\n### Periodic updates\n\n\u003e 🔍 Source: [`.github/workflows/check-externals.yml`](.github/workflows/check-externals.yml)\n\nThis site is periodically updated by way of a [hosted cronjob][] and a GitHub\nworkflow. Every 5 minutes, the cronjob runs the workflow responsible for\npolling external data sources by using a [workflow dispatch event][]. If any of\nthe external sources have updated data since the last execution of the\nworkflow, the site will be re-published (along with the new data).\n\n[🎈 eleventy]: https://11ty.dev\n[11ty.js]: https://www.11ty.dev/docs/languages/javascript/\n[@11ty/eleventy-plugin-syntaxhighlight]: https://www.npmjs.com/package/@11ty/eleventy-plugin-syntaxhighlight\n[clean-css]: https://www.npmjs.com/package/clean-css\n[feather icons]: https://feathericons.com\n[github actions]: https://github.com/features/actions\n[github pages]: https://pages.github.com\n[esbuild]: https://www.npmjs.com/package/esbuild\n[hosted cronjob]: https://cron-job.org\n[html-minifier]: https://www.npmjs.com/package/html-minifier\n[markdown-it]: https://www.npmjs.com/package/markdown-it\n[purgecss]: https://www.npmjs.com/package/purgecss\n[workflow dispatch event]: https://docs.github.com/en/rest/actions/workflows#create-a-workflow-dispatch-event\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaliphax%2Fhaliphax-dot-dev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaliphax%2Fhaliphax-dot-dev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaliphax%2Fhaliphax-dot-dev/lists"}