├── .eleventy.js
├── .github
└── workflows
│ ├── pr_check.yml
│ └── release.yml
├── .gitignore
├── .nvmrc
├── .prettierrc
├── .releaserc
├── CHANGELOG.md
├── README.md
├── _includes
├── default.njk
└── page.njk
├── assets
├── favicon.ico
├── grid_desktop_1630347066416_0.png
├── grid_mobile_1630347074383_0.png
└── ogimage.png
├── babel.config.js
├── data.json
├── index.11ty.js
├── jest.config.js
├── journals
├── 2015-04-30.md
├── 2018-06-26.md
├── 2019-10-07.md
├── 2020-08-24.md
├── 2020-10-23.md
├── 2020-12-17.md
├── 2021-03-04.md
├── 2021-06-08.md
├── 2021-06-09.md
├── 2021-06-10.md
├── 2021-06-11.md
├── 2021-06-14.md
├── 2021-06-15.md
├── 2021-06-16.md
├── 2021-06-18.md
├── 2021-06-21.md
├── 2021-06-22.md
├── 2021-06-30.md
├── 2021-07-12.md
├── 2021-07-16.md
├── 2021-07-18.md
├── 2021-08-03.md
├── 2021-08-30.md
├── 2021-09-22.md
├── 2021-10-01.md
├── 2021-11-10.md
├── 2021-11-15.md
├── 2021-11-16.md
└── 2021-11-17.md
├── package-lock.json
├── package.json
├── pages
├── abortcontroller-can-be-used-to-cancel-multiple-request.md
├── accessibility.md
├── adding-types-to-a-react-component-in-typescript.md
├── always-use-real-variable-names-in-examples.md
├── api.md
├── braden-becker.md
├── brittany-storoz.md
├── contents.md
├── css-grid-tricks.md
├── css.md
├── derek-prior.md
├── describe-what-youre-doing-before-doing-it.md
├── development.md
├── difference-between-nullish-coalescing-and-logical-or.md
├── dont-use-shorthands-in-css.md
├── errors.md
├── eslint.md
├── etymology.md
├── explain-in-plain-words.md
├── falsy-in-javascript.md
├── firefox.md
├── frontend-testing-workshop.md
├── frontend.md
├── git.md
├── good-documentation-is-written-by-and-for-humans.md
├── grace-hopper.md
├── handling-tech-debt-is-like-doing-the-dishes.md
├── harvard-university.md
├── hemnet.md
├── how-to-save-and-quit-vim.md
├── ide.md
├── implementing-a-strong-code-review-culture.md
├── index-signature.md
├── internet-explorer.md
├── jason-etcovich.md
├── javascript.md
├── jest.md
├── johnny-ji.md
├── kernel.md
├── learn-by-doing-side-projects.md
├── learning-in-public.md
├── learning.md
├── max-rozen.md
├── mdn.md
├── meta-viewport-for-mobile-devices.md
├── mob-programming.md
├── neovim.md
├── nerdtree.md
├── nielsen-norman-group.md
├── people-cost-more-than-their-tools.md
├── pr.md
├── prettier.md
├── react-podcast.md
├── react-query.md
├── react.md
├── recommended-way-of-importing-react.md
├── record-utility.md
├── rewriting-git-commit-history.md
├── richard-feynman.md
├── rubber-ducking.md
├── rubocop.md
├── ryan-florence.md
├── save-disk-space-by-deleting-node_modules.md
├── seo.md
├── sha.md
├── share-shortcuts-and-plugins-when-teaching-new-developers.md
├── shu-omi.md
├── socratic-method.md
├── ssr.md
├── structure-of-css.md
├── tdd.md
├── teaching.md
├── technical-debt.md
├── testing-library.md
├── testing.md
├── the-big-hack.md
├── the-etymology-of-programming.md
├── thomas-boutell.md
├── til.md
├── twitter.md
├── typescript.md
├── use-the-objects-identifier-type.md
├── use-valueasnumber-and-valueasdate-on-inputs.md
├── vim.md
├── whats-new-in-react-18.md
├── write-great-alt-texts-for-images.md
└── write-useful-error-messages.md
├── postcss.config.js
├── src
├── __tests__
│ ├── __snapshots__
│ │ └── generate.test.ts.snap
│ ├── elements.test.ts
│ ├── frontmatter.test.ts
│ ├── generate.test.ts
│ └── utils.test.ts
├── elementBuilder.ts
├── elements.ts
├── frontmatter.ts
├── generate.ts
├── references.ts
├── types.ts
└── utils.ts
├── styles
├── coldark.css
└── style.css
├── tailwind.config.js
└── tsconfig.json
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight')
2 | const pluginSEO = require('eleventy-plugin-seo')
3 |
4 | module.exports = function (config) {
5 | config.addPlugin(syntaxHighlight)
6 | config.addPassthroughCopy('assets')
7 | config.addPassthroughCopy({
8 | './_tmp/style.css': './style.css',
9 | })
10 | config.addPassthroughCopy({
11 | './styles/coldark.css': './coldark.css',
12 | })
13 |
14 | config.addPlugin(pluginSEO, {
15 | title: 'Devlog',
16 | description:
17 | 'Ideas, thoughts, reminders and things I find interesting in software development',
18 | url: 'https://devlog.willcodefor.beer',
19 | author: 'Rickard Natt och Dag',
20 | twitter: 'rnattochdag',
21 | image: '/assets/ogimage.png',
22 | options: {
23 | imageWithBaseUrl: true,
24 | },
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/pr_check.yml:
--------------------------------------------------------------------------------
1 | name: Run tests on PR
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | test:
10 | name: Run tests
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v2
15 |
16 | - name: Setup Node
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: '14'
20 |
21 | - name: Run tests and linting
22 | run: |
23 | npm ci
24 | npm test
25 | env:
26 | CI: true
27 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v2
16 |
17 | - name: Setup Node
18 | uses: actions/setup-node@v1
19 | with:
20 | node-version: '14'
21 |
22 | - name: Run tests and linting
23 | run: |
24 | npm install
25 | npm test
26 | env:
27 | CI: true
28 |
29 | - name: Create release using semantic-release
30 | uses: cycjimmy/semantic-release-action@v2
31 | id: semantic
32 | with:
33 | semantic_version: 17.1.1
34 | extra_plugins: |
35 | @semantic-release/changelog@5.0.1
36 | @semantic-release/git@9.0
37 | env:
38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39 |
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules
3 |
4 | # Logs
5 | *.log
6 |
7 | # env
8 | .env
9 |
10 | # IDE
11 | .vscode
12 |
13 | # Mac
14 | .DS_Store
15 |
16 | _site
17 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v14.15.0
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "es5",
8 | "bracketSpacing": true,
9 | "jsxBracketSameLine": false
10 | }
11 |
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "branches": ["main"],
3 | "plugins": [
4 | "@semantic-release/commit-analyzer",
5 | "@semantic-release/release-notes-generator",
6 | "@semantic-release/changelog",
7 | ["@semantic-release/npm", {
8 | "npmPublish": false
9 | }],
10 | "@semantic-release/git"
11 | ]
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # devlog
2 |
3 | **NOTE:** This is no longer maintained. I've moved content to my personal site https://willcodefor.beer/ and the code https://github.com/believer/willcodefor.
4 |
5 | This is my attempt at learning in public and the site is available at https://devlog.willcodefor.beer. I'm using [Logseq](https://github.com/logseq/logseq) to do my writing and generate pages using [eleventy](https://github.com/11ty/eleventy/).
6 |
7 | ## Get started
8 |
9 | - Fork the repo
10 | - `npm install`
11 | - Export your graph as JSON from Logseq. Save the file as `data.json` in the
12 | root of the project
13 | - Run `npm start` to generate the files into the folders `/pages` and `/journals`
14 | - Run `npm run css:prod` to compile the CSS
15 | - Run `npm run serve` to start eleventy
16 | - Go to http://localhost:8080
17 |
18 | The project is also ready to deploy on [Vercel](https://vercel.com/believer)
19 |
--------------------------------------------------------------------------------
/_includes/default.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% seo "" %}
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 | Devlog
33 |
34 |
35 |
36 |
37 |
38 | You've found my devlog!
41 | Here I'm trying to collect ideas and thoughts, new findings, and
42 | reminders regarding software development. I see it as a
43 | second brain
55 | for all things related to development. It's also also a way for me
56 | to practice
57 |
69 | [[ Learning in public]] .
75 |
76 |
77 | The content is created in
78 | Logseq , exported to JSON and then generated as static HTML.
90 |
91 |
92 | I'm currently on paternal leave for the rest of 2021. Updates might
93 | not happen that often.
94 |
95 |
96 | {% block content %}
97 | {{ content | safe }}
98 | {% endblock %}
99 |
100 |
101 |
102 | Built by
103 | @rnattochdag . Code at
118 | GitHub .
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/_includes/page.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% seo "" %}
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 | Devlog
33 |
34 |
35 |
36 | {% block content %}
37 | {{ content | safe }}
38 | {% endblock %}
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/believer/devlog/627ddf86091073be067dda81b4f5dc652c84400b/assets/favicon.ico
--------------------------------------------------------------------------------
/assets/grid_desktop_1630347066416_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/believer/devlog/627ddf86091073be067dda81b4f5dc652c84400b/assets/grid_desktop_1630347066416_0.png
--------------------------------------------------------------------------------
/assets/grid_mobile_1630347074383_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/believer/devlog/627ddf86091073be067dda81b4f5dc652c84400b/assets/grid_mobile_1630347074383_0.png
--------------------------------------------------------------------------------
/assets/ogimage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/believer/devlog/627ddf86091073be067dda81b4f5dc652c84400b/assets/ogimage.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ['@babel/preset-env', {targets: {node: 'current'}}],
4 | '@babel/preset-typescript',
5 | ],
6 | };
7 |
--------------------------------------------------------------------------------
/index.11ty.js:
--------------------------------------------------------------------------------
1 | class Index {
2 | data() {
3 | return {
4 | layout: 'default',
5 | }
6 | }
7 |
8 | render(data) {
9 | return `
10 | ${data.collections.journal
11 | .slice()
12 | .reverse()
13 | .map((journal) => {
14 | return `
15 | ${journal.templateContent} `
16 | })
17 | .join('\n')}
18 | `
19 | }
20 | }
21 |
22 | module.exports = Index
23 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'node',
3 | watchPlugins: [
4 | 'jest-watch-typeahead/filename',
5 | 'jest-watch-typeahead/testname',
6 | ],
7 | }
8 |
--------------------------------------------------------------------------------
/journals/2015-04-30.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2015-04-30'
4 | title: |
5 | 2015-04-30
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2018-06-26.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2018-06-26'
4 | title: |
5 | 2018-06-26
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2019-10-07.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2019-10-07'
4 | title: |
5 | 2019-10-07
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2020-08-24.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2020-08-24'
4 | title: |
5 | 2020-08-24
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/journals/2020-10-23.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2020-10-23'
4 | title: |
5 | 2020-10-23
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2020-12-17.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2020-12-17'
4 | title: |
5 | 2020-12-17
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2021-03-04.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-03-04'
4 | title: |
5 | 2021-03-04
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2021-06-08.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-08'
4 | title: |
5 | 2021-06-08
6 | tags: 'journal'
7 | excerpt: |
8 | Write out all the test cases – that you can think of – as TODOs before you start writing the code. Jest will display these tests as a separate metric in the interactive runner and in the test summary. It's as simple as using test.todo('description')
9 | ---
10 |
11 |
12 |
13 |
14 |
Write out all the test cases – that you can think of – as TODOs before you start writing the code.
[[ Jest]] will display these tests as a separate metric in the interactive runner and in the test summary. It's as simple as using
test.todo('description')
#Testing
15 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/journals/2021-06-09.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-09'
4 | title: |
5 | 2021-06-09
6 | tags: 'journal'
7 | excerpt: |
8 | Rewriting Git commit history
9 | ---
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ```ts
23 | type Server = 'dev' | 'stage' | 'production'
24 |
25 | // Index signature
26 | const serversIndex: { [key in Server]: string } = {
27 | dev: 'url-dev',
28 | stage: 'url-stage',
29 | production: 'url-production'
30 | } as const
31 |
32 | // Using the Record utility
33 | const serversRecord: Record = {
34 | dev: 'url-dev',
35 | stage: 'url-stage',
36 | production: 'url-production'
37 | } as const
38 | ```
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/journals/2021-06-10.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-10'
4 | title: |
5 | 2021-06-10
6 | tags: 'journal'
7 | excerpt: |
8 | I'll keep this here for future reference when I eventually forget what the meta tag should be and have to look it up again Meta viewport for mobile devices
9 | ---
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ```
21 | # Make the viewport scale correctly on mobile devices
22 | snippet metav "Meta viewport"
23 |
24 | endsnippet
25 | ```
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
--------------------------------------------------------------------------------
/journals/2021-06-11.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-11'
4 | title: |
5 | 2021-06-11
6 | tags: 'journal'
7 | excerpt: |
8 | A coworker asked for tips on how to get more advanced React knowledge. This got me thinking about how I do learning.
9 | ---
10 |
11 |
12 |
13 |
14 |
A coworker asked for tips on how to get more advanced
[[ React]] knowledge. This got me thinking about how I do learning.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/journals/2021-06-14.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-14'
4 | title: |
5 | 2021-06-14
6 | tags: 'journal'
7 | excerpt: |
8 | The act utility in React makes your tests run closer to how React works in the browser. If you're using Testing Library you won't need it that often since the library already wraps the code in act when necessary.
9 | ---
10 |
11 |
12 |
13 |
14 |
The
act
utility in
[[ React]] makes your tests run closer to how React works in the browser. If you're using
[[ Testing Library]] you won't need it that often since the library already wraps the code in
act
when necessary.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/journals/2021-06-15.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-15'
4 | title: |
5 | 2021-06-15
6 | tags: 'journal'
7 | excerpt: |
8 | Here's an example of a bug I found recently. It was a list of users that occasionally displayed the wrong name with the wrong image. The data was stored as a JSON file and was using a .sort() operation before looping over each item. .sort() is a mutating method and by adding a .slice() before sorting we can create a shallow copy of the array to not alter the original data.
9 | ---
10 |
11 |
12 |
13 |
14 |
Here's an example of a bug I found recently. It was a list of users that occasionally displayed the wrong name with the wrong image. The data was stored as a JSON file and was using a .sort()
operation before looping over each item. .sort()
is a mutating method and by adding a .slice()
before sorting we can create a shallow copy of the array to not alter the original data.
15 |
16 |
17 |
18 |
19 |
20 | ```js
21 | // React app
22 |
23 | const data = [{ name: 'Test Testsson' }, { name: 'Aaron Aaronson' }];
24 |
25 | // Incorrect
26 | // The sorting operation that was used didn't really work as expected
27 | // and since the sort method is mutating the original data
28 | // we got some unexpected results
29 | data.sort((a, b) => a.name > b.name).map((user) =>
{user.name}
);
30 |
31 | // Correct
32 | // Use the slice method to create a copy of the array
33 | // to not mutate the original data.
34 | // Update the sorting operation to use localeCompare for better results
35 | data
36 | .slice()
37 | .sort((a, b) => a.name.localeCompare(b.name))
38 | .map((user) =>
{user.name}
);
39 | ```
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/journals/2021-06-16.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-16'
4 | title: |
5 | 2021-06-16
6 | tags: 'journal'
7 | excerpt: |
8 | Today I held a workshop in testing for my team at Hemnet. All the descriptions, code, and explanations are available on the page Frontend testing workshop
9 | ---
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Make many small commits instead of a few large ones. This will make the PR read more as a story of what happened which is a good compliment to a good description.
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/journals/2021-06-18.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-18'
4 | title: |
5 | 2021-06-18
6 | tags: 'journal'
7 | excerpt: |
8 | I haven't thought about using my sidebar/file explorer to the right in Neovim (or in any other IDE I've ever used for that matter). After reading through the answers in this Twitter question I found it interesting that with the sidebar to the right, the code won't shift when toggling it. I think a lot of people keep the file explorer open while developing and don't experience this, but I always close it when I don't use it. I'm going to try using the sidebar to the right for a while and see if it sticks.
9 | ---
10 |
11 |
12 |
13 |
14 |
I haven't thought about using my sidebar/file explorer to the right in
[[ Neovim]] (or in any other
[[ IDE]] I've ever used for that matter). After reading through the answers in this
Twitter question I found it interesting that with the sidebar to the right, the code won't shift when toggling it. I think a lot of people keep the file explorer open while developing and don't experience this, but I always close it when I don't use it. I'm going to try using the sidebar to the right for a while and see if it sticks.
15 |
16 |
I'm using
[[ NERDTree]] as my file explorer and the setting to display the sidebar to the right is
17 |
18 |
19 |
20 | ```vim
21 | let g:NERDTreeWinPos = "right"
22 | ```
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/journals/2021-06-21.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-21'
4 | title: |
5 | 2021-06-21
6 | tags: 'journal'
7 | excerpt: |
8 | I hadn't kept up with what the latest was in the newly announced React 18 but decided that it was the perfect thing to start this Monday off with. What's new in React 18
9 | ---
10 |
11 |
12 |
13 |
14 |
I hadn't kept up with what the latest was in the newly announced
[[ React]] 18 but decided that it was the perfect thing to start this Monday off with.
[[ What's new in React 18]]
15 |
16 |
If you use a correct
[[ Meta viewport for mobile devices]] you'll never see the 300-350 ms tap delay that browsers add to wait for a double tap. If you for some reason can't add the meta tag, there's also a
[[ CSS]] property that does the same thing. It's not supported by
[[ Firefox]] , so the meta tag is preferred.
17 |
18 |
Neither of the solutions affect the
[[ Accessibility]] on the page since pinch-to-zoom will still work.
19 |
20 |
21 |
22 | ```css
23 | /* Set the property on the entire page or on specific
24 | elements like a or button */
25 | html {
26 | touch-action: manipulation;
27 | }
28 | ```
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
--------------------------------------------------------------------------------
/journals/2021-06-22.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-22'
4 | title: |
5 | 2021-06-22
6 | tags: 'journal'
7 | excerpt: |
8 | The Etymology of Programming
9 | ---
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Tech is full of jargon which can be hard for everyone to understand. Some languages might not even have a name for a certain topic. Here are a few ways that can help make things easier to understand
17 |
18 |
Use cartoons or illustrations instead of writing text
19 |
20 |
21 |
22 |
Work with native speakers of other languages to create better documentation
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
I keep forgetting the official names for each part of the structure of CSS. Hopefully writing it down will help future me in remembering it -
[[ Structure of CSS]] .
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/journals/2021-06-30.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-06-30'
4 | title: |
5 | 2021-06-30
6 | tags: 'journal'
7 | excerpt: |
8 | Handling tech debt is like doing the dishes
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-07-12.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-07-12'
4 | title: |
5 | 2021-07-12
6 | tags: 'journal'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/journals/2021-07-16.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-07-16'
4 | title: |
5 | 2021-07-16
6 | tags: 'journal'
7 | excerpt: |
8 | Transfer Good documentation is written by and for humans by Jason Etcovich
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-07-18.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-07-18'
4 | title: |
5 | 2021-07-18
6 | tags: 'journal'
7 | excerpt: |
8 | Good documentation is written by and for humans
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-08-03.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-08-03'
4 | title: |
5 | 2021-08-03
6 | tags: 'journal'
7 | excerpt: |
8 | Write great alt texts for images
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-08-30.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-08-30'
4 | title: |
5 | 2021-08-30
6 | tags: 'journal'
7 | excerpt: |
8 | Describe what you're doing before doing it
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-09-22.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-09-22'
4 | title: |
5 | 2021-09-22
6 | tags: 'journal'
7 | excerpt: |
8 | Difference between nullish coalescing (??) and logical or (||)
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-10-01.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-10-01'
4 | title: |
5 | 2021-10-01
6 | tags: 'journal'
7 | excerpt: |
8 | Share shortcuts and plugins when teaching new developers
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-11-10.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-11-10'
4 | title: |
5 | 2021-11-10
6 | tags: 'journal'
7 | excerpt: |
8 | Use valueAsNumber and valueAsDate on inputs
9 | ---
10 |
11 |
12 |
13 |
18 |
19 |
20 |
24 |
--------------------------------------------------------------------------------
/journals/2021-11-15.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-11-15'
4 | title: |
5 | 2021-11-15
6 | tags: 'journal'
7 | excerpt: |
8 | Recommended way of importing React
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-11-16.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-11-16'
4 | title: |
5 | 2021-11-16
6 | tags: 'journal'
7 | excerpt: |
8 | People cost more than their tools
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/journals/2021-11-17.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: '2021-11-17'
4 | title: |
5 | 2021-11-17
6 | tags: 'journal'
7 | excerpt: |
8 | Use the object's identifier type
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devlog-publish",
3 | "version": "1.24.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "css": "NODE_ENV=development postcss styles/style.css -o _site/style.css -w",
8 | "css:prod": "NODE_ENV=production postcss styles/style.css -o _site/style.css",
9 | "dev": "tsc -w --noEmit",
10 | "serve": "eleventy --serve",
11 | "start": "ts-node ./src/generate.ts",
12 | "test": "is-ci-cli test:ci test:watch",
13 | "test:ci": "jest",
14 | "test:watch": "jest --watch",
15 | "build": "NODE_ENV=production eleventy && npm run css:prod"
16 | },
17 | "author": "Rickard Natt och Dag",
18 | "license": "ISC",
19 | "devDependencies": {
20 | "@11ty/eleventy": "0.12.1",
21 | "@11ty/eleventy-plugin-syntaxhighlight": "3.1.1",
22 | "@babel/preset-env": "7.14.5",
23 | "@babel/preset-typescript": "7.14.5",
24 | "@types/jest": "26.0.23",
25 | "@types/node": "15.12.2",
26 | "autoprefixer": "10.2.6",
27 | "eleventy-plugin-seo": "0.5.1",
28 | "is-ci-cli": "2.2.0",
29 | "jest": "27.0.4",
30 | "jest-watch-typeahead": "0.6.4",
31 | "postcss": "8.3.2",
32 | "postcss-cli": "8.3.1",
33 | "prettier": "2.3.1",
34 | "tailwindcss": "2.1.4",
35 | "ts-node": "10.0.0",
36 | "typescript": "4.3.2"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/pages/abortcontroller-can-be-used-to-cancel-multiple-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'abortcontroller-can-be-used-to-cancel-multiple-request'
4 | title: |
5 | AbortController can be used to cancel multiple request
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development, React
9 |
10 | pid: 210622110339
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Let's say the user clicks a link while we are still loading some data. Then we can use AbortController
, a controller object that allows us to abort one or more web requests , to tell the browser to cancel and ignore the request.
21 |
22 |
23 |
24 | ```js
25 | const { signal } = new AbortController();
26 |
27 | // Pass the same signal to multiple promises
28 | fetch('url-one', { signal });
29 | fetch('url-two', { signal });
30 |
31 | // Cancel all requests
32 | controller.abort();
33 | ```
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
--------------------------------------------------------------------------------
/pages/accessibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'accessibility'
4 | title: |
5 | Accessibility
6 | tags: 'page'
7 | excerpt: |
8 | Commonly abbreviated as a11y (a numeronym) which means "a - 11 letters - y" as in "a - ccessibilit - y"
9 | ---
10 |
11 |
12 |
13 |
14 |
Commonly abbreviated as a11y (a numeronym) which means "a - 11 letters - y" as in "a - ccessibilit - y"
15 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/pages/always-use-real-variable-names-in-examples.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'always-use-real-variable-names-in-examples'
4 | title: |
5 | Always use real variable names in examples
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development
9 |
10 | pid: 210426074810
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Just like you wouldn't use foo
, bar
, and baz
in the real code you are writing, you should not use them when writing example code either.
21 |
22 |
Instead use real variable names that describe what it contains and create examples based on reality. This will make your examples easier to grasp and build upon.
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
35 |
--------------------------------------------------------------------------------
/pages/api.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'api'
4 | title: |
5 | API
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/braden-becker.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'braden-becker'
4 | title: |
5 | Braden Becker
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/brittany-storoz.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'brittany-storoz'
4 | title: |
5 | Brittany Storoz
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/contents.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'contents'
4 | title: |
5 | Contents
6 | tags: 'page'
7 | excerpt: |
8 | Here I'm trying to collect ideas and thoughts, new findings, and reminders regarding software development. I see it as a second brain for all things related to development. It's also also a way for me to practice Learning in public
9 | ---
10 |
11 |
12 |
13 |
14 |
Here I'm trying to collect ideas and thoughts, new findings, and reminders regarding software development. I see it as a
second brain for all things related to development. It's also also a way for me to practice
[[ Learning in public]]
15 |
16 |
17 |
18 |
I'm currently on paternal leave for the rest of 2021. Updates won't happen often.
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/pages/css-grid-tricks.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'css-grid-tricks'
4 | title: |
5 | CSS Grid tricks
6 | tags: 'page'
7 | excerpt: |
8 | Add columns for spacing on mobile
9 | ---
10 |
11 |
12 |
13 |
14 |
Add columns for spacing on mobile
15 |
16 |
We have some content that we want to position in the center of the screen. For this we can use
[[ CSS Grid]] . By defining fixed values at the edges of our grid template we can achieve spacing without using
padding
when the grid resizes on a smaller screen.
17 |
18 |
19 |
20 |
21 |
22 | ```html
23 |
24 |
25 | Elit suscipit consequuntur rerum alias eius. Autem soluta voluptas
26 | doloremque corrupti distinctio dicta Cumque sit accusamus minima magni
27 | voluptatum. Distinctio veritatis consectetur et eligendi dolores est
28 | Impedit at tenetur pariatur
29 |
30 |
31 |
32 | ```
33 |
34 |
35 |
36 |
37 |
38 | ```css
39 | .grid {
40 | display: grid;
41 | grid-template-columns: 20px 1fr minmax(0, 960px) 1fr 20px;
42 | }
43 |
44 | /* From the image below we can see that our content's
45 | area starts at column 3 and ends at column 4 */
46 | .content {
47 | grid-column: 3 / 4;
48 | /* This is a shorthand form of:
49 | * grid-column-start: 3;
50 | * grid-column-end: 4;
51 | */
52 | }
53 | ```
54 |
55 |
56 |
57 |
Here's the grid in desktop size with the grid columns highlighted using
[[ Chrome]] 's
grid
tool.
58 |
59 |
60 |
61 |
The same grid on a screen size of 411px
(Pixel 2 XL) displays that our 1fr
columns are very small (or non-existent) at this point leaving only our "padding" columns and the content.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
73 |
--------------------------------------------------------------------------------
/pages/css.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'css'
4 | title: |
5 | CSS
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/derek-prior.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'derek-prior'
4 | title: |
5 | Derek Prior
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/development.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'development'
4 | title: |
5 | Development
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/difference-between-nullish-coalescing-and-logical-or.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'difference-between-nullish-coalescing-and-logical-or'
4 | title: |
5 | Difference between nullish coalescing (??) and logical or (||)
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development, JavaScript
9 |
10 | pid: 210922101321
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
||
(logical OR) will use the right value when the left side is
[[ falsy]] .
??
(nullish coalescing) only uses the right value when the left side is
nullish , i.e.
null
or
undefined
.
21 |
22 |
23 |
24 | ```js
25 | // ||
26 | console.log('' || 'default') // 'default'
27 | console.log('test' || 'default') // 'test'
28 |
29 | console.log(0 || 'default') // 'default'
30 | console.log(12 || 'default') // 12
31 |
32 | console.log(false || 'default') // 'default'
33 | console.log(true || 'default') // true
34 |
35 | console.log(undefined || 'default') // 'default'
36 | console.log(null || 'default') // 'default'
37 |
38 | // ??
39 | console.log('' ?? 'default') // ''
40 | console.log('test' ?? 'default') // 'test'
41 |
42 | console.log(0 ?? 'default') // 0
43 | console.log(12 ?? 'default') // 12
44 |
45 | console.log(false ?? 'default') // false
46 | console.log(true ?? 'default') // true
47 |
48 | console.log(undefined ?? 'default') // 'default'
49 | console.log(null ?? 'default') // 'default'
50 | ```
51 |
52 |
53 |
54 |
55 |
56 |
60 |
--------------------------------------------------------------------------------
/pages/dont-use-shorthands-in-css.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'dont-use-shorthands-in-css'
4 | title: |
5 | Don't use shorthands in CSS
6 | tags: 'page'
7 | excerpt: |
8 | tags: CSS, Development
9 |
10 | pid: 210427103751
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
In
[[ CSS]] we have shorthands which makes it easier to write certain properties, for example
background
or
margin
. However, these affect more properties than what you're probably aiming for.
21 |
22 |
Instead use specific properties such as background-color
or margin-left
23 |
24 |
25 |
26 | ```css
27 | /*
28 | Here's an example where we want to change the background color to red.
29 | */
30 | .test {
31 | background: red;
32 | }
33 |
34 | /*
35 | By using background we implicitly set all other values to initial
36 | when we only wanted to change the background color
37 | */
38 | .test {
39 | background-image: initial;
40 | background-position-x: initial;
41 | background-position-y: initial;
42 | background-size: initial;
43 | background-repeat-x: initial;
44 | background-repeat-y: initial;
45 | background-attachment: initial;
46 | background-origin: initial;
47 | background-clip: initial;
48 | background-color: red;
49 | }
50 | ```
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
64 |
--------------------------------------------------------------------------------
/pages/errors.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'errors'
4 | title: |
5 | Errors
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/eslint.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'eslint'
4 | title: |
5 | ESLint
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/etymology.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'etymology'
4 | title: |
5 | Etymology
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/falsy-in-javascript.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'falsy-in-javascript'
4 | title: |
5 | Falsy in JavaScript
6 | tags: 'page'
7 | excerpt: |
8 | tags: JavaScript
9 |
10 |
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/pages/firefox.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'firefox'
4 | title: |
5 | Firefox
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/frontend.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'frontend'
4 | title: |
5 | Frontend
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/git.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'git'
4 | title: |
5 | Git
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/good-documentation-is-written-by-and-for-humans.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'good-documentation-is-written-by-and-for-humans'
4 | title: |
5 | Good documentation is written by and for humans
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development, Documentation
9 |
10 | pid: 210718220754
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Writing good documentation is hard. Remember that you are writing for humans. It might be the first time they are seeing code like the one you are describing.
21 |
22 |
Everyone has at least one example of good documentation. Write your documentation as that example, the way you would want to find it.
[[ Explain in plain words]] as everyone might not have the same level of knowledge as you do.
23 |
24 |
There are tools that help with generating documentation, but it does not help you write good documentation. Generate documentation when possible, but put in extra effort to make it good.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
--------------------------------------------------------------------------------
/pages/grace-hopper.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'grace-hopper'
4 | title: |
5 | Grace Hopper
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/handling-tech-debt-is-like-doing-the-dishes.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'handling-tech-debt-is-like-doing-the-dishes'
4 | title: |
5 | Handling tech debt is like doing the dishes
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development
9 |
10 | pid: 210630160342
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Whenever you procrastinate on doing the dishes – even if it's only a plate, a knife, and a fork – something happens. The dishes start to pile up since there's already something in the sink. If you have a dishwasher there might be a feeling that "the dishwasher must be full or running or clean and I don't want to be the one to handle it". You do this knowing full well that the problem will become more of a hassle with each item that gets added to the pile.
21 |
22 |
The same can be said for
[[ Technical debt]] . The longer we ignore or avoid the issues, the harder they'll be to clean up.
When you spot something, take a short amount of time and fix it . It'll be much easier to do now when you are in the context. Or at least make a note, preferably with context, and make sure it's fixed straight after the feature has been released.
23 |
24 |
25 |
26 |
30 |
--------------------------------------------------------------------------------
/pages/harvard-university.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'harvard-university'
4 | title: |
5 | Harvard University
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/hemnet.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'hemnet'
4 | title: |
5 | Hemnet
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/how-to-save-and-quit-vim.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'how-to-save-and-quit-vim'
4 | title: |
5 | How to save and quit Vim
6 | tags: 'page'
7 | excerpt: |
8 | There's a joke around the internet that it's impossible to quit Vim, but we'll see that it's actually not that hard. First of all, make sure that you're in normal mode. If you haven't changed any settings, you'll get to normal mode by pressing Esc. From here you can use any of the following commands:
9 | ---
10 |
11 |
12 |
13 |
14 |
There's a
joke around the internet that it's impossible to quit
[[ Vim]] , but we'll see that it's actually not that hard. First of all, make sure that you're in
normal mode . If you haven't changed any settings, you'll get to normal mode by pressing
Esc
. From here you can use any of the following commands:
15 |
16 |
:q
- quit (short for :quit
)
17 |
18 |
:q!
- quit without saving
19 |
20 |
21 |
22 |
:wq
- write (save) and quit
23 |
24 |
:wq!
- write and quit even if the file is in read only mode
25 |
26 |
:x
- write and quit (only writes if there are changes)
27 |
28 |
29 |
30 |
31 |
32 |
All together that would for instance be: Esc:q
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
--------------------------------------------------------------------------------
/pages/ide.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'ide'
4 | title: |
5 | IDE
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/index-signature.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'index-signature'
4 | title: |
5 | Index signature
6 | tags: 'page'
7 | excerpt: |
8 | Documentation
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/pages/internet-explorer.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'internet-explorer'
4 | title: |
5 | Internet Explorer
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/jason-etcovich.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'jason-etcovich'
4 | title: |
5 | Jason Etcovich
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/pages/javascript.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'javascript'
4 | title: |
5 | JavaScript
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/pages/jest.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'jest'
4 | title: |
5 | Jest
6 | tags: 'page'
7 | excerpt: |
8 | Jest is a JavaScript testing framework.
9 | ---
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
--------------------------------------------------------------------------------
/pages/johnny-ji.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'johnny-ji'
4 | title: |
5 | Johnny Ji
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/kernel.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'kernel'
4 | title: |
5 | Kernel
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/learn-by-doing-side-projects.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'learn-by-doing-side-projects'
4 | title: |
5 | Learn by doing side projects
6 | tags: 'page'
7 | excerpt: |
8 | tags: Learning
9 |
10 | pid: 210611104633
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
I think I can honestly say that building a bunch of side projects has made me a better developer. I get to actively work on different problems, try new things and improve my knowledge.
21 |
22 |
Have
one specific project , a project you know
exactly how you want it to work, to test out new ideas, technology and frameworks on. If it contains multiple parts, like interacting with an
[[ API]] or how to contain state, it's a perfect project to evaluate new technologies with.
23 |
24 |
25 |
26 |
27 |
28 |
32 |
--------------------------------------------------------------------------------
/pages/learning-in-public.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'learning-in-public'
4 | title: |
5 | Learning in public
6 | tags: 'page'
7 | excerpt: |
8 | tags: Learning
9 |
10 | pid: 210611104738
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Share your knowledge and insights. To do this in the most effective way you'll need to
[[ Explain in plain words]] . This "forces" you to refine your thinking until you can explain the topic in the most accessible way.
21 |
22 |
By learning and building in public you'll sooner or later post something that resonates with someone else. This feedback might lead to new insights and even better knowledge.
23 |
24 |
25 |
26 |
33 |
--------------------------------------------------------------------------------
/pages/learning.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'learning'
4 | title: |
5 | Learning
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/max-rozen.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'max-rozen'
4 | title: |
5 | Max Rozen
6 | tags: 'page'
7 | excerpt: |
8 | Twitter
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/pages/mdn.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'mdn'
4 | title: |
5 | MDN
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/pages/meta-viewport-for-mobile-devices.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'meta-viewport-for-mobile-devices'
4 | title: |
5 | Meta viewport for mobile devices
6 | tags: 'page'
7 | excerpt: |
8 | Mobile devices render pages in a virtual viewport, which is usually wider than the screen, and shrink the content to fit. This viewport won't work when we want to use Media queries. If the viewport is 980px and we have media queries that target 480px, they'll never fire.
9 | ---
10 |
11 |
12 |
13 |
14 |
Mobile devices render pages in a virtual viewport, which is usually wider than the screen, and shrink the content to fit. This viewport won't work when we want to use
[[ Media queries]] . If the viewport is
980px
and we have media queries that target
480px
, they'll never fire.
15 |
16 |
[[ Apple]] introduced the
viewport
meta
tag in
[[ Safari]] to let developers control the viewport's size and scale. This is not part of any web standard, but it's supported by most other mobile browsers.
17 |
18 |
19 |
20 | ```html
21 |
22 | ```
23 |
24 |
25 |
26 |
27 |
28 |
34 |
--------------------------------------------------------------------------------
/pages/mob-programming.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'mob-programming'
4 | title: |
5 | Mob programming
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/neovim.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'neovim'
4 | title: |
5 | Neovim
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/nerdtree.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'nerdtree'
4 | title: |
5 | NERDTree
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/nielsen-norman-group.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'nielsen-norman-group'
4 | title: |
5 | Nielsen Norman Group
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/pr.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'pr'
4 | title: |
5 | PR
6 | tags: 'page'
7 | excerpt: |
8 | A pull request
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
24 |
--------------------------------------------------------------------------------
/pages/prettier.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'prettier'
4 | title: |
5 | Prettier
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/react-podcast.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'react-podcast'
4 | title: |
5 | React Podcast
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/react-query.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'react-query'
4 | title: |
5 | React Query
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/react.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'react'
4 | title: |
5 | React
6 | tags: 'page'
7 | excerpt: |
8 | Documentation
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
28 |
--------------------------------------------------------------------------------
/pages/record-utility.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'record-utility'
4 | title: |
5 | Record utility
6 | tags: 'page'
7 | excerpt: |
8 | Documentation
9 | ---
10 |
11 |
12 |
13 |
18 |
19 |
20 |
24 |
--------------------------------------------------------------------------------
/pages/richard-feynman.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'richard-feynman'
4 | title: |
5 | Richard Feynman
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/rubber-ducking.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'rubber-ducking'
4 | title: |
5 | Rubber ducking
6 | tags: 'page'
7 | excerpt: |
8 | tags: Teaching, Learning
9 |
10 |
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Rubber ducking is the process of explaining your problem to another human or even an inanimate object like a plastic duck (hence the name). By putting the problem into words you might see issues that you've missed by only writing the code.
21 |
22 |
23 |
24 |
25 |
26 |
30 |
--------------------------------------------------------------------------------
/pages/rubocop.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'rubocop'
4 | title: |
5 | Rubocop
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/ryan-florence.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'ryan-florence'
4 | title: |
5 | Ryan Florence
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/seo.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'seo'
4 | title: |
5 | SEO
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/sha.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'sha'
4 | title: |
5 | SHA
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/share-shortcuts-and-plugins-when-teaching-new-developers.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'share-shortcuts-and-plugins-when-teaching-new-developers'
4 | title: |
5 | Share shortcuts and plugins when teaching new developers
6 | tags: 'page'
7 | excerpt: |
8 | tags: Development, Teaching
9 |
10 | pid: 211001194321
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
When teaching a new developer, share with them what keyboard shortcuts/commands you use and if you're using any specific plugins that can help with the task. These things are easy to forget the more advanced your own knowledge gets, but can have a great impact to new developers.
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
--------------------------------------------------------------------------------
/pages/shu-omi.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'shu-omi'
4 | title: |
5 | Shu Omi
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/socratic-method.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'socratic-method'
4 | title: |
5 | Socratic method
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/ssr.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'ssr'
4 | title: |
5 | SSR
6 | tags: 'page'
7 | excerpt: |
8 | Server-side rendering
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/pages/structure-of-css.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'structure-of-css'
4 | title: |
5 | Structure of CSS
6 | tags: 'page'
7 | excerpt: |
8 | tags: CSS
9 |
10 | pid: 210622091048
11 | ---
12 |
13 |
14 |
15 |
16 |
tags: [[ CSS]]
17 |
18 |
pid: 210622091048
19 |
20 |
The basic blocks of CSS are properties and values . Properties are a human-readable identifiers that describe what is being styled. Values indicate how to style that property. When these are paired together they create a CSS declaration
21 |
22 |
23 |
24 | ```css
25 | /* Property: color, value: red - together they form a CSS declaration */
26 | color: red;
27 | ```
28 |
29 |
30 |
31 |
CSS declarations are found within CSS declaration blocks . When CSS declaration blocks are paired with selectors (or a list of selectors) they produce CSS rulesets (or CSS rules).
32 |
33 |
34 |
35 | ```css
36 | /* p is a selector which together with the CSS declaration block creates a CSS rule */
37 | p {
38 | /* Multiple declarations form a CSS declaration block */
39 | background-color: black;
40 | color: white;
41 | }
42 | ```
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
--------------------------------------------------------------------------------
/pages/tdd.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'tdd'
4 | title: |
5 | TDD
6 | tags: 'page'
7 | excerpt: |
8 | Test-driven development
9 | ---
10 |
11 |
12 |
13 |
16 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/pages/teaching.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'teaching'
4 | title: |
5 | Teaching
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/technical-debt.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'technical-debt'
4 | title: |
5 | Technical debt
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/testing-library.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'testing-library'
4 | title: |
5 | Testing Library
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/testing.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'testing'
4 | title: |
5 | Testing
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/the-big-hack.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'the-big-hack'
4 | title: |
5 | The Big Hack
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/thomas-boutell.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'thomas-boutell'
4 | title: |
5 | Thomas Boutell
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/til.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'til'
4 | title: |
5 | TIL
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/pages/twitter.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'twitter'
4 | title: |
5 | Twitter
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/pages/typescript.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'typescript'
4 | title: |
5 | TypeScript
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/pages/use-the-objects-identifier-type.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'use-the-objects-identifier-type'
4 | title: |
5 | Use the object's identifier type
6 | tags: 'page'
7 | excerpt: |
8 | tags: TypeScript, Development
9 |
10 | pid: 211117191049
11 | ---
12 |
13 |
14 |
15 |
16 |
19 |
20 |
Select the object's identifier type instead of using for example string
when you have a function that should only take a specific identifier. This will make the code easier to refactor and also make it more evident what the function is expecting.
21 |
22 |
23 |
24 | ```ts
25 | type Task = {
26 | id: string
27 | }
28 |
29 | // This is fine, but might require refactoring if the id ever changes type
30 | function getTask(id: string) {}
31 |
32 | // Better alternative
33 | function getTask(id: Task['id']) {}
34 | ```
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
47 |
--------------------------------------------------------------------------------
/pages/vim.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: 'page'
3 | slug: 'vim'
4 | title: |
5 | Vim
6 | tags: 'page'
7 | ---
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/generate.test.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`#getContent renders a page 1`] = `
4 | Array [
5 | "Share your knowledge and insights. To do this in the most effective way you'll need to
[[ Explain in plain words]] . This \\"forces\\" you to refine your thinking until you can explain the topic in the most accessible way.
includes the commit in question in the rebase Commit B ",
6 | "We have some content that we want to position in the center of the screen. For this we can use
[[ CSS Grid]] . By defining fixed values at the edges of our grid template we can achieve spacing without using
padding
when the grid resizes on a smaller screen.
",
7 | [Circular],
8 | " ",
9 | "
10 |
11 | \`\`\`md
12 | pick 456 Commit B
13 | pick 789 Commit C
14 |
15 | # Commands
16 | # p, pick = use commit
17 | # e, edit = use commit, but stop for amending
18 | # ...
19 | \`\`\`
20 |
21 |
",
22 | ]
23 | `;
24 |
--------------------------------------------------------------------------------
/src/__tests__/elements.test.ts:
--------------------------------------------------------------------------------
1 | import { plain } from '../elements'
2 |
3 | describe('#plain', () => {
4 | test('handles heading 1', () => {
5 | const child = {
6 | content: '# test',
7 | }
8 |
9 | expect(plain('test', child)).toEqual(
10 | 'test '
11 | )
12 | })
13 |
14 | test('handles heading 2', () => {
15 | const child = {
16 | content: '## test',
17 | }
18 |
19 | expect(plain('test', child)).toEqual(
20 | 'test '
21 | )
22 | })
23 |
24 | test('handles heading 3', () => {
25 | const child = {
26 | content: '### test',
27 | }
28 |
29 | expect(plain('test', child)).toEqual(
30 | 'test '
31 | )
32 | })
33 |
34 | test('handles plain text', () => {
35 | const child = {
36 | content: 'test',
37 | }
38 |
39 | expect(plain('test', child)).toEqual('test')
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/src/__tests__/frontmatter.test.ts:
--------------------------------------------------------------------------------
1 | import { createFrontmatter } from '../frontmatter'
2 |
3 | describe('#createFrontmatter', () => {
4 | test('should return frontmatter without excerpt', () => {
5 | expect(createFrontmatter({ slug: 'title', title: 'title', contents: [] }))
6 | .toEqual(`---
7 | layout: 'page'
8 | slug: 'title'
9 | title: |
10 | title
11 | tags: 'page'
12 | ---
13 | `)
14 | })
15 |
16 | test('should return frontmatter with excerpt', () => {
17 | expect(
18 | createFrontmatter({
19 | slug: 'title',
20 | title: 'title',
21 | contents: ['[[Test]] #Tags Element
'],
22 | })
23 | ).toEqual(`---
24 | layout: 'page'
25 | slug: 'title'
26 | title: |
27 | title
28 | tags: 'page'
29 | excerpt: |
30 | Test Element
31 | ---
32 | `)
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/src/__tests__/generate.test.ts:
--------------------------------------------------------------------------------
1 | import { getContent } from '../generate'
2 |
3 | describe('#getContent', () => {
4 | const data = [
5 | {
6 | id: '60c32b51-33ce-4ab6-a8cf-46c52dc3b726',
7 | properties: { public: true },
8 | format: 'markdown',
9 | children: [],
10 | body: [['Paragraph', [['Break_Line']]]],
11 | content: 'public:: true',
12 | },
13 | {
14 | id: '60c32b51-d354-4ea8-ae01-683a8801ac6d',
15 | format: 'markdown',
16 | children: [
17 | {
18 | id: '60c32b52-534b-474b-9be1-382894ef91bc',
19 | format: 'markdown',
20 | children: [],
21 | title: [
22 | [
23 | 'Plain',
24 | 'We have some content that we want to position in the center of the screen. For this we can use ',
25 | ],
26 | [
27 | 'Link',
28 | {
29 | url: ['Search', 'CSS Grid'],
30 | label: [['Plain', '']],
31 | full_text: '[[CSS Grid]]',
32 | metadata: '',
33 | },
34 | ],
35 | [
36 | 'Plain',
37 | '. By defining fixed values at the edges of our grid template we can achieve spacing without using ',
38 | ],
39 | ['Code', 'padding'],
40 | ['Plain', ' when the grid resizes on a smaller screen.'],
41 | ],
42 | body: [],
43 | content:
44 | 'We have some content that we want to position in the center of the screen. For this we can use [[CSS Grid]]. By defining fixed values at the edges of our grid template we can achieve spacing without using `padding` when the grid resizes on a smaller screen.',
45 | },
46 | ],
47 | title: [
48 | [
49 | 'Plain',
50 | "Share your knowledge and insights. To do this in the most effective way you'll need to ",
51 | ],
52 | [
53 | 'Link',
54 | {
55 | url: ['Page_ref', 'Explain in plain words'],
56 | label: [['Plain', '']],
57 | full_text: '[[Explain in plain words]]',
58 | metadata: '',
59 | },
60 | ,
61 | ],
62 | [
63 | 'Plain',
64 | '. This "forces" you to refine your thinking until you can explain the topic in the most accessible way.',
65 | ],
66 | [
67 | 'Emphasis',
68 | [
69 | ['Bold'],
70 | [['Plain', ' includes the commit in question in the rebase']],
71 | ],
72 | ],
73 | ['Emphasis', [['Italic'], [['Plain', 'Commit B']]]],
74 | ],
75 | body: [],
76 | content:
77 | 'Share your knowledge and insights. To do this in the most effective way you\'ll need to [[Explain in plain words]]. This "forces" you to refine your thinking until you can explain the topic in the most accessible way.',
78 | },
79 | {
80 | id: '60c32b51-6c07-4b47-8f83-5cc0c94ec9de',
81 | format: 'markdown',
82 | children: [],
83 | title: [],
84 | body: [['Horizontal_Rule']],
85 | content: ' ---',
86 | },
87 | {
88 | id: '60c32b51-0d50-4e9d-93cc-70c2b5adf914',
89 | format: 'markdown',
90 | children: [],
91 | title: [],
92 | body: [
93 | [
94 | 'Src',
95 | {
96 | lines: [
97 | 'pick 456 Commit B',
98 | '\n',
99 | 'pick 789 Commit C',
100 | '\n',
101 | '\t ',
102 | '\n',
103 | '# Commands',
104 | '\n',
105 | '# p, pick = use commit',
106 | '\n',
107 | '# e, edit = use commit, but stop for amending',
108 | '\n',
109 | '# ...',
110 | '\n',
111 | ],
112 | language: 'md',
113 | pos_meta: { start_pos: 723, end_pos: 888 },
114 | full_content:
115 | '\t ```md\n\t pick 456 Commit B\n\t pick 789 Commit C\n\t \n\t # Commands\n\t # p, pick = use commit\n\t # e, edit = use commit, but stop for amending\n\t # ...\n\t ```\n',
116 | },
117 | ],
118 | ],
119 | content:
120 | '\t ```md\npick 456 Commit B\npick 789 Commit C\n\n# Commands\n# p, pick = use commit\n# e, edit = use commit, but stop for amending\n# ...\n```',
121 | },
122 | ]
123 |
124 | test('renders a page', () => {
125 | expect(getContent(data)).toMatchSnapshot()
126 | })
127 | })
128 |
--------------------------------------------------------------------------------
/src/__tests__/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { slugify } from '../utils'
2 |
3 | describe('#slugify', () => {
4 | test('removes any linked references', () => {
5 | expect(slugify('[[test]]')).toEqual('test')
6 | })
7 |
8 | test('removes any tags', () => {
9 | expect(slugify('#[[test]]')).toEqual('test')
10 | expect(slugify('#test')).toEqual('test')
11 | })
12 |
13 | test('sets the slug to lower case', () => {
14 | expect(slugify('TEsT')).toEqual('test')
15 | })
16 |
17 | test('replaces spaces with hyphens', () => {
18 | expect(slugify('test test test')).toEqual('test-test-test')
19 | })
20 |
21 | test('removes quotation marks', () => {
22 | expect(slugify("don't do this")).toEqual('dont-do-this')
23 | expect(slugify('dont "do" this')).toEqual('dont-do-this')
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/src/elementBuilder.ts:
--------------------------------------------------------------------------------
1 | import {
2 | boldText,
3 | code,
4 | externalLink,
5 | image,
6 | inlineCode,
7 | italicText,
8 | link,
9 | plain,
10 | quote,
11 | tag,
12 | warning,
13 | } from './elements'
14 | import { EmphasisType, LinkType, Type } from './types'
15 |
16 | const buildLink = (titleContent: any) => {
17 | const [linkType, url] = titleContent.url
18 |
19 | switch (linkType) {
20 | case LinkType.Search:
21 | case LinkType.PageRef:
22 | return link(url)
23 |
24 | case LinkType.Complex:
25 | return externalLink(url, titleContent.label[0][1])
26 |
27 | case LinkType.File:
28 | return image(url)
29 | }
30 | }
31 |
32 | const buildEmphasis = (titleContent: any) => {
33 | const emphasisType = titleContent[0][0]
34 | const text = titleContent[1][0][1]
35 |
36 | switch (emphasisType) {
37 | case EmphasisType.Bold:
38 | return boldText(text)
39 |
40 | case EmphasisType.Italic:
41 | return italicText(text)
42 | }
43 | }
44 |
45 | export const constructChildren = (
46 | child: any,
47 | [titleType, titleContent]: [Type, any]
48 | ) => {
49 | switch (titleType) {
50 | case Type.Plain:
51 | return plain(titleContent, child)
52 |
53 | case Type.Tag:
54 | return tag(titleContent)
55 |
56 | case Type.Code:
57 | return inlineCode(
58 | titleContent.replace(//g, '>')
59 | )
60 |
61 | case Type.Link:
62 | return buildLink(titleContent)
63 |
64 | case Type.Emphasis:
65 | return buildEmphasis(titleContent)
66 | }
67 | }
68 |
69 | export const constructTitle = ([titleType, titleContent, ...rest]: [
70 | Type,
71 | any,
72 | ...any
73 | ]) => {
74 | switch (titleType) {
75 | case Type.Src:
76 | return `${code(titleContent.lines.join(''), titleContent.language)}`
77 | case Type.Custom:
78 | if (titleContent === 'warning') {
79 | return warning(rest[2])
80 | }
81 | break
82 | case Type.Quote:
83 | return quote(titleContent)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/elements.ts:
--------------------------------------------------------------------------------
1 | import { Type } from './types'
2 | import { isJournal, removeLinkRef, slugify } from './utils'
3 |
4 | export const link = (title: string) => {
5 | const href = `/${isJournal(title) ? 'journals' : 'pages'}/${slugify(title)}`
6 |
7 | if (title.startsWith('..')) {
8 | return image(title)
9 | }
10 |
11 | if (title.startsWith('#')) {
12 | return internalLink(title)
13 | }
14 |
15 | return `[[ ${title}]] `
16 | }
17 |
18 | export const internalLink = (title: string) => {
19 | return `${title.substr(1)} `
22 | }
23 |
24 | export const externalLink = (
25 | link: { protocol: 'http' | 'https'; link: string },
26 | label: string
27 | ) => {
28 | return `${label} `
29 | }
30 |
31 | export const boldText = (title: string) => {
32 | return `${title} `
33 | }
34 |
35 | export const italicText = (title: string) => {
36 | return `${title} `
37 | }
38 |
39 | export const inlineCode = (title: string) => {
40 | return `${title}
`
41 | }
42 |
43 | export const code = (code: string, language = '') => {
44 | const snippet = code
45 | .replace(/{{/g, '{% raw %}{{')
46 | .replace(/}}/g, '}}{% endraw %}')
47 |
48 | return `\n\n\`\`\`${language}
49 | ${snippet}\`\`\`\n\n`
50 | }
51 |
52 | export const tag = (text: any) => {
53 | if (Array.isArray(text) && text[0][0] === Type.Plain) {
54 | return `#${removeLinkRef(text[0][1])} `
57 | } else if (Array.isArray(text) && text[0][0] === Type.Link) {
58 | return `#${removeLinkRef(text[0][1].url[1])} `
61 | }
62 | }
63 |
64 | export const image = (src: string) => {
65 | return ` `
66 | }
67 |
68 | export const warning = (text: string) => {
69 | return `${text}
`
70 | }
71 |
72 | export const quote = (content: any) => {
73 | let text = ''
74 |
75 | for (const [contentType, contentText] of content[0][1]) {
76 | if (contentType === Type.Plain) {
77 | text += contentText
78 | }
79 |
80 | if (contentType === Type.Emphasis && contentText[0][0] === 'Bold') {
81 | text += boldText(contentText[1][0][1])
82 | }
83 |
84 | if (contentType === Type.Link && contentText.url[0] === 'Complex') {
85 | text += externalLink(contentText.url[1], contentText.label[0][1])
86 | }
87 | }
88 |
89 | return `${text} `
90 | }
91 |
92 | export const plain = (text: string, child: any): string => {
93 | const slug = slugify(text)
94 | const isHeading = child.content.match(/^#+/)
95 |
96 | if (isHeading) {
97 | const headingType: 1 | 2 | 3 = isHeading[0].length
98 | const fontSize = {
99 | 1: 'text-2xl',
100 | 2: 'text-xl',
101 | 3: 'text-lg',
102 | }
103 |
104 | return `${text} `
105 | }
106 |
107 | return text
108 | }
109 |
--------------------------------------------------------------------------------
/src/frontmatter.ts:
--------------------------------------------------------------------------------
1 | import { isJournal, removeLinkRef } from './utils'
2 |
3 | const addExcerpt = (contents?: Array) => {
4 | const excerpt =
5 | contents?.[0]?.replace(/<[^>]*>/g, '').replace(/#\w+/g, '') ?? ''
6 |
7 | return excerpt
8 | ? `excerpt: |
9 | ${removeLinkRef(excerpt)}\n`
10 | : ''
11 | }
12 |
13 | const addRow = ([k, v]: [string, string]) => `${k}: '${v}'\n`
14 | const addMutlilineRow = ([k, v]: [string, string]) => `${k}: |
15 | ${v}\n`
16 |
17 | interface FrontmatterProps {
18 | slug: string
19 | title: string
20 | contents?: Array
21 | }
22 |
23 | export const createFrontmatter = ({
24 | slug,
25 | title,
26 | contents,
27 | }: FrontmatterProps) => {
28 | let t = {
29 | layout: 'page',
30 | slug,
31 | title,
32 | tags: isJournal(title) ? 'journal' : 'page',
33 | }
34 |
35 | let data = '---\n'
36 |
37 | for (let row of Object.entries(t)) {
38 | if (row[0] === 'title') {
39 | data += addMutlilineRow(row)
40 | } else {
41 | data += addRow(row)
42 | }
43 | }
44 |
45 | data += addExcerpt(contents)
46 | data += '---\n'
47 |
48 | return data
49 | }
50 |
--------------------------------------------------------------------------------
/src/references.ts:
--------------------------------------------------------------------------------
1 | import { LinkType, Type } from './types'
2 | import { slugify } from './utils'
3 |
4 | export const references = new Map()
5 |
6 | const addReference = (ref: string, title: string) => {
7 | if (references.has(ref)) {
8 | const current = references.get(ref)
9 | references.set(ref, current.add(title))
10 | } else {
11 | const newSet = new Set()
12 | references.set(ref, newSet.add(title))
13 | }
14 | }
15 |
16 | export const collectReferences = (children: any, title: string) => {
17 | for (const child of children) {
18 | if (child.title?.length > 0) {
19 | for (const [titleType, titleContent] of child.title) {
20 | if (
21 | titleType === Type.Link &&
22 | (titleContent.url[0] === LinkType.PageRef ||
23 | titleContent.url[0] === LinkType.Search)
24 | ) {
25 | addReference(slugify(titleContent.url[1]), title)
26 | } else if (
27 | titleType === Type.Tag &&
28 | titleContent?.[0]?.[0] === Type.Plain
29 | ) {
30 | addReference(slugify(titleContent[0][1]), title)
31 | } else if (
32 | titleType === Type.Tag &&
33 | titleContent?.[0]?.[0] === Type.Link
34 | ) {
35 | addReference(slugify(titleContent[0][1].url[1]), title)
36 | }
37 | }
38 |
39 | if (child.children.length > 0) {
40 | collectReferences(child.children, title)
41 | } else {
42 | continue
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export enum Type {
2 | Code = 'Code',
3 | Custom = 'Custom',
4 | Emphasis = 'Emphasis',
5 | Link = 'Link',
6 | Macro = 'Macro',
7 | Plain = 'Plain',
8 | Quote = 'Quote',
9 | Src = 'Src',
10 | Tag = 'Tag',
11 | }
12 |
13 | export enum LinkType {
14 | Complex = 'Complex',
15 | File = 'File',
16 | Search = 'Search',
17 | PageRef = 'Page_ref',
18 | }
19 |
20 | export enum EmphasisType {
21 | Bold = 'Bold',
22 | Italic = 'Italic',
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { constants } from 'fs'
2 | import { access, mkdir } from 'fs/promises'
3 |
4 | export const removeLinkRef = (text: string) => text.replace(/[\[\]\#]/g, '')
5 |
6 | export const isJournal = (title: string) => /^\d{4}-\d{2}-\d{2}$/.test(title)
7 |
8 | const clean = (input: string) =>
9 | input
10 | .replace(/[?()|'"]/g, '')
11 | .trim()
12 | .replace(/\s+/g, '-')
13 |
14 | export const slugify = (input: string) =>
15 | clean(removeLinkRef(input.trim().toLowerCase()))
16 |
17 | export const ensureDirectory = async (dir: string) => {
18 | try {
19 | await access(dir, constants.R_OK)
20 | } catch {
21 | await mkdir(dir)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/styles/style.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | body {
7 | @apply text-gray-700 dark:bg-gray-900 dark:text-gray-300;
8 | }
9 |
10 | ul {
11 | @apply pl-5 list-disc space-y-2;
12 | }
13 |
14 | li > ul {
15 | @apply mt-2;
16 | }
17 |
18 | h1 {
19 | @apply mb-5 text-3xl font-semibold;
20 | }
21 |
22 | pre {
23 | max-width: 100%;
24 | overflow: auto;
25 | }
26 |
27 | pre > code {
28 | @apply text-xs rounded;
29 | }
30 |
31 | :not(pre) > code {
32 | }
33 |
34 | :not(pre) > code {
35 | @apply text-xs border rounded border-cyan-300 dark:border-cyan-800 bg-opacity-20 dark:bg-opacity-20 bg-cyan-200 dark:bg-cyan-500;
36 | font-family: MonoLisa, 'Fira Code', Monaco, Menlo, Consolas, 'COURIER NEW',
37 | monospace;
38 | padding: 2px 5px !important;
39 | }
40 | }
41 |
42 | @layer components {
43 | .grid-template-main {
44 | grid-template-columns: 20px 1fr minmax(0, 660px) 1fr 20px;
45 | }
46 |
47 | .element-block {
48 | @apply flex items-start;
49 | }
50 |
51 | .element-block[data-level='1'] {
52 | @apply ml-4;
53 | }
54 |
55 | .element-block:before {
56 | @apply block mr-2 bg-gray-700 rounded-full;
57 | content: '';
58 | height: 6px;
59 | margin-top: 6px;
60 | width: 6px;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const colors = require('tailwindcss/colors')
2 |
3 | module.exports = {
4 | mode: 'jit',
5 | purge: [
6 | './*.njk',
7 | './_includes/*.njk',
8 | './*.11ty.js',
9 | './pages/*.md',
10 | './journals/*.md',
11 | ],
12 | darkMode: 'media',
13 | theme: {
14 | extend: {
15 | colors: {
16 | teal: colors.teal,
17 | rose: colors.rose,
18 | cyan: colors.cyan,
19 | },
20 | },
21 | },
22 | variants: {
23 | extend: {},
24 | },
25 | plugins: [],
26 | }
27 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "target": "esnext",
5 | "lib": ["esnext", "dom"],
6 | "moduleResolution": "node",
7 | "esModuleInterop": true,
8 | "resolveJsonModule": true
9 | }
10 | }
11 |
12 |
--------------------------------------------------------------------------------