Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/preview/texst/0.1.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Shusuke Ioku

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.
129 changes: 129 additions & 0 deletions packages/preview/texst/0.1.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# texst

`TeXst` is a Typst package for LaTeX-like academic paper formatting.

## Start Here

Use one of these package imports:

1. Published package (Typst Universe):

```typst
#import "@preview/texst:0.1.0": paper
```

2. Local package install:

```typst
#import "@local/texst:0.1.0": paper
```

## Manual Install (No `@preview`)

If you download the repo manually, you can install it as a local Typst package:

1. Download and unzip this repository.
2. Copy its contents into this folder structure:
- macOS: `~/Library/Application Support/typst/packages/local/texst/0.1.0/`
- Linux: `~/.local/share/typst/packages/local/texst/0.1.0/`
- Windows: `%APPDATA%\\typst\\packages\\local\\texst\\0.1.0\\`
3. Import from `@local` in your Typst file:

```typst
#import "@local/texst:0.1.0": paper
```

## Fastest Way to Use It

Copy this into your `main.typ`:

```typst
#import "@preview/texst:0.1.0": paper

#show: doc => paper(
title: [Paper Title],
subtitle: [Optional Subtitle],
authors: (
(name: [Author One]),
(name: [Author Two]),
),
date: datetime.today().display("[month repr:long] [day], [year]"),
abstract: [Write a concise abstract here.],
doc,
)

#outline(title: [Contents])

#heading(level: 1)[Introduction]

Start writing your paper.

#heading(level: 1)[Appendix]

#heading(level: 2)[Additional Material]

Add supplementary details here.
```

## Initialize a Template Project

```bash
typst init @preview/texst:0.1.0
```

This generates a starter project from `template/main.typ`.

## What `paper(...)` Does

`paper(...)` applies:
- page layout and numbering
- typography defaults
- heading style and spacing
- table/figure alignment and numbering
- equation and reference behavior
- title block and abstract formatting

Your document content is passed through `doc`.

## Public API

- `paper(title:, subtitle:, authors:, date:, abstract:, style:, doc)`
- `nneq(eq)` (unnumbered display equation)
- `caption-note(body)`
- `caption-with-note(title, note)`
- `table-note(body)`
- `theorem`, `proof`, `prop`, `lem`, `rem`, `asp`

## Style Overrides

Pass a `style` dictionary to override defaults:

```typst
#show: doc => paper(
title: [Styled Paper],
style: (
body_font: "Libertinus Serif",
page_margin: (x: 1in, y: 1in),
heading_numbering: "1.",
accent_main: rgb(20, 40, 120),
),
doc,
)
```

Common keys include:
- `page_margin`, `page_numbering`
- `body_font`, `body_size`
- `paragraph_leading`, `paragraph_indent`
- `heading_numbering`, `heading_size`, `heading_weight`
- `footnote_numbering`, `accent_main`

## Local Development

- `examples/minimal.typ` is the local smoke test.
- `template/main.typ` is the package template entrypoint.
- Compile locally:

```bash
typst compile --root . examples/minimal.typ /tmp/minimal.pdf
```
223 changes: 223 additions & 0 deletions packages/preview/texst/0.1.0/src/lib.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#import "@preview/ctheorems:1.1.3": *
#import "@preview/cetz:0.4.2"

// =============================================================================
// BASIC SETTINGS (edit here)
// =============================================================================
#let page-margin = (x: 1.2in, y: 1.2in)
#let page-numbering = "1"

#let body-font = "New Computer Modern"
#let body-size = 11pt
#let body-top-edge = 0.7em
#let body-bottom-edge = -0.3em

#let par-leading = 1em
#let par-first-indent = 1.8em

#let heading-numbering = "1."
#let heading-size = 1em
#let heading-weight = "bold"
#let heading-level1-size = 0.9em

#let table-text-size = 0.8em
#let table-leading = 0.65em
#let table-top-edge = 0.35em
#let table-bottom-edge = -0.3em

#let block-above = 1.5em
#let block-below = 1.5em

#let footnote-numbering = "[1]"

#let cmain = rgb(0,0,100)
#let csub = rgb("#8b0000")

