Skip to content

QuadnucYard/ourchat-typ

Repository files navigation

Ourchat

Universe GitHub

Create chat interfaces in Typst with ease

Ourchat is a Typst package for building chat UI mockups. It helps you document software features, create presentations, or prototype chat interfaces with themes for popular platforms like WeChat, Discord, and QQ.

typst-frame

#let yau = wechat.default-user(name: [丘成桐(囯內)])

#wechat.chat(
  theme: "dark",
  ..oc.with-side-user(
    left,
    yau,
    oc.time[5月16日 上午10:23],
    oc.free-message[
      已經到了無恥的地步。
    ],
    oc.time[6月18日 凌晨00:06],
    oc.free-message[
      我宣布他已經不是我的學生了
    ],
    oc.time[14:00],
    oc.free-message[
      這種成績,使人汗顏!如此成績,如何招生?
    ],
  ),
  oc.message(right, yau)[
    我沒有説過這種話!

    ——發自我的手機
  ],
)

Features

  • Out-of-the-box themes: WeChat, Discord, QQNT theme support
  • Simple API: Easy-to-use, declarative interface
  • Customizable styling: Colors, avatars, layouts, and typography
  • Just do it: Write anything inside messages—Code blocks, tables, mathematical equations…

Quick Start

First, import the package in your Typst document:

#import "@preview/ourchat:0.2.0" as oc
#import oc.themes: *

Then create your first chat:

#let alice = wechat.user(name: [Alice], avatar: circle(fill: blue, text(white)[A]))
#let bob = wechat.user(name: [Bob], avatar: circle(fill: green, text(white)[B]))

#wechat.chat(
  oc.time[Today 14:30],

  oc.message(left, alice)[
    Hey! How's the new project going?
  ],

  oc.message(right, bob)[
    Great! Just finished the API integration.
    The performance improvements are impressive! 🚀
  ],
)

typst-frame

Builtin Themes

WeChat Theme

#let user1 = wechat.user(name: [Alice], avatar: circle(fill: blue, text(white)[A]))
#let user2 = wechat.user(name: [Bob], avatar: circle(fill: green, text(white)[B]))

#wechat.chat(
  theme: "light",  // or "dark"
  layout: (
    bubble-radius: 8pt,
  ),
  width: 400pt,

  oc.time[Monday 9:00 AM],
  oc.message(left, user1)[Hello world!],
  oc.message(right, user2)[Hi there! 👋],
)

typst-frame

Discord Theme

#set text(font: ("gg sans", "IBM Plex Sans SC"))

#let developer = discord.user(
  name: [Dev],
  avatar: circle(fill: purple, text(white)[D])
)
#let admin = discord.user(
  name: [Admin],
  avatar: circle(fill: red, text(white)[A])
)

#discord.chat(
  oc.time[Today at 2:14 PM],

  oc.message(left, developer)[
```python
def optimize_query():
    return cache_strategy.redis_cluster()
```
    What do you think about this approach? @admin
  ],

  oc.message(right, admin)[
    @developer Looks good! The Redis cluster should handle the load well.
  ],
)

typst-frame

QQNT Theme

#let student = qqnt.user(
  name: [Student],
  avatar: circle(fill: orange, text(white)[S])
)
#let expert = qqnt.user(
  name: [Expert],
  avatar: circle(fill: teal, text(white)[E])
)

#qqnt.chat(
  theme: (
    inherit: "light",
    bubble-left: rgb("#F0F8FF"),
    bubble-right: rgb("#E8F5E8"),
    text-right: rgb("#111111"),
  ),

  oc.message(left, student)[
    Can someone explain Rust ownership?
  ],

  oc.message(right, expert)[
    Sure! Ownership prevents data races at compile time...
  ],
)

typst-frame

Advanced Usage

Convenience Functions

For multiple messages from the same user, use with-side-user to avoid repetition:

#set text(font: ("gg sans", "IBM Plex Sans SC"))

#let admin = oc.user(
  name: [System Admin],
  avatar: circle(fill: red.darken(20%), text(white, weight: "bold")[⚡])
)

#discord.chat(
  oc.time[Today at 3:45 PM],

  // Instead of repeating the user for each message:
  // oc.message(left, admin)[Server maintenance scheduled],
  // oc.message(left, admin)[Downtime: 30 minutes max],
  // oc.message(left, admin)[Please save your work],

  // Use with-side-user for cleaner code:
  ..oc.with-side-user(
    left,
    admin,
    oc.free-message[🚨 *URGENT: Server Maintenance Alert*],
    oc.free-message[Scheduled downtime: Tonight 11 PM - 11:30 PM],
    oc.free-message[All services will be temporarily unavailable],
    oc.free-message[Please save your work and plan accordingly],
  ),
)

typst-frame

Custom User Avatars

Create distinctive user profiles:

