Teruhiro Komaki's Diary (Archive)

タグ:ブログ(3)

author
Teruhiro Komaki komaki.dev
2024年 04月 02日 火曜日
01時00分

<code>タグにコードを貼り付けるためのミニアプリを作りました

個人の日記や、会社のブログを投稿するうえで、<code>タグにHTMLや、様々なコードを貼り付けるケースが多く、適切にエスケープする必要があります。

今までは、以下のサイトのように、文字列をエスケープしてくれるサイトを使っていました。

マークアップとして間違って評価されないように、文字列をエスケープしてくれるサイトです。

Free Online HTML Escape / Unescape Tool - FreeFormatter.com

HTMLのエスケープをしてくれるサイト
エスケープをしてくれるサイト

しかし、このようなサイトは、バックグラウンドでどのようなことが起こっているか分からないので、あまり積極的に使いたくないな…と思っていました。

そこで、隙間時間を使い、上記のサイトの代替となりうる自分専用のミニアプリを作りました。

Code Escape for <code> tag

リリースしたミニアプリ
リリースしたミニアプリ

自分がほしいミニアプリが作れて、満足しています。

今回、初めてVite(Vite + Bootstrap + PostCSS)を使いました。

以下のコードを貼る際に、早速ミニアプリを使っています。

自分のメモのために、コードを貼っておきます。

vite.config.js

const path = require('node:path');
import viteCompression from 'vite-plugin-compression';
import {defineConfig} from 'vite';

/** @type {import('vite').UserConfig} */
export default defineConfig({
  root: path.resolve(__dirname, 'src'),
  base: '/',
  build: {
    outDir: '../dist',
  },
  server: {
    port: 8080,
  },
  plugins: [viteCompression()],
});

postcss.config.js

const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const purgeCss = require('@fullhuman/postcss-purgecss');

/** @type {import('postcss-load-config').Config} */
const config = {
  plugins: [
    autoprefixer(),
    purgeCss({
      content: ['src/**/*.html'],
      variables: true,
    }),
    cssnano(),
  ],
};
module.exports = config;

src/js/main.js

// Import our custom CSS
import '../scss/styles.scss';

const DEFAULT_PATTERN = `&<>"{}#$%'()*+-\/`;

const CodeElement = document.getElementById('code');
const PatternElement = document.getElementById('pattern');
const EscapedElement = document.getElementById('escaped');
const CopyButtonElement = document.getElementById('copy');

// CodeElement
CodeElement.placeholder = `For example...\n<tag></tag>\n{{ template }}`;
CodeElement.addEventListener('input', (e) => {
  updateEscapedElement();
});
CodeElement.addEventListener('input', (e) => {
  EscapedElement.value = escapeHtml(CodeElement.value);
  CopyButtonElement.disabled = !Boolean(CodeElement.value);
});

function updateEscapedElement() {
  EscapedElement.value = escapeHtml(CodeElement.value);
  CopyButtonElement.disabled = !Boolean(CodeElement.value);
}

// PatternElement
PatternElement.value = getPattern() ? getPattern() : DEFAULT_PATTERN;
PatternElement.placeholder = DEFAULT_PATTERN;
PatternElement.addEventListener('input', (e) => {
  setPattern(PatternElement.value);
  updateEscapedElement();
});

// CopyButtonElement
CopyButtonElement.addEventListener('click', (e) => {
  onClickCopy();
});

export function onClickCopy() {
  if (EscapedElement.value) {
    navigator.clipboard.writeText(EscapedElement.value);
  }
}

function escapeHtml(text) {
  const pattern = `[${PatternElement.value}]`;
  const regexPattern = new RegExp(pattern, 'g');
  return text.replace(regexPattern, (character) => {
    return '&#' + character.charCodeAt(0) + ';';
  });

}

function getPattern() {
  return window.localStorage.getItem('pattern');
}

function setPattern(value) {
  return window.localStorage.setItem('pattern', value);
}
よろしければ、使ってみてください。
author
Teruhiro Komaki komaki.dev
2024年 03月 15日 金曜日
00時30分

EleventyのPaginationについて

このサイトは、#Eleventyを使って、HTMLを生成しています。

#EleventyPaginationという機能を使い、、以下のスクショのように、年、月、日、タグのページを動的に生成しています。

スクリーンショット
スクリーンショット

タグのページを動的に生成する書き方は、以下のページに丁寧に書かれています。

Quick Tip #004—Zero Maintenance Tag Pages for your Blog — Eleventy

以下のようなFront Matterを書けば、動的にタグのページが生成されます。

すばらしく簡単です!

---
pagination:
  data: collections
  size: 1
  alias: tag
permalink: /tags/{{ tag }}/
---
<h1>Tagged “{{ tag }}”</h1>

<ol>
{% set taglist = collections[ tag ] %}
  {% for post in taglist | reverse %}
    <li><a href="{{ post.url }}">{{ post.data.title }}</a></li>
  {% endfor %}
</ol>

実装するなかで、ひとつ課題がありました。

以下のようにcollectionApi.getAll()をしても、Paginationの結果がNページある場合においても、1ページしか取得できない問題に遭遇しました。

eleventyConfig.addCollection('allPost', (collectionApi) => {
    const posts = collectionApi.getAll()
    for (const post of posts) {
      console.log(post.data.title)
    }
    return posts
  });

調べてみると、以下のIssueに答えがありました。

Collections.all only lists first page created with pagination, not others · Issue #253 · 11ty/eleventy

以下のように、Paginationを設定しているファイルのFront MatterにaddAllPagesToCollections: trueを追加することで、すべてのPaginationのページが取得できました。

---
pagination:
  addAllPagesToCollections: true
---
author
Teruhiro Komaki komaki.dev
2024年 03月 14日 木曜日
15時50分

タイトルを考えることのコスト

タイトルを考えることって、以外にコストが高いのではないか?と思いまして…

このサイトは、タイトルという概念を持っておらず、投稿日時をパースして、自動的にタイトルにしています。

具体的には、以下のような文字列をタイトルにしています。

2024年03月14日 15時50分

今まで、色々と#ブログを書いてきましたが、#WordPressの投稿一覧に、下書きのまま眠っている記事が山のようにあります。

書きたいことが見つかったら、すぐに、その内容を投稿する。

本当は、これくらい簡単なことで良いような気がしています。

いつかのタイミングで、投稿や伝えたいことを整理して、一つの記事にまとめて投稿する。という運用で良いのではないかと…