// =============================================================================
// UTILITIES
// =============================================================================
#let nneq(eq) = math.equation(block: true, numbering: none, eq)
#let caption-note(body) = align(left)[
#pad(x: 2em, y: 0em)[
#par(leading: 0.2em)[
#text(size: 0.9em)[*Note:* #body]
]
]
]
#let caption-with-note(title, note) = [#title #caption-note(note)]
#let table-note(body) = align(left)[
#text(size: 0.9em)[#emph(body)]
]

#show: thmrules.with(qed-symbol: $square$)
#let theorem = thmbox("theorem", "Theorem")
#let proof = thmproof(
"proof", "Proof"
)
#let prop = thmbox(
"prop",
"Proposition",
inset: (x:2em, y:.5em),
base_level: 0,
base: "prop",
titlefmt: smallcaps,
bodyfmt: body => [
#body
]
).with(numbering: "1")
#let lem = thmbox(
"lem",
"Lemma",
inset: (x:2em, y:.5em),
base_level: 0,
base: "lem",
titlefmt: smallcaps,
bodyfmt: body => [
#body
]
).with(numbering: "1")
#let rem = thmbox(
"rem",
"Remark",
inset: (x:2em, y:.5em),
base_level: 0,
base: "rem",
titlefmt: smallcaps,
bodyfmt: body => [
#body
]
).with(numbering: "1")
#let ass = thmbox(
"ass",
"Assumption",
inset: (x:2em, y:.5em),
base_level: 0,
base: "ass",
titlefmt: smallcaps,
bodyfmt: body => [
#body
]
).with(numbering: "1")

#let paper(
title: none,
subtitle: none,
authors: (),
date: none,
abstract: none,
doc,
) = {
set page(
margin: page-margin,
numbering: page-numbering
)

set par(
leading: par-leading,
first-line-indent: par-first-indent,
justify: true
)

set text(
font: body-font,
size: body-size,
top-edge: body-top-edge,
bottom-edge: body-bottom-edge
)

set math.equation(numbering: "(1)")
set table(align: (x, _) => if x == 0 { left } else { center })
set figure(numbering: "1")
show ref: it => {
let eq = math.equation
let el = it.element
if el != none and el.func() == eq {
// Override equation references.
numbering(
el.numbering,
..counter(eq).at(el.location())
)
} else {
// Other references as usual.
it
}
}

set bibliography(style: "american-political-science-association")
show bibliography: set par(first-line-indent: 0em)

set quote(block: true)

set heading(numbering: heading-numbering)
show heading: set block(above: 2em, below: 1em)
show heading: set par(leading: 0.3em)
show heading: set text(size: heading-size, weight: heading-weight)
//show heading: set text(font: "PT Sans", weight: "bold")
// Center first level headings only
show heading: it => {
if it.level == 1 {
smallcaps(align(center, text(size: heading-level1-size, it)))
} else {
it
}
}

set enum(indent: 1.8em)
show enum: set block(above: 1em, below: 1em)

show table: set text(size: table-text-size)
show table: set par(leading: table-leading)
show table: set text(top-edge: table-top-edge, bottom-edge: table-bottom-edge)
show figure: set block(below: 0em)
set block(above: block-above, below: block-below)
show figure: set align(center)
// Set all tables to be centered
show table: set align(center)
// Also center table captions
show figure.where(kind: table): set align(center)
// Center figures with tables inside them
show figure.where(body: it => {
if it.func() == table { true } else { false }
}): set align(center)

//show figure.caption: set text(font: "PT Sans", weight: "regular")
set figure(placement: auto)

show link: set text(rgb(0,0,100))
show ref: set text(rgb(0,0,100))
show cite: set text(rgb(0,0,100))
show footnote: set text(rgb(0,0,100))
show footnote: set text(weight:"bold")
//show footnote.entry: set par(leading: 1em)
//set footnote.entry(gap: 1em)
set footnote(numbering: footnote-numbering)

v(4em)
set align(center)
par(leading: .5em)[#text(1.2em)[#title]\ #text(1em)[#subtitle]]

let count = authors.len()
let ncols = calc.min(count, 3)
grid(
columns: (1fr,) * ncols,
row-gutter: 24pt,
..authors.map(author => [
#text(author.name) \
//#text(0.8em, author.affiliation) \
//#text(0.8em, link("mailto:" + author.email))
]),
)

text(date)

set align(left)
if abstract != none {
pad(x: 3em,
par(leading: 0.4em,
text(0.9em,
[#smallcaps("Abstract.") #abstract]
)))
}

doc
}
Loading