/// /// import { ChildStyle, Style } from "./deps.ts"; export type AttributeSelectorOperator = "^=" | "=" | "$=" | "*=" | "~=" | "|="; export interface URLInit { url: string; /** * 属性セレクタに使用する演算子 * 指定しない場合は`^=`が用いられる */ selectorSyntax: AttributeSelectorOperator; } export interface LinkInit { url: string | URLInit | (string | URLInit)[]; style: ChildStyle; } /** * 外部リンクを区別するUserCSSを生成する関数 */ export function generateExternalLinkStyle( /** アイコンを付与しないURLが入ったオブジェクト */ links: LinkInit[], /** オプションで設定するスタイル(CSS) */ style?: { /** 外部リンクを区別するアイコンに設定するスタイル */ icon?: ChildStyle; }, ): Style { const urls = getURLFromLinkInit(links); const selector = ".line span:not(.modal-image):not(.pointing-device-map) > a.link:not(.icon):not(:is(" + urls.reduce( (pre, crt) => `${pre}[href${crt.selectorSyntax}"${crt.url}"],`, "", ) + "))::after"; const iconStyleDefault: ChildStyle = { "display": "inline-block", "padding-right": "2px", "font-size": ".5em", "font-weight": "bold", "font-family": "'Font Awesome 5 Free', 'Font Awesome 5 Brands'", "content": "'\\f35d'", "cursor": "text", }; const iconStyle: Style = { [selector]: style?.icon === undefined ? iconStyleDefault : { ...iconStyleDefault, ...style.icon }, }; return iconStyle; } /** * 特定のリンクにアイコンをつけるUserCSSを生成する関数 */ export function generateLinkIconStyle( /** アイコンを付与するリンクの情報 */ links: LinkInit[], /** オプションで設定するスタイル(CSS) */ style?: { /** アイコンに共通で設定するスタイル */ iconBase?: ChildStyle; }, ): Style { const allURLs = getURLFromLinkInit(links); const baseSelector = ".line span:not(.deco-\\.) > span > a.link:is(" + allURLs.reduce( (pre, crt) => `${pre}[href${crt.selectorSyntax}"${crt.url}"],`, "", ) + ")::before"; const baseStyleDefault: ChildStyle = { "display": "inline-block", "width": "auto", "height": "1em", "line-height": "1em", "vertical-align": "middle", "text-align": "center", "background-size": "contain", "background-repeat": "no-repeat", "font-family": "'Font Awesome 5 Free', 'Font Awesome 5 Brands'", "cursor": "text", }; /** 先頭にアイコンを付けるための共通のスタイル */ const baseStyle: Style = { [baseSelector]: style?.iconBase === undefined ? baseStyleDefault : { ...baseStyleDefault, ...style.iconBase }, }; const individualStyle: Style = {}; for (const link of links) { const urls = getURLFromLinkInit([link]); const selector = ":is(.line, .line .deco) a.link:is(" + urls.reduce( (pre, crt) => `${pre}[href${crt.selectorSyntax}"${crt.url}"],`, "", ) + ")::before"; individualStyle[selector] = link.style; } return { ...baseStyle, ...individualStyle }; } /** * LinkInitの配列からURLを取り出す * @param {LinkInit[]} links 取り出し元のオブジェクト * @param {AttributeSelectorOperator} [defaultOperator="^="] selectorSyntaxが指定されていなかった際に使用するデフォルト値 * @return {URLInit[]} */ function getURLFromLinkInit( links: LinkInit[], defaultOperator: AttributeSelectorOperator = "^=", ): URLInit[] { const resultURLs: URLInit[] = []; for (const link of links) { if (Array.isArray(link.url)) { for (const url of link.url) { if (typeof url === "string") { resultURLs.push({ url: url, selectorSyntax: defaultOperator }); } else { resultURLs.push(url); } } } else { const url = link.url; if (typeof url === "string") { resultURLs.push({ url: url, selectorSyntax: defaultOperator }); } else { resultURLs.push(url); } } } return resultURLs; }