Changes
9 changed files (+579/-1)
-
NOTICE (new)
-
@@ -0,0 +1,23 @@Macana Copyright 2024 Shota FUJI --- This application includes asset files in a source code form developed by Lucide project (https://lucide.dev/). ISC License Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-
-
@@ -25,3 +25,5 @@- Application source code is licensed under [Apache-2.0](./LICENSES/Apache-2.0.txt). - Documentation files are licensed under [CC-BY-4.0](./LICENSES/CC-BY-4.0.txt). - Tool config files (e.g. `.gitignore`) are licensed under [CC0-1.0](./LICENSES/CC0-1.0.txt). This project bundles third-party source code. See [NOTICE](./NOTICE) file for more details.
-
-
-
@@ -27,6 +27,8 @@export { macanaReplaceAssetTokens } from "./obsidian_markdown/mdast_util_macana_replace_asset_tokens.ts"; export { macanaReplaceDocumentToken } from "./obsidian_markdown/mdast_util_macana_replace_document_tokens.ts"; export { ofmWikilinkToHastHandlers } from "./obsidian_markdown/mdast_util_ofm_wikilink.ts"; export { ofmCalloutToHastHandlers } from "./obsidian_markdown/mdast_util_ofm_callout.ts"; export type { CalloutType } from "./obsidian_markdown/mdast_util_ofm_callout.ts"; function getFrontMatterValue( frontmatter: Record<string, unknown>,
-
-
-
@@ -5,6 +5,8 @@import type * as Mdast from "../../deps/esm.sh/mdast/types.ts"; import type { Extension } from "../../deps/esm.sh/mdast-util-from-markdown/mod.ts"; import { SKIP, visit } from "../../deps/esm.sh/unist-util-visit/mod.ts"; import type { State } from "../../deps/esm.sh/mdast-util-to-hast/mod.ts"; import type * as Hast from "../../deps/esm.sh/hast/types.ts"; export interface OfmCallout extends Mdast.Node { type: "ofmCallout";
-
@@ -187,3 +189,160 @@ },], }; } function normalizeType(typeIdent: string) { switch (typeIdent.toLowerCase()) { case "abstract": case "summary": case "tldr": return "abstract"; case "info": return "info"; case "todo": return "todo"; case "tip": case "hint": case "important": return "tip"; case "success": case "check": case "done": return "success"; case "question": case "help": case "faq": return "question"; case "warning": case "caution": case "attention": return "warning"; case "failure": case "fail": case "missing": return "failure"; case "danger": case "error": return "danger"; case "bug": return "bug"; case "example": return "example"; case "quote": case "cite": return "quote"; default: return "note"; } } export type CalloutType = ReturnType<typeof normalizeType>; export interface OfmCalloutToHastHandlersOptions { generateTitleId?(count: number): string; generateIcon?(type: CalloutType): Hast.ElementContent | null; } function defaultTitleId(count: number): string { return `_ofm_callout__${count}`; } export function ofmCalloutToHastHandlers( { generateTitleId = defaultTitleId, generateIcon }: OfmCalloutToHastHandlersOptions = {}, ) { let counter = 0; return { ofmCallout(state: State, node: OfmCallout): Hast.Nodes { const titleTextTitleCased = node.calloutType.slice(0, 1).toUpperCase() + node.calloutType.slice(1).toLowerCase(); const type = normalizeType(node.calloutType); const titleId = generateTitleId(counter++); const icon = generateIcon?.(type); const title: Hast.ElementContent[] = node.title.length > 0 ? state.all({ type: "paragraph", children: node.title, }) : [{ type: "text", value: titleTextTitleCased, }]; if (node.isFoldable) { return { type: "element", tagName: "aside", properties: { "data-ofm-callout-type": type, "aria-labelledby": titleId, }, children: [ { type: "element", tagName: "details", properties: { open: node.defaultExpanded ? "" : undefined, }, children: [ { type: "element", tagName: "summary", properties: { id: titleId, }, children: [ ...(icon ? [icon] : []), ...title, ], }, { type: "element", tagName: "div", properties: {}, // @ts-expect-error: unist-related libraries heavily relies on ambient module declarations, // which Deno does not support. APIs also don't accept type parameters. children: state.all(node), }, ], }, ], }; } return { type: "element", tagName: "aside", properties: { "data-ofm-callout-type": type, "aria-labelledby": titleId, }, children: [ { type: "element", tagName: "p", properties: { id: titleId, }, children: [ ...(icon ? [icon] : []), ...title, ], }, { type: "element", tagName: "div", properties: {}, // @ts-expect-error: unist-related libraries heavily relies on ambient module declarations, // which Deno does not support. APIs also don't accept type parameters. children: state.all(node), }, ], }; }, }; }
-
-
-
@@ -11,6 +11,22 @@> [!info]+ Title > Body ```markdown > [!danger] > Danger! ``` > [!danger] > Danger! ```markdown > [!warning]- > Yay ``` > [!warning]- > Yay ## Escapes ```markdown
-
-
-
@@ -30,7 +30,7 @@ - [x] PDF file- [ ] List from another file - [ ] Search results - [x] ==Highlight== - [ ] Callouts - [x] Callouts - [ ] Comments %% You can check this item once I'm no longer visible %% - [ ] Strip Raw HTML (only `<title>` is troublesome, but align behavior to Obsidian's) - [ ] `<script>` <script>console.log("This tag should be eliminated: escaping is not suffice")</script>
-
-
-
@@ -261,4 +261,20 @@ hr {margin: 0; margin-top: calc(var(--baseline) * 1rem); } aside[data-ofm-callout-type] { margin: 0; margin-top: calc(var(--baseline) * 1rem); padding: calc(var(--baseline) * 0.5rem) 1em; line-height: calc(var(--baseline) * 1rem); max-width: 100%; font-size: 1rem; border: 1px solid var(--color-fg-light); border-radius: 4px; } aside[data-ofm-callout-type] > p:first-child, aside[data-ofm-callout-type] > details > summary { margin-top: 0; font-weight: 700; } `;
-
-
-
@@ -16,7 +16,9 @@ import * as HastToJSXRuntime from "../../../deps/esm.sh/hast-util-to-jsx-runtime/mod.ts";import type { Document, DocumentTree } from "../../../types.ts"; import { type CalloutType, type ObsidianMarkdownDocument, ofmCalloutToHastHandlers, ofmWikilinkToHastHandlers, } from "../../../content_parser/obsidian_markdown.ts"; import type { JSONCanvasDocument } from "../../../content_parser/json_canvas.ts";
-
@@ -27,6 +29,8 @@import { globalStyles } from "./global_styles.ts"; import { mapTocItem, tocMut } from "../hast/hast_util_toc_mut.ts"; import type { Assets } from "../builder.tsx"; import * as LucideIcons from "./lucide_icons.tsx"; import * as DocumentTreeUI from "./organisms/document_tree.tsx"; import * as Footer from "./organisms/footer.tsx";
-
@@ -58,6 +62,50 @@ }function toNode(hast: ReturnType<typeof toHast>) { return toJsxRuntime(hast, { components: { MacanaOfmCalloutIcon({ type }: { type: CalloutType }) { switch (type) { case "abstract": return ( <LucideIcons.ClipboardList role="img" aria-label="Clipboard icon" /> ); case "info": return <LucideIcons.Info role="img" aria-label="Info icon" />; case "todo": return ( <LucideIcons.CircleCheck role="img" aria-label="Check icon" /> ); case "tip": return <LucideIcons.Flame role="img" aria-label="Flame icon" />; case "success": return <LucideIcons.Check role="img" aria-label="Check icon" />; case "question": return ( <LucideIcons.CircleHelp role="img" aria-label="Question icon" /> ); case "warning": return ( <LucideIcons.TriangleAlert role="img" aria-label="Warning icon" /> ); case "failure": return <LucideIcons.X role="img" aria-label="Cross icon" />; case "danger": return <LucideIcons.Zap role="img" aria-label="Lightning icon" />; case "bug": return <LucideIcons.Bug role="img" aria-label="Bug icon" />; case "example": return <LucideIcons.List role="img" aria-label="List icon" />; case "quote": return <LucideIcons.Quote role="img" aria-label="Quote icon" />; case "note": default: return <LucideIcons.Pencil role="img" aria-label="Pencil icon" />; } }, }, Fragment, jsx(type, props, key) { return jsx(type, nanoifyProps(props), key || "");
-
@@ -70,6 +118,7 @@ }export const styles = css.join( globalStyles, LucideIcons.styles, DocumentTreeUI.styles, Footer.styles, SiteLayout.styles,
-
@@ -88,6 +137,18 @@ const hast = toHast(content.content, {// @ts-expect-error: unist-related libraries heavily relies on ambiend module declarations, // which Deno does not support. APIs also don't accept type parameters. handlers: { ...ofmCalloutToHastHandlers({ generateIcon(type) { return { type: "element", tagName: "MacanaOfmCalloutIcon", properties: { type, }, children: [], }; }, }), ...ofmWikilinkToHastHandlers, }, });
-
-
-
@@ -0,0 +1,299 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 // // This file includes source code of [Lucide](https://lucide.dev/). // See NOTICE file at the project root for its own license. /** @jsx h */ import { h } from "../../../deps/deno.land/x/nano_jsx/mod.ts"; import { css } from "../css.ts"; function cls( ...classNames: readonly (string | null | false | undefined)[] ): string { return classNames.filter((c) => typeof c === "string").join(" "); } const enum C { Icon = "li--i", } export const styles = css` .${C.Icon} { height: 1em; width: auto; vertical-align: sub; } `; export interface LucideIconProps { className?: string; role?: string; } export function ClipboardList({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <rect width="8" height="4" x="8" y="2" rx="1" ry="1" /> <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" /> <path d="M12 11h4" /> <path d="M12 16h4" /> <path d="M8 11h.01" /> <path d="M8 16h.01" /> </svg> ); } export function Pencil({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" /> <path d="m15 5 4 4" /> </svg> ); } export function Info({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <circle cx="12" cy="12" r="10" /> <path d="M12 16v-4" /> <path d="M12 8h.01" /> </svg> ); } export function CircleCheck({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <circle cx="12" cy="12" r="10" /> <path d="m9 12 2 2 4-4" /> </svg> ); } export function Flame({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z" /> </svg> ); } export function Check({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M20 6 9 17l-5-5" /> </svg> ); } export function CircleHelp({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <circle cx="12" cy="12" r="10" /> <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /> <path d="M12 17h.01" /> </svg> ); } export function TriangleAlert({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /> <path d="M12 9v4" /> <path d="M12 17h.01" /> </svg> ); } export function X({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M18 6 6 18" /> <path d="m6 6 12 12" /> </svg> ); } export function Zap({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" /> </svg> ); } export function Bug({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="m8 2 1.88 1.88" /> <path d="M14.12 3.88 16 2" /> <path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" /> <path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" /> <path d="M12 20v-9" /> <path d="M6.53 9C4.6 8.8 3 7.1 3 5" /> <path d="M6 13H2" /> <path d="M3 21c0-2.1 1.7-3.9 3.8-4" /> <path d="M20.97 5c0 2.1-1.6 3.8-3.5 4" /> <path d="M22 13h-4" /> <path d="M17.2 17c2.1.1 3.8 1.9 3.8 4" /> </svg> ); } export function List({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <line x1="8" x2="21" y1="6" y2="6" /> <line x1="8" x2="21" y1="12" y2="12" /> <line x1="8" x2="21" y1="18" y2="18" /> <line x1="3" x2="3.01" y1="6" y2="6" /> <line x1="3" x2="3.01" y1="12" y2="12" /> <line x1="3" x2="3.01" y1="18" y2="18" /> </svg> ); } export function Quote({ className, ...rest }: LucideIconProps) { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest} className={cls(C.Icon, className)} > <path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z" /> <path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z" /> </svg> ); }
-