Skip to content

Commit 23d8c4b

Browse files
authored
ourchat:0.2.1 (#3606)
1 parent 54abbce commit 23d8c4b

File tree

19 files changed

+4209
-0
lines changed

19 files changed

+4209
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 [QuadnucYard]
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
<h1>
2+
3+
Ourchat
4+
5+
</h1>
6+
7+
<a href="https://typst.app/universe/package/ourchat">
8+
9+
<img src="https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Ftypst.app%2Funiverse%2Fpackage%2Fourchat&amp;query=%2Fhtml%2Fbody%2Fdiv%2Fmain%2Fdiv%5B2%5D%2Faside%2Fsection%5B2%5D%2Fdl%2Fdd%5B3%5D&amp;logo=typst&amp;label=Universe&amp;color=%2339cccc" alt="Universe" />
10+
11+
</a> <a href="https://github.com/QuadnucYard/ourchat-typ">
12+
13+
<img src="https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2FQuadnucYard%2Fourchat-typ%2Frefs%2Fheads%2Fmain%2Ftypst.toml&amp;query=package.version&amp;logo=GitHub&amp;label=GitHub" alt="GitHub" />
14+
15+
</a>
16+
17+
_Create chat interfaces in Typst with ease_
18+
19+
Ourchat is a [Typst](https://typst.app/) 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.
20+
21+
## Features
22+
23+
- **Out-of-the-box themes**: WeChat, Discord, QQNT theme support
24+
- **Simple API**: Easy-to-use, declarative interface
25+
- **Customizable styling**: Colors, avatars, layouts, and typography
26+
- **Just do it**: Write anything inside messages—Code blocks, tables, mathematical equations…
27+
28+
## Quick Start
29+
30+
First, import the package in your Typst document:
31+
32+
```typst
33+
#import "@preview/ourchat:0.2.1" as oc
34+
#import oc.themes: *
35+
```
36+
37+
Then create your first chat:
38+
39+
```typst
40+
#let alice = wechat.user(name: [Alice], avatar: circle(fill: blue, text(white)[A]))
41+
#let bob = wechat.user(name: [Bob], avatar: circle(fill: green, text(white)[B]))
42+
43+
#wechat.chat(
44+
oc.time[Today 14:30],
45+
46+
oc.message(left, alice)[
47+
Hey! How's the new project going?
48+
],
49+
50+
oc.message(right, bob)[
51+
Great! Just finished the API integration.
52+
The performance improvements are impressive! 🚀
53+
],
54+
)
55+
```
56+
57+
![typst-frame](assets/frame_0.svg)
58+
59+
## Builtin Themes
60+
61+
### WeChat Theme
62+
63+
```typst
64+
#let user1 = wechat.user(name: [Alice], avatar: circle(fill: blue, text(white)[A]))
65+
#let user2 = wechat.user(name: [Bob], avatar: circle(fill: green, text(white)[B]))
66+
67+
#wechat.chat(
68+
theme: "light", // or "dark"
69+
layout: (
70+
bubble-radius: 8pt,
71+
),
72+
width: 400pt,
73+
74+
oc.time[Monday 9:00 AM],
75+
oc.message(left, user1)[Hello world!],
76+
oc.message(right, user2)[Hi there! 👋],
77+
)
78+
```
79+
80+
![typst-frame](assets/frame_1.svg)
81+
82+
### Discord Theme
83+
84+
````typst
85+
#set text(font: ("gg sans", "IBM Plex Sans SC"))
86+
87+
#let developer = discord.user(
88+
name: [Dev],
89+
avatar: circle(fill: purple, text(white)[D])
90+
)
91+
#let admin = discord.user(
92+
name: [Admin],
93+
avatar: circle(fill: red, text(white)[A])
94+
)
95+
96+
#discord.chat(
97+
oc.time[Today at 2:14 PM],
98+
99+
oc.message(left, developer)[
100+
```python
101+
def optimize_query():
102+
return cache_strategy.redis_cluster()
103+
```
104+
What do you think about this approach? @admin
105+
],
106+
107+
oc.message(right, admin)[
108+
@developer Looks good! The Redis cluster should handle the load well.
109+
],
110+
)
111+
````
112+
113+
![typst-frame](assets/frame_2.svg)
114+
115+
### QQNT Theme
116+
117+
```typst
118+
#let student = qqnt.user(
119+
name: [Student],
120+
avatar: circle(fill: orange, text(white)[S])
121+
)
122+
#let expert = qqnt.user(
123+
name: [Expert],
124+
avatar: circle(fill: teal, text(white)[E])
125+
)
126+
127+
#qqnt.chat(
128+
theme: (
129+
inherit: "light",
130+
bubble-left: rgb("#F0F8FF"),
131+
bubble-right: rgb("#E8F5E8"),
132+
text-right: rgb("#111111"),
133+
),
134+
135+
oc.message(left, student)[
136+
Can someone explain Rust ownership?
137+
],
138+
139+
oc.message(right, expert)[
140+
Sure! Ownership prevents data races at compile time...
141+
],
142+
)
143+
```
144+
145+
![typst-frame](assets/frame_3.svg)
146+
147+
## Advanced Usage
148+
149+
### Convenience Functions
150+
151+
For multiple messages from the same user, use `with-side-user` to avoid repetition:
152+
153+
```typst
154+
#set text(font: ("gg sans", "IBM Plex Sans SC"))
155+
156+
#let admin = oc.user(
157+
name: [System Admin],
158+
avatar: circle(fill: red.darken(20%), text(white, weight: "bold")[⚡])
159+
)
160+
161+
#discord.chat(
162+
oc.time[Today at 3:45 PM],
163+
164+
// Instead of repeating the user for each message:
165+
// oc.message(left, admin)[Server maintenance scheduled],
166+
// oc.message(left, admin)[Downtime: 30 minutes max],
167+
// oc.message(left, admin)[Please save your work],
168+
169+
// Use with-side-user for cleaner code:
170+
..oc.with-side-user(
171+
left,
172+
admin,
173+
oc.free-message[🚨 *URGENT: Server Maintenance Alert*],
174+
oc.free-message[Scheduled downtime: Tonight 11 PM - 11:30 PM],
175+
oc.free-message[All services will be temporarily unavailable],
176+
oc.free-message[Please save your work and plan accordingly],
177+
),
178+
)
179+
```
180+
181+
![typst-frame](assets/frame_4.svg)
182+
183+
### Custom User Avatars
184+
185+
Create distinctive user profiles:
186+
187+
```typst
188+
#let ceo = oc.user(
189+
name: [Sarah Chen],
190+
badge: qqnt.badge(text-color: purple, bg-color: purple.transparentize(80%))[#text(stroke: 0.05em + purple)[CEO]],
191+
avatar: rect(
192+
fill: blue.darken(20%),
193+
radius: 4pt,
194+
inset: 6pt,
195+
text(white, weight: "bold")[SC]
196+
)
197+
)
198+
199+
#qqnt.chat(
200+
oc.message(left, ceo)[
201+
Hi team! Ready for the quarterly review?
202+
],
203+
)
204+
```
205+
206+
![typst-frame](assets/frame_5.svg)
207+
208+
### Rich Content Support
209+
210+
Include tables, code blocks, and visual elements:
211+
212+
```typst
213+
#let analyst = wechat.user(
214+
name: [Data Analyst],
215+
avatar: circle(fill: green.darken(10%), text(white)[📊])
216+
)
217+
218+
#wechat.chat(
219+
oc.message(left, analyst)[
220+
Here's our performance analysis:
221+
222+
#table(
223+
columns: (auto, auto, auto),
224+
[*Metric*], [*Before*], [*After*],
225+
[Response Time], [250ms], [120ms],
226+
[Throughput], [1000 RPS], [2500 RPS],
227+
)
228+
229+
The optimization yielded 58% improvement! 📊
230+
]
231+
)
232+
```
233+
234+
![typst-frame](assets/frame_6.svg)
235+
236+
### Theme Customization
237+
238+
Modify existing themes or create your own:
239+
240+
```typst
241+
#let custom_theme = (
242+
inherit: "light",
243+
background: rgb("#F5F5F5"),
244+
bubble-left: rgb("#E3F2FD"),
245+
bubble-right: rgb("#C8E6C9"),
246+
text-primary: rgb("#212121"),
247+
text-secondary: rgb("#757575"),
248+
)
249+
250+
#wechat.chat(theme: custom_theme, /* same as above */)
251+
```
252+
253+
### Layout Control
254+
255+
Fine-tune spacing and dimensions:
256+
257+
```typst
258+
#wechat.chat(
259+
layout: (
260+
content-width: 350pt,
261+
message-spacing: 0.8em,
262+
avatar-size: 32pt,
263+
bubble-padding: 12pt,
264+
),
265+
/* same as above */
266+
)
267+
```
268+
269+
## Examples Gallery
270+
271+
Explore our comprehensive example collection: [https://quadnucyard.github.io/ourchat-typ](https://quadnucyard.github.io/ourchat-typ)
272+
273+
The source codes for these example are located at `./examples`.
274+
275+
## Architecture & Design
276+
277+
### API Design Philosophy
278+
279+
Ourchat follows a unified component architecture where `oc` provides the core building blocks:
280+
281+
- `oc.message()`, `oc.user()`, `oc.time()` - Universal components that work across all themes
282+
- Built-in themes (`wechat`, `discord`, `qqnt`) import all common components but may override them for platform-specific features
283+
- For example, `qqnt.user()` extends the base user component with `badge` support for role badges
284+
- Uses `chat` as the rendering function of messages, which is defined in individual themes. Styling is decided here.
285+
286+
```typst
287+
// Universal approach - works with any theme
288+
#let user = oc.user(name: [Alice])
289+
290+
// Theme-specific approach - leverages extended features
291+
#let qqnt_user = qqnt.user(
292+
name: [Alice],
293+
badge: qqnt.badge()[Admin] // QQNT specific feature
294+
)
295+
```
296+
297+
### Theme Customization Scope
298+
299+
Built-in themes provide a solid foundation but don’t cover every possible customization. You’re encouraged to:
300+
301+
- Extend existing themes for minor modifications using `theme` and `layout` parameters.
302+
- 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
303+
304+
## API Reference
305+
306+
Here only lists exported functions and variables. Please refer to the documentation comments of each function for details
307+
308+
### Common Components
309+
310+
- `oc.user(name, avatar, badge)`: Create universal user profiles
311+
- `oc.message(side, user, body, time, merge)`: Add chat messages (`left` or `right`)
312+
- `oc.time(body)`: Insert timestamp dividers
313+
- `oc.with-side-user(side, user, ..messages)`: Convenience for multiple messages from same user
314+
- `oc.free-message(body, time, merge)`: Create message without specific user or side
315+
- `oc.plain(side, user, body)`: Create plain item without padding
316+
317+
Note: These are just helper functions for data wrapping. You can directly create data structures if you like.
318+
319+
### Theme Collections
320+
321+
#### `oc.themes.wechat`
322+
323+
WeChat layout and color schemes (`light`, `dark`)
324+
325+
- `wechat.chat(theme, layout, width, validate, ..messages)`: WeChat-style interface
326+
- `wechat.default-user`: Pre-configured user with WeChat avatar
327+
328+
#### `oc.themes.qqnt`
329+
330+
QQNT layout and color schemes (`light`, `dark`)
331+
332+
- `qqnt.chat(theme, layout, width, validate, ..messages)`: QQNT-style interface
333+
- `qqnt.user` (uses `oc.user` with badge support): QQNT user with role support
334+
- `qqnt.badge(body, text-color, bg-color)`: Create role badges
335+
336+
#### `oc.themes.discord`
337+
338+
Discord layout and color schemes
339+
340+
- `discord.newbie-user`: Pre-configured user with newbie badge
341+
- `discord.mention(body)`: Create Discord-style mention element
342+
- `discord.chat(theme, layout, width, validate, auto-mention, ..messages)`: Discord-style interface
343+
344+
### Utilities (`oc.utils`)
345+
346+
- `validate-theme(theme, reference, field-type)`: Validate theme dictionary fields
347+
- `validate-layout(layout, reference)`: Validate layout dictionary fields
348+
- `resolve-theme(themes, theme, default, validate)`: Resolve theme with inheritance support
349+
- `resolve-layout(layout, default-layout, validate)`: Merge and validate layout settings
350+
- `stretch-cover(item)`: Scale content to cover its container
351+
- `auto-mention-rule(auto-mention, styler)`: Create show rule for automatic mention styling
352+
353+
## Contributing
354+
355+
We welcome contributions! Please check our GitHub repository for:
356+
357+
- Bug reports and feature requests
358+
- Code contributions and improvements
359+
- Documentation updates
360+
- New theme proposals and existing theme improvements
361+
362+
## License
363+
364+
MIT License - see [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)