#let ceo = oc.user(
  name: [Sarah Chen],
  badge: qqnt.badge(text-color: purple, bg-color: purple.transparentize(80%))[#text(stroke: 0.05em + purple)[CEO]],
  avatar: rect(
    fill: blue.darken(20%),
    radius: 4pt,
    inset: 6pt,
    text(white, weight: "bold")[SC]
  )
)

#qqnt.chat(
  oc.message(left, ceo)[
    Hi team! Ready for the quarterly review?
  ],
)

typst-frame

Rich Content Support

Include tables, code blocks, and visual elements:

#let analyst = wechat.user(
  name: [Data Analyst],
  avatar: circle(fill: green.darken(10%), text(white)[📊])
)

#wechat.chat(
  oc.message(left, analyst)[
    Here's our performance analysis:

    #table(
      columns: (auto, auto, auto),
      [*Metric*], [*Before*], [*After*],
      [Response Time], [250ms], [120ms],
      [Throughput], [1000 RPS], [2500 RPS],
    )

    The optimization yielded 58% improvement! 📊
  ]
)

typst-frame

Theme Customization

Modify existing themes or create your own:

#let custom_theme = (
  inherit: "light",
  background: rgb("#F5F5F5"),
  bubble-left: rgb("#E3F2FD"),
  bubble-right: rgb("#C8E6C9"),
  text-primary: rgb("#212121"),
  text-secondary: rgb("#757575"),
)

#wechat.chat(theme: custom_theme, ...)

Layout Control

Fine-tune spacing and dimensions:

#wechat.chat(
  layout: (
    content-width: 350pt,
    message-spacing: 0.8em,
    avatar-size: 32pt,
    bubble-padding: 12pt,
  ),
  ...
)

Examples Gallery

Explore our comprehensive example collection: https://quadnucyard.github.io/ourchat-typ

The source codes for these example are located at ./examples.

Architecture & Design

API Design Philosophy

Ourchat follows a unified component architecture where oc provides the core building blocks:

  • oc.message(), oc.user(), oc.time() - Universal components that work across all themes
  • Built-in themes (wechat, discord, qqnt) import all common components but may override them for platform-specific features
    • For example, qqnt.user() extends the base user component with badge support for role badges
  • Uses chat as the rendering function of messages, which is defined in individual themes. Styling is decided here.
// Universal approach - works with any theme
#let user = oc.user(name: [Alice])

// Theme-specific approach - leverages extended features
#let qqnt_user = qqnt.user(
  name: [Alice],
  badge: qqnt.badge()[Admin]  // QQNT specific feature
)

Theme Customization Scope

Built-in themes provide a solid foundation but don't cover every possible customization. You're encouraged to:

  • Extend existing themes for minor modifications using theme and layout parameters.
  • Create entirely new themes for different platforms or unique designs with basic blocks. Refer to the source code of built-in themes as implementation guides

API Reference

Here only lists exported functions and variables. Please refer to the documentation comments of each function for details

Common Components

  • oc.user(name, avatar, badge): Create universal user profiles
  • oc.message(side, user, body, time, merge): Add chat messages (left or right)
  • oc.time(body): Insert timestamp dividers
  • oc.with-side-user(side, user, ..messages): Convenience for multiple messages from same user
  • oc.free-message(body, time, merge): Create message without specific user or side
  • oc.plain(side, user, body): Create plain item without padding

Note: These are just helper functions for data wrapping. You can directly create data structures if you like.

Theme Collections

oc.themes.wechat

WeChat layout and color schemes (light, dark)

  • wechat.chat(theme, layout, width, validate, ..messages): WeChat-style interface
  • wechat.default-user: Pre-configured user with WeChat avatar

oc.themes.qqnt

QQNT layout and color schemes (light, dark)

  • qqnt.chat(theme, layout, width, validate, ..messages): QQNT-style interface
  • qqnt.user (uses oc.user with badge support): QQNT user with role support
  • qqnt.badge(body, text-color, bg-color): Create role badges

oc.themes.discord

Discord layout and color schemes

  • discord.newbie-user: Pre-configured user with newbie badge
  • discord.mention(body): Create Discord-style mention element
  • discord.chat(theme, layout, width, validate, auto-mention, ..messages): Discord-style interface

Utilities (oc.utils)

  • validate-theme(theme, reference, field-type): Validate theme dictionary fields
  • validate-layout(layout, reference): Validate layout dictionary fields
  • resolve-theme(themes, theme, default, validate): Resolve theme with inheritance support
  • resolve-layout(layout, default-layout, validate): Merge and validate layout settings
  • stretch-cover(item): Scale content to cover its container
  • auto-mention-rule(auto-mention, styler): Create show rule for automatic mention styling

Contributing

We welcome contributions! Please check our GitHub repository for:

  • Bug reports and feature requests
  • Code contributions and improvements
  • Documentation updates
  • New theme proposals and existing theme improvements

License

MIT License - see LICENSE file for details.

About

Forge wonderful chat messages in typst

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •