記事の見た目をいじる のバックアップソース(No.2)

更新

[[プログラミング/svelte]]

* いろいろきれいに見えるようにする [#k9f0334b]

#contents

* メモ: style の :global について [#xfd2fae0]

svelte の style 定義には自動的にコンポーネントインスタンスの id が追加されるため、
そのコンポーネントに直接含まれる(子コンポーネントは除外)エレメントにしか効果を及ぼさない。

コンポーネントを超えて効果を期待する場合には :global を付ける。

https://svelte.jp/docs/svelte-components#style
 LANG: html
 <style>
 	:global(strong) {
 		/* これはすべての <strong> に適用されます */
 		margin: 0;
 	}
 
 	div :global(strong) {
 		/* これは「このコンポーネント内の <div> 要素」の中にある
 			 「すべての <strong> 要素」に
 			 適用されます */
 		color: goldenrod;
 	}
 </style>

上記の例では div に :global がかかっていないため、div にはコンポーネントインスタンスの 
ID が付き、その下にあることが条件になっている。

「このコンポーネントの子供」に適用したい場合にはこのテクニックが役に立ちそう。

* ArticleElement コンポーネントを作成 [#q2fec75a]

db の Article と同名だとややこしいことになるようなので ArticleElement とした。

src/routes/articles/ArticleElement.svelte に置くことも考えたのだけれど、
関連コードが増えてフォルダーを掘りたくなる気もしたので

src/lib/components/ArticleElement.svelte  にした
 LANG: html
 <script lang="ts" context="module">
   import { marked } from 'marked';
   import { baseUrl } from 'marked-base-url';
   import markedLinkifyIt from 'marked-linkify-it';
   import { markedHighlight } from 'marked-highlight';
   import hljs from 'highlight.js';
   import markedKatex from 'marked-katex-extension';
   import { page } from '$app/stores';
 
   import 'highlight.js/styles/stackoverflow-dark.min.css';
 
   marked.use(baseUrl('https://example.com/folder/'));
   const linkifyItSchemas = {};
   const linkifyItOptions = {};
   marked.use(markedLinkifyIt(linkifyItSchemas, linkifyItOptions));
   marked.use(
     markedHighlight({
       langPrefix: 'hljs language-',
       highlight(code, lang) {
         const language = hljs.getLanguage(lang) ? lang : 'plaintext';
         return hljs.highlight(code, { language }).value;
       },
     })
   );
   marked.use(
     markedKatex({
       throwOnError: false,
     })
   );
 </script>
 
 <script lang="ts">
   export let title: string;
   export let author: string;
   export let date: Date;
   export let body: string;
   export let permLink: string;
 </script>
 
 <article class="prose max-w-full p-4">
   <h1>{title}</h1>
   <div>
     <span>{author}</span>
     <span>{date.toLocaleString()}</span>
     <span><a href={permLink + '/edit'}>編集</a></span>
   </div>
   <content>
     {@html marked.parse(body)}
   </content>
 </article>

src/routes/articles/[...titleOrId]/+page.svelte
 LANG: html
 <script lang="ts">
   import type { PageData } from './$types';
   import ArticleElement from '$lib/components/ArticleElement.svelte';
   import { encodeTitle } from '../lib';
 
   export let data: PageData;
 </script>
 
 <ArticleElement 
   title={data.article.title}
   body={data.article.body}
   author={data.article.author.name}
   date={data.article.createdAt}
   permLink={data.urlRoot + '/articles/' + encodeTitle(data.article.title)}
 />

* 見出しのレベルを調整 [#s2a8d1d1]

ブログ記事ではタイトルが h1 なので本文中では一番大きいのが h2 になる。

 LANG: ts
   // デフォルトのレンダラ
   const vanillaRenderer = new marked.Renderer();
 
   // 見出しの階層を1つ下げる
   marked.use({
     renderer: {
       heading(text, level, raw) {
         return vanillaRenderer.heading(text, level + 1, raw);
       }
     }
   });

* ベース URL [#db9a96e3]

 LANG: ts 
 import { baseUrl } from 'marked-base-url';
 import { PUBLIC_URL_ROOT } from '$env/static/public';
   ...
 
   // ベースアドレス
   marked.use(baseUrl(PUBLIC_URL_ROOT));

* シンタックスハイライト [#fea7e75c]

痒い所に手が届くよう、marked-highlight を使わず自分でやろう。

 $ pnpm rm marked-highlight

Counter: 383 (from 2010/06/03), today: 3, yesterday: 0