diff --git a/packages/preview/joho-ipsj/0.1.0/LICENSE b/packages/preview/joho-ipsj/0.1.0/LICENSE new file mode 100644 index 0000000000..1636280621 --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 mkpoli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/preview/joho-ipsj/0.1.0/README.md b/packages/preview/joho-ipsj/0.1.0/README.md new file mode 100644 index 0000000000..8b055cbc3d --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/README.md @@ -0,0 +1,125 @@ +# 情報処理学会テンプレート (IPSJ Typst Templates) + +情報処理学会(Information Processing Society of Japan, IPSJ)で利用される各種文書のための Typst テンプレート集です。現時点では **研究報告(Technical Report)** のみをサポートしています。今後、論文誌・全国大会など他の文書形式への対応も予定しています。 + +## ⚠️ プレビュー段階のテンプレートです + +動作はしますが、組版細部や検証は十分ではありません。**学会への正式な提出には[公式テンプレート](https://www.ipsj.or.jp/journal/submit/style.html)を必ずご利用ください。** 本テンプレートは下書き・プレビュー用途に留めることを強く推奨します。 + +## サポート状況 + +| ドキュメント種別 | 状態 | 備考 | +|---|---|---| +| 研究報告(Technical Report) | ✅ プレビュー | 本リポジトリで提供 | +| 論文誌・全国大会・その他 | ⏳ 未対応 | 今後対応予定 | + +## 注意事項 + +* 本テンプレートは **非公式** であり、情報処理学会と一切関係ありません。 +* 開発中につき、仕様・出力は予告なく変更される可能性があります。 +* 学会から承認されたものではないため、利用は自己責任となります。本テンプレートを利用したことによる一切の損害について責任を負いません。 +* 正式な提出時は必ず[公式テンプレート](https://www.ipsj.or.jp/journal/submit/style.html)で再組版・確認してください。 + +## クイックスタート + +新しい原稿ディレクトリを作成(Typst Universe にて公開後): + +```bash +typst init @preview/joho-ipsj:0.1.0 my-report +cd my-report +typst compile main.typ +``` + +## 基本的な使い方 + +`techrep` を `#show` ルールで適用するだけで、研究報告のレイアウト・書式が自動で組まれます。 + +```typst +#import "@preview/joho-ipsj:0.1.0": techrep, acknowledgement, fake-bibliography + +#show: techrep.with( + title: [Typstによる情報処理研究報告の作成法], + title-en: "How to write IPSJ SIG Technical Report with Typst", + affiliations: ( + "IPSJ": [情報処理学会 \ IPSJ, Chiyoda, Tokyo 101–0062, Japan], + ), + authors: ( + ( + name: "情報 太郎", + name-en: "Taro Joho", + affiliations: ("IPSJ",), + email: "joho.taro@ipsj.or.jp", + ), + ), + abstract: [本稿では,情報処理学会研究報告のスタイルを Typst で再現するテンプレートを示す.], + abstract-en: [This paper presents a Typst template ...], + keywords: ("情報処理学会", "研究報告", "Typst"), + keywords-en: ("IPSJ", "Technical Report", "Typst"), + bibliography: bibliography("refs.yml", title: "参考文献"), +) + += はじめに + +本文をここに書きます. + += おわりに + +#acknowledgement[本研究は ... の支援を受けた.] +``` + +`typst init` で生成された `main.typ` には上記と同等の雛形が含まれています。`refs.yml` を参考文献として編集してください。 + +### `techrep` の主な引数 + +| 引数 | 型 | 説明 | +|---|---|---| +| `title` | content | 和文タイトル | +| `title-en` | string \| content | 英文タイトル | +| `affiliations` | dictionary | 所属(キー → 表示名) | +| `paffiliations` | dictionary | 現所属 | +| `authors` | array of dict | 著者情報(`name` / `name-en` / `affiliations` / `email`) | +| `abstract` | content | 和文概要 | +| `abstract-en` | content | 英文概要 | +| `keywords` | array | 和文キーワード | +| `keywords-en` | array | 英文キーワード | +| `volume` / `number` | string / int | 巻号 | +| `date` | datetime \| auto | 発行日(既定 `auto` で本日) | +| `bibliography` | content | 参考文献ブロック | +| `appendix` | content | 付録 | +| `fonts` | dictionary | 和文/欧文フォントの上書き | + +引数の詳細やデフォルト値は [`lib.typ`](./lib.typ) のドキュメントコメントを参照してください。 + +### その他の公開関数 + +* `acknowledgement(body)` — 「謝辞」セクションを組む +* `fake-bibliography(yaml-data, show-unused: false)` — 参考文献の見た目だけを組む補助関数 +* `table(..)` — IPSJ 風の罫線・スタイルを当てた表 + +## 開発・ローカルインストール(Tyler) + +本リポジトリは [Tyler](https://github.com/mkpoli/tyler) で管理されています。手元で改変したテンプレートを試す場合は、Universe ではなくローカルパッケージとしてインストールできます。 + +### 1. Tyler を導入 + +```bash +bun i -g @mkpoli/tyler +# または +npm install -g @mkpoli/tyler +``` + +### 2. ローカルにビルド & インストール + +リポジトリのルートで: + +```bash +tyler build -i +``` + +これでビルド成果物が `@local/joho-ipsj:0.1.0` としてローカル Typst パッケージに登録され、`typst init @local/joho-ipsj:0.1.0 my-report` で利用できます。 + +## 参照用ファイル + +* [情報処理学会研究報告テンプレート](https://www.ipsj.or.jp/journal/submit/style.html) +* [研究報告原稿(PDFファイル)作成について](https://www.ipsj.or.jp/kenkyukai/genko.html) +* [ken1row/IPSJ-techrep-xelatex](https://github.com/ken1row/IPSJ-techrep-xelatex/) diff --git a/packages/preview/joho-ipsj/0.1.0/lib.typ b/packages/preview/joho-ipsj/0.1.0/lib.typ new file mode 100644 index 0000000000..dd7eadfe6e --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/lib.typ @@ -0,0 +1,533 @@ +#import "lib/mixed-font.typ": mixed as mixed-font +#import "lib/latex.typ": draw-tex +#import "lib/bibliography.typ": fake-bibliography +#import "lib/number.typ": n +#import "@preview/tablex:0.0.9": tablex + +#let std-bibliography = bibliography + +// TODO: 2段組を採用しており,左右の段で行の基準線の位置が一致することを原則としている. + +// TODO: また,節見出しなど, +// 行の間隔を他よりたくさんとった方が読みやすい場所では, +// この原則を守るようにスタイルファイルが自動的にスペースを挿入する. + +#let table(..args) = { + // set text(size: 0.85em, fill: blue) + let named = args.named() + + let columns = if "columns" in named { + if type(named.columns) == array { + named.columns.len() + } else if type(named.columns) == int { + named.columns + } else { + panic("Invalid argument: columns") + } + } else { + 2 + } + + let rows = calc.floor(args.pos().len() / columns) + + tablex( + ..range(columns).map(it => []), + map-hlines: h => ( + ..h, + stroke: if ( + type(named.at("header-rows", default: none)) == int + and h.y <= named.header-rows + 1 + ) + or h.y == rows + 1 { 0.5pt } else {}, + ), + map-vlines: v => ( + ..v, + stroke: if v.x == named.at("header-columns", default: none) { + 0.5pt + } else {}, + ), + ..args, + rows: ( + 1pt, + ..{ + if "rows" not in named or type(named.rows) == int { + range(rows).map(it => auto) + } else if type(named.rows) == array { + named.rows + } else { + panic("Invalid argument: rows") + } + }, + ), + ) +} + +#let is-empty(it) = { + it == none or it == "" or it == [] or it == ("",) +} + +// #let LaTeX = { +// set text(font: "New Computer Modern") +// box(width: 2.55em, { +// [L] +// place(top, dx: 0.3em, text(size: 0.7em)[A]) +// place(top, dx: 0.7em)[T] +// place(top, dx: 1.26em, dy: 0.22em)[E] +// place(top, dx: 1.8em)[X] +// }) +// } + + +// #locate(query(selector(footnote).where(footnote.entry == "joho.taro@ipsj.or.jp")) + +#let abstract-block(abstract) = { + set text(size: 8.5pt) + align(center)[#block(width: 47em)[ + // #set text(size: 8.5pt) + #set par(justify: true, leading: 0.75em) + #set align(left) + *概要*:#abstract + ]] +} + +#let abstract-block-en(abstract, sans-font) = { + set text(size: 8.5pt) + align(center)[#block(width: 47em)[ + #set par(justify: true, leading: 0.5em) + #set align(left) + #text(style: "italic", font: sans-font, weight: "bold")[Abstract:] #abstract + ]] +} + +#let acknowledgement(body) = { + [*謝辞*#h(1em, weak: true)#body] +} + + + +/// 情報処理学会研究報告テンプレート +/// +/// - lang (string): 言語 +/// - title (string): 和文タイトル +/// - title-en (string): 英文タイトル +/// - affiliations (dictionary): 所属 +/// - paffiliations (dictionary): 現所属 +/// - replace-punctuations (bool): 句読点(、。)をコンマ・ピリオド「,.」に置き換えるかどうか +/// - authors (array): 著者情報 +/// - fonts (dictionary): フォントの設定 ```Typst +/// serif-ja // 和文フォント(明朝体) +/// sans-ja // 和文フォント(ゴシック体) +/// serif // 欧文フォント(セリフ体) +/// sans // 欧文フォント(サンセリフ体) +/// ``` +/// - abstract (string): 和文概要 +/// - abstract-en (string): 英文概要 +/// - keywords (array): 和文キーワード +/// - keywords-en (array): 英文キーワード +/// - date (auto, string): 日付 +/// - volume (string): 巻数 +/// - number (int): 号数 +/// - copyright (auto, string): コピーライト表記 +/// - appendix (array): 付録 +/// - bibliography (content): 参考文献 +/// - footnote-numbering (str, function): 脚注番号の形式(一般) +/// - footnote-numbering-email (str, function): 脚注番号の形式(メールアドレス) +/// - footnote-numbering-affiliate (str, function): 脚注番号の形式(所属) +/// - footnote-numbering-paffiliate (str, function): 脚注番号の形式(現所属) +/// -> content +#let techrep( + lang: "ja", + title: none, + // title: "Typstによる情報処理研究報告の作成法", + title-en: none, + // title-en: "How to write IPSJ SIG Technical Report with Typst", + affiliations: (:), + paffiliations: (:), + authors: ( + ( + name: "情報 太郎", + affiliations: ("IPSJ",), + email: "joho.taro@ipsj.or.jp", + ), + ), + fonts: ( + sans-ja: "Noto Sans CJK JP", + serif-ja: "Noto Serif CJK JP", + mono-ja: "Noto Sans Mono CJK JP", + sans: "Noto Sans", + // serif: "Noto Serif" + serif: "New Computer Modern", + // mono: "Noto Sans Mono" + mono: "New Computer Modern Mono", + ), + abstract: "", + abstract-en: "", + keywords: ("",), + keywords-en: ("",), + date: auto, + volume: str(datetime.today().year()) + "-XX-1XX", + number: 0, + copyright: auto, + replace-punctuations: true, + appendix: [], + bibliography: none, + footnote-numbering: (..num) => "*" + str(num.pos().at(0)), + footnote-numbering-email: "a)", + footnote-numbering-affiliate: "1", + footnote-numbering-paffiliate: "†1", + ..doc, +) = { + // メタデータ + set document( + title: title, + author: authors.map(it => it.name).join(", "), + keywords: keywords.join(", "), + ) + + if date == auto { + date = datetime.today() + } + + if copyright == auto { + copyright = ( + "© " + str(date.year()) + " Information Processing Society of Japan" + ) + } + + // 書体設定 + set text( + font: (fonts.serif, fonts.serif-ja), + size: 9.2pt, + lang: lang, + ) + show raw: it => { + set text(font: (fonts.mono, fonts.mono-ja), size: 1.25em) + it + } + show raw.where(block: true): it => { + set par(leading: 0.85em) + it + } + let mixed(body) = { + mixed-font(fonts.sans-ja, fonts.serif, body) + } + show strong: it => mixed(it) + show heading: it => { + mixed(it) + } + set super(typographic: false) + + // 間隔設定 + // #set page(margin: 1.75in) + // #set par(leading: 0.55em, first-line-indent: 1.8em, justify: true) + set par(leading: 0.55em, justify: true, spacing: 1em) + // #set text(font: "New Computer Modern") + // #show raw: set text(font: "New Computer Modern Mono") + + show quote: set block(above: 1em, below: 1em) + show quote: set pad(left: 2em) + set list(spacing: 0.85em, indent: 1em) + set enum(spacing: 0.85em, numbering: "( 1 )") + // show raw: block.with(above: 0pt, below: 0pt) + + set page( + margin: (top: 22.5mm, bottom: 22.5mm, left: 16.65mm, right: 16.65mm), + header: [ + #grid( + columns: (auto, auto), + gutter: 1fr, + [ + #set par(leading: 0.65em) + #text(size: 8.5pt, font: fonts.sans-ja)[情報処理学会研究報告] \ + #text( + size: 8pt, + stretch: 175%, + spacing: 175%, + )[IPSJ SIG Technical Report] + ], + [ + #set text(size: 8pt) + #set align(right) + Vol.#volume No.#number \ #date.display("[year]/[month]/[day]") + ], + ) + ], + header-ascent: 1.4em, + footer: grid( + columns: 2, + gutter: 1fr, + { + set text(size: 8pt) + copyright + }, + context { + counter(page).display("1") + }, + // #copyright + ), + footer-descent: 2.4em, + ) + + set par(first-line-indent: 1em) + set heading(numbering: (..params) => { + let numbers = params.pos() + return numbering( + if numbers.len() == 1 { "1." } else { "1.1.1" } + " ", + ..numbers, + ) + }) + show ref: it => { + let el = it.element + if el != none and el.func() == heading { + numbering( + "1.1", + ..counter(heading).at(el.location()), + ) + [章] + h(0pt, weak: true) + } else { + it + } + } + // show ref + + // 最初の段落の字下げを修正 + show heading: it => { + it + par()[#text(size: 0.5em)[#h(0.0em)]] + } + + /// タイトル + let title-block(body, en: false) = { + set align(center) + set text(size: if en { 1.5em } else { 2em }) + set par(leading: if en { 0.35em } else { 0.55em }) + v(if en { 2em } else { 2.45em }) + mixed(body) // タイトルへ応用 + } // タイトルのスタイル設定 + + show figure.where( + kind: raw, + ): it => { + show raw: set block( + stroke: 0.5pt + black, + inset: 0.5em, + above: 1em, + below: 1em, + ) + set figure(supplement: "1") + it + } + show figure.where( + supplement: [表], + ): set figure.caption(position: top) + show figure.caption: set text(size: 0.85em) + + /// Debug + let l(tag, value) = raw(tag + " = " + repr(value), lang: "typst", block: true) + + let emails = authors.map(author => author.email).filter(it => it != none) + let author-block(authors, lang: "ja") = { + set align(center) + set text(size: 1.25em) + v(1.25em) + + let label-map = (:) + for (i, author) in authors.enumerate() { + if lang == "ja" { + author.name + } else { + set text(0.85em, lang: "en") + upper(author.at("name-en", default: author.name)) + } + h(0pt, weak: true) + let footnote-markers = () + + let current-affiliations = affiliations + .keys() + .filter(affiliation => affiliation in author.affiliations) + + for (key, affiliation) in current-affiliations.enumerate() { + let footnote-marker = super(numbering( + footnote-numbering-affiliate, + key + 1, + )) + footnote-markers.push(footnote-marker) + } + + let current-paffiliations = paffiliations + .keys() + .filter(affiliation => affiliation in author.affiliations) + + for (key, affiliation) in current-paffiliations.enumerate() { + let footnote-marker = super(numbering( + footnote-numbering-paffiliate, + key + 1, + )) + footnote-markers.push(footnote-marker) + } + + if author.email != none { + footnote-markers.push(super(numbering( + footnote-numbering-email, + emails.position(it => it == author.email) + 1, + ))) + } + + for (i, footnote-marker) in footnote-markers.enumerate() { + footnote-marker + if (i < footnote-markers.len() - 1) { + super(",") + } + } + if (i != authors.len() - 1) { + h(1em) + } + } + if lang == "en" { + v(1.5em) + } else { + v(2.8em) + } + } + set footnote.entry( + separator: line(length: 50%, stroke: 0.5pt), + ) + + set footnote.entry(indent: 0pt) + show footnote.entry: entry => { + grid( + columns: (3em, 1fr), + numbering( + entry.note.numbering, + ..counter(footnote).at(entry.note.location()), + ), + entry.note.body, + ) + } + // 一般的な脚注 + set footnote(numbering: footnote-numbering) + + // TODO: + // if replace-punctuations { + // show "、": "," + // show "。": "." + // } + show "、": "," + show "。": "." + + show regex(" ?(Lua|Xe|BiB|pdf|p|up)?(La)?TeX(2e)? ?"): it => { + [ ] + draw-tex(it.text.trim()) + [ ] + } + + // 見出し設定 + show heading.where(level: 1): it => { + set block(above: 1.5em, below: 0.5em) + set text(size: 11.3pt) + it + } + show heading.where(level: 2): it => { + set block(above: 0.9em, below: 0.15em) + set text(size: 9.2pt) + it + } + show heading.where(level: 3): it => { + set block(above: 0.9em, below: 0em) + set text(size: 9.2pt) + it + } + + // 前付け + title-block(title) + author-block(authors) + // v(3em) + abstract-block(abstract) + if not is-empty(keywords) { + v(0.85em) + align(center, block(width: 8.5pt * 47)[ + #align(left)[ + *キーワード*:#keywords.join(", ") + ] + ]) + } + if not is-empty(title-en) { + set text(lang: "en") + title-block(title-en, en: true) + author-block(authors, lang: "en") + } else { + v(1em) + } + if not is-empty(abstract-en) { + set text(lang: "en") + abstract-block-en(abstract-en, fonts.sans) + } + if not is-empty(keywords-en) { + set text(lang: "en") + v(0.85em) + align(center, block(width: 8.5pt * 47)[ + #align(left)[ + #text(style: "italic", font: fonts.sans, weight: "bold")[Keywords:] + #keywords-en.join(", ") + ] + ]) + } + v(2em) + { + // 本文 + set par(leading: 8pt, spacing: 8pt) + // show par: set block(spacing: 1em, above: 0.5em, below: 0.5em) + + for (i, part) in doc.pos().enumerate() { + if type(part) == content { + columns(2, gutter: 5%, [ + #if i == 0 { + hide(context { + // 表題脚注があるケースに対応するため + let current-counter = counter(footnote).get() + + // 所属の脚注 + counter(footnote).update(0) + for affiliation in affiliations.values() { + footnote(affiliation, numbering: footnote-numbering-affiliate) + } + + // 現所属の脚注 + counter(footnote).update(0) + for paffiliation in paffiliations.values() { + footnote(paffiliation, numbering: footnote-numbering-paffiliate) + } + + // メールアドレスの脚注 + counter(footnote).update(0) + for email in emails { + footnote(email, numbering: footnote-numbering-email) + } + + // 本文の脚注に戻す + counter(footnote).update(current-counter) + }) + } + + #v(5pt) + #part + #if i == doc.pos().len() - 1 { + show std-bibliography: set text(size: 0pt) + bibliography + } + ]) + } else { + part.value + } + } + } + + if appendix != [] { + pagebreak() + counter(heading).update(0) + set heading(numbering: "付録1.1") + appendix + } +} + diff --git a/packages/preview/joho-ipsj/0.1.0/lib/bibliography.typ b/packages/preview/joho-ipsj/0.1.0/lib/bibliography.typ new file mode 100644 index 0000000000..9e063c92ec --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/lib/bibliography.typ @@ -0,0 +1,240 @@ +/// CSL言語の制限を超えたカスタマイズのための擬似的な参考文献リストを生成する +/// +/// - yaml-data (dictionary): Hayagriva YAML形式のデータ +/// - show-unused (boolean): 文内未参照のエントリーを表示するかどうか +#let fake-bibliography(yaml-data, show-unused: false) = { + if yaml-data == none { + return none + } + // set text(fill: blue) + // TODO: + // locate(loc => { + // let all-refs = query(cite, loc) + // repr(all-refs) + // }) + let format-entry(b) = { + let language = if "language" in b { + b.language + } else { + "en" + } + + let colon = if language == "ja" { + ":" + } else { + ": " + } + let comma = if language == "ja" { + "," + } else { + ", " + } + let period = if language == "ja" { + "." + } else { + ". " + } + let parenthesize(text) = "(" + text + ")" + + // 著者 + if "author" in b { + if type(b.author) == str { + b.author = (b.author,) + } + let replaced = b.author.map(a => if language == "ja" { + a.replace(", ", "") + } else { + a + }) + + if language == "ja" or replaced.len() == 1 { + replaced.join(comma) + } else { + replaced.slice(0, -1).join(comma) + " and " + replaced.at(-1) + } + } + + if "editor" in b { + if type(b.editor) == str { + b.editor = (b.editor,) + } + let replaced = b.editor.map(a => if language == "ja" { + a.replace(", ", "") + } else { + a + }) + + if language == "ja" or replaced.len() == 1 { + replaced.join(comma) + } else { + replaced.slice(0, -1).join(comma) + " and " + replaced.at(-1) + } + } + + colon + + if language == "en" and b.type == "Book" { + emph(b.title) + } else { + b.title + } + + if "note" in b { + " " + parenthesize(b.note) + } + + // Journal/Book of an article + if "parent" in b { + if "title" in b.parent { + comma + if language == "en" { + emph(b.parent.title) + } else { + (b.parent.title) + } + } + + if "volume" in b.parent { + comma + "Vol. " + str(b.parent.volume) + } + + if "issue" in b.parent { + comma + "No. " + str(b.parent.issue) + } + } + + if "series" in b { + comma + b.series + } + + if "volume" in b { + comma + "Vol. " + str(b.volume) + } + + if "issue" in b { + comma + "No. " + str(b.issue) + } + + if "publisher" in b { + comma + b.publisher + } + + if "address" in b { + comma + b.address + } + + let format-date(date) = { + "(" + let splitted = str(date).split("-") + splitted.join(".") + ")" + } + + if "date" in b { + [ ] + format-date(b.date) + } + + if "url" in b { + let url = none + let access = none + if type(b.url) == str { + url = b.url + } else { + url = b.url.value + access = b.url.date + } + + if url != none { + comma + [入手先 ] + "⟨" + url + "⟩" + } + + if access != none { + [ ] + format-date(access) + } + } + + if "page-range" in b { + comma + "pp. " + b.page-range + } + + if "doi" in b { + comma + "DOI: " + link("https://doi.org/" + b.doi, b.doi) + } + + if "serial-number" in b { + if type(b.serial-number) == str { + comma + b.serial-number + } + + for (key, number) in b.serial-number.pairs() { + comma + if key == "doi" { + "DOI: " + link("https://doi.org/" + number, number) + } else { + upper(key) + ": " + number + } + } + } + + period + } + + context { + let citations = query(ref.where(element: none)) + .map(r => str(r.target)) + .dedup() + + // If no citations are found, list all entries to prevent user confusion + let formatted-entries = if citations.len() == 0 { + yaml-data.values().map(value => format-entry(value)) + } else { + citations.map(c => format-entry(yaml-data.at(c))) + } + + /// Entries that are not cited + let rest-entries = if show-unused { + let used-entries = citations.map(c => yaml-data.at(c)) + yaml-data + .values() + .filter(e => not used-entries.contains(e)) + .map(format-entry) + } else { + () + } + + // repr(citations.len()) + set text(size: 8.5pt) + enum( + numbering: "[1]", + indent: 0em, + body-indent: 2em, + ..formatted-entries, + ..rest-entries, + ) + } +} diff --git a/packages/preview/joho-ipsj/0.1.0/lib/latex.typ b/packages/preview/joho-ipsj/0.1.0/lib/latex.typ new file mode 100644 index 0000000000..17da918b3c --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/lib/latex.typ @@ -0,0 +1,98 @@ +#let skew(angle, vscale: 1, body) = { + let (a, b, c, d) = (1, vscale * calc.tan(angle), 0, vscale) + let E = (a + d) / 2 + let F = (a - d) / 2 + let G = (b + c) / 2 + let H = (c - b) / 2 + let Q = calc.sqrt(E * E + H * H) + let R = calc.sqrt(F * F + G * G) + let sx = Q + R + let sy = Q - R + let a1 = calc.atan2(F, G) + let a2 = calc.atan2(E, H) + let theta = (a2 - a1) / 2 + let phi = (a2 + a1) / 2 + + set rotate(origin: bottom + center) + set scale(origin: bottom + center) + + rotate(phi, scale(x: sx * 100%, y: sy * 100%, rotate(theta, body))) +} + +#let fake-italic(body) = skew(-12deg, body) + +#let TeX = { + [T] + box(move( + dx: -1.5pt, + dy: 2.2pt, + box(scale(100%)[E]), + )) + box(move( + dx: -3.0pt, + dy: 0pt, + [X], + )) + h(-1.0pt) +} + +#let LaTeX = { + [L] + box(move( + dx: -4pt, + dy: -1pt, + box(scale(x: 80%, y: 70%, [A])), + )) + box(move( + dx: -5.7pt, + dy: 0pt, + [T], + )) + box(move( + dx: -7.0pt, + dy: 2.3pt, + box(scale(100%)[E]), + )) + box(move( + dx: -8.0pt, + dy: 0pt, + [X], + )) + h(-8.0pt) +} + +#let LaTeX2e = { + [2] + box(move( + dx: -1pt, + dy: 1.5pt, + box(text(style: "italic")[#fake-italic("ε")]), + )) +} + +/// Draw TeX logo +/// text (string): the text to be typeset. Examples: "LaTeX", "TeX", "LaTeX2e", "LuaLaTeX", "XeLaTeX", "pdfLaTeX", "pdfTeX", "LaTeX2ε", etc. +#let draw-tex(tex) = { + set text(font: "New Computer Modern Math") + box( + if (tex == "LaTeX") { + LaTeX + } else if (tex == "TeX") { + TeX + } else { + show "TeX": TeX + show "2e": LaTeX2e + tex + }, + ) +} + +// #let LaTeX2e = { +// LaTeX;box(move( +// dx: -4.2pt, dy: -1.2pt, +// box(scale(65%)[2]) +// ));box(move( +// dx: -5.7pt, dy: 0pt, +// [ε] +// ));h(-5.7pt) +// } diff --git a/packages/preview/joho-ipsj/0.1.0/lib/mixed-font.typ b/packages/preview/joho-ipsj/0.1.0/lib/mixed-font.typ new file mode 100644 index 0000000000..95593ab178 --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/lib/mixed-font.typ @@ -0,0 +1,29 @@ +/// 和文・欧文で異なるフォントを指定する +/// +/// - jfont (string, array): 和文フォントの種類 +/// - jweight (string, integer): 和文フォントの太さ +/// - efont (string, array): 欧文フォントの種類 +/// - eweight (string, integer): 欧文フォントの太さ +/// - body (content): 本文 +/// -> content +#let mixed( + jfont, + jweight: "regular", + jsize: 1em, + efont, + eweight: "bold", + esize: 1.05em, + body, +) = { + show regex("[\p{Latin}0-9]"): set text( + font: efont, + weight: eweight, + size: esize, + ) + show regex("[\p{scx:Han}\p{scx:Hira}\p{scx:Kana}]"): set text( + font: jfont, + weight: jweight, + size: jsize, + ) + body +} diff --git a/packages/preview/joho-ipsj/0.1.0/lib/number.typ b/packages/preview/joho-ipsj/0.1.0/lib/number.typ new file mode 100644 index 0000000000..3d79084071 --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/lib/number.typ @@ -0,0 +1,37 @@ +#let n(num, thousands: ",", decimal: ".") = { + let parts = str(num).split(".") + let decimal_part = if parts.len() == 2 { parts.at(1) } + let integer_part = parts + .at(0) + .rev() + .clusters() + .enumerate() + .map(item => { + let (index, value) = item + return ( + value + + if calc.rem(index, 3) == 0 and index != 0 { + thousands + } + ) + }) + .rev() + .join("") + return integer_part + if decimal_part != none { decimal + decimal_part } +} + +#let d = n.with(decimal: ".", thousands: ",") // English Style +#let c = n.with(decimal: ",", thousands: ".") // Continental Style +#let s = n.with(decimal: ".", thousands: " ") // SI Style (English) +#let f = n.with(decimal: ",", thousands: " ") // SI Style (French) + +#for x in (1.2, 65536, 3800.25) { + [ + *#x* \ + #raw("d" + "(" + str(x) + ")") = #d(x) \ + #raw("c" + "(" + str(x) + ")") = #c(x) \ + #raw("f" + "(" + str(x) + ")") = #s(x) \ + #raw("s" + "(" + str(x) + ")") = #f(x) \ + \ + ] +} diff --git a/packages/preview/joho-ipsj/0.1.0/template/main.typ b/packages/preview/joho-ipsj/0.1.0/template/main.typ new file mode 100644 index 0000000000..80ec486295 --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/template/main.typ @@ -0,0 +1,70 @@ +#import "@preview/joho-ipsj:0.1.0": acknowledgement, fake-bibliography, table, techrep + +#import "@preview/roremu:0.1.0": roremu + +#techrep( + title: [Typstによる情報処理研究報告の作成法], + title-en: "How to write IPSJ SIG Technical Report with Typst", + // title_en: [Template for IPSJ Technical Report using Typst], + affiliations: ( + "IPSJ": [情報処理学会 \ IPSJ, Chiyoda, Tokyo 101–0062, Japan], + ), + paffiliations: ( + "JU": [現在,情報処理大学 \ Presently with Johoshori University], + ), + authors: ( + ( + name: "情報 太郎", + name-en: "Taro Joho", + affiliations: ("IPSJ",), + email: "joho.taro@ipsj.or.jp", + ), + ( + name: "処理 花子", + name-en: "Hanako Shori", + affiliations: ("IPSJ",), + email: none, + ), + ( + name: "学会 次郎", + name-en: "Jiro Gakkai", + affiliations: ("IPSJ", "JU"), + email: "gakkai.jiro@ipsj.or.jp", + ), + ), + abstract: [ + #roremu(250) + ], + keywords: ("情報処理学会", "研究報告", "Typst"), + abstract-en: [ + #lorem(150) + ], + keywords-en: ("IPSJ", "Technical Report", "Typst"), + [ + = はじめに + #roremu(50)@Word + $E=m c^2$ + #roremu(50, offset: 50)#footnote("脚注の例") + $ E=m c^2 $ + #roremu(50, offset: 100)#footnote("脚注の例その2") + + = 本論 + + #roremu(500)@LaTeX + + = コードブロック + ``` + fn main() { + println!("Hello, world!"); + } + ``` + + = おわりに + + #roremu(150)@XeLaTeX + ], + bibliography: [ + #bibliography("refs.yml", title: "参考文献") + #fake-bibliography(yaml("refs.yml"), show-unused: false) + ], +) diff --git a/packages/preview/joho-ipsj/0.1.0/template/refs.yml b/packages/preview/joho-ipsj/0.1.0/template/refs.yml new file mode 100644 index 0000000000..6f8af6d48d --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/template/refs.yml @@ -0,0 +1,38 @@ +LaTeX: + type: Article + language: ja + title: 情報処理学会研究報告の準備方法(2018年10月29日版) + date: '2018-10-29' + page-range: '1-6' + author: ['情報, 太郎', '処理, 花子', '学会, 次郎'] + parent: + type: Periodical + title: 情報処理学会研究報告 + url: https://www.ipsj.or.jp/journal/submit/style.html + +Word: + type: Article + language: ja + title: MS-Wordによる研究報告作成のガイド(第3.5版) + date: '2023-09-18' + author: ['寺田, 真敏', '西田, 豊明', '植村, 俊亮'] + parent: + type: Periodical + title: 情報処理学会研究報告 + url: https://www.ipsj.or.jp/journal/submit/style.html + +XeLaTeX: + type: Article + language: ja + title: ShareLatexを用いた情報処理学会研究報告の共同執筆 + date: '2016-01-13' + author: ['情報, 太郎', '処理, 花子', '学会, 次郎'] + url: https://github.com/ken1row/IPSJ-techrep-xelatex + +Unused: + type: Book + language: en + title: Unused Book + author: ['John Doe', 'Jane May'] + publisher: The University + date: '2024' diff --git a/packages/preview/joho-ipsj/0.1.0/thumbnail.png b/packages/preview/joho-ipsj/0.1.0/thumbnail.png new file mode 100644 index 0000000000..257897270e Binary files /dev/null and b/packages/preview/joho-ipsj/0.1.0/thumbnail.png differ diff --git a/packages/preview/joho-ipsj/0.1.0/typst.toml b/packages/preview/joho-ipsj/0.1.0/typst.toml new file mode 100644 index 0000000000..43e61e3195 --- /dev/null +++ b/packages/preview/joho-ipsj/0.1.0/typst.toml @@ -0,0 +1,29 @@ +[package] +name = "joho-ipsj" +version = "0.1.0" +compiler = "0.13.0" +entrypoint = "lib.typ" +repository = "https://github.com/mkpoli/ipsj-typst-template" +authors = ["mkpoli "] +license = "MIT" +description = "IPSJ Technial Report template" +keywords = [ + "Information Processing Society of Japan", + "IPSJ", + "japanese", + "Computer Science", + "Computer Engineering", + "Software", + "Digital Humanities", +] +categories = ["paper", "report"] +exclude = ["compare/**", "docs/**", "*.ps1", ".gitignore"] + +[template] +entrypoint = "main.typ" +path = "template" +thumbnail = "thumbnail.png" + +[tool.tyler] +srcdir = "." +outdir = "dist"