| Name | Description |
|---|---|
| ext/ | 3rd party codes |
| img/ | Static images |
| doc/ | Documents |
| src/css/ | CSS styling files (moved from css/ for Tailwind CSS v4 migration) |
| app/ | Main javascript source code folder |
| sw/ | Service worker source code folder |
| html/ | Entry files |
| build.js | Node.js build script to compile code and prepare package |
| package.json | npm package configuration with build scripts |
This project uses Node.js and npm for building. The build process replaces the previous bash-based package.sh script.
- Node.js >= 18.0.0
- npm
# Install dependencies
npm install
# Build the project
npm run build
# Clean build artifacts
npm run clean
# Package (same as build)
npm run packageThe build script (build.js) performs the following steps:
- Generate entry points: Creates ES module entry points (
src/index.js,src/sw.js) fromapp/file_list.txtandsw/file_list.txt - Bundle JavaScript: Uses
esbuildto bundle all modules into a single file with tree-shaking and minification - Process CSS: Uses
esbuildto minify CSS fromsrc/css/hst.css - Package outputs: Creates web2 and web3 deployment packages in the
dist/directory - Create tarball: Generates
dist/web3.tar.gzfor web3 deployment
The project uses Tailwind CSS v4 for styling:
- CSS Location: CSS files are located in
src/css/ - Tailwind Entry Point:
src/css/tailwind.cssis the main CSS entry point that:- Imports Tailwind CSS v4 theme and utilities (preflight/base styles are disabled to preserve existing custom styles)
- Uses
@import "tailwindcss/theme.css"and@import "tailwindcss/utilities.css"(excludingpreflight.css) - Includes existing custom styles from
hst.css - Supports custom theme configuration via
@themedirective - Note: Preflight is disabled to avoid conflicts with existing custom CSS styles
- Build Process: The build automatically:
- Processes
src/css/tailwind.csswith PostCSS and Tailwind CSS plugin - Minifies the processed CSS using esbuild
- Outputs the final CSS to
dist/web2/static/css/anddist/web3/static/
- Processes
- Migration Path: To gradually migrate to Tailwind utility classes:
- Replace custom classes in
hst.csswith Tailwind utility classes prefixed withtw-(e.g., usetw-flexinstead offlex,tw-text-centerinstead oftext-center) - Use
@themeintailwind.cssfor custom theme values - Remove unused custom classes from
hst.cssas you migrate
- Replace custom classes in
- Prefix: All Tailwind utility classes use the
tw-prefix to avoid conflicts with existing custom CSS classes
The project now uses ES modules instead of file concatenation:
- Entry points:
src/index.jsandsrc/sw.jsare auto-generated from file lists - Bundling:
esbuildbundles all modules with proper dependency resolution - Source files: Original files in
app/remain unchanged (still use IIFE pattern for now) - Build output: Same structure as before for compatibility
- The old
package.shbash script has been replaced withbuild.js(Node.js) - The old
mergejsbash script has been replaced with module-based bundling usingesbuild - Build dependencies (
esbuild,uglifycss) are managed via npm - Build output structure remains the same for compatibility
- Entry point files in
src/are auto-generated and should not be edited manually
Root file
Root file holds everything about a user's public information
{
"version": "1.0",
"profile": {
"nickname": "",
"icon_cid": "",
"brief_introduction": ""
},
"posts": "<cid of post list file>",
"idols": "<cid of idol list file>",
"marks": "<cid of mark map file>"
}
Fields:
version: For software backward compatiblity.profile: Basic user profile like name, brief introduction, icon, banner image etc.posts: Cid of file containing user's posts.idols: Cid of file containing user ids followed by current user.marks: Cid of file containing user's interations with other users.
Index files
Index files are used when referring to mulitple items. Special considerations are needed when the total number of items are expected to grow large over time. The purpose is to improve loading performance on client side.
A item is a relatively small json dict which may contain a file cid referring to the full content.
- Item order
- Reverse chronological.
- Short list
- Plain json array of items.
- Long list
- Bottom items shall automatically "fold" into sub index files.
- Sub index file shall hold limited items, the limit can be set from either a fixed time span(e.g. a month) or a fixed number(e.g. 1k~10k).
- Sub index file along with the timestamp of the lastest item inside becomes the item content in master list.
- Timestamp can help time based search.
{
"posts": [{
"timestamp" : 1746741377,
"type": "ARTICLE",
"cid": "QmRo5R6cCMcuekniEbV5QjRoqJnvAcDSxEVppisHPcndMR"
}, {
"timestamp" : 1746741367,
"type": "ARTICLE",
"cid": "QmR1hzM9jJYPH4Yp8P22d1VkLErPpCbdHjJBmRaASPYN4j"
}, {
"timestamp" : 1746741357,
"type": "_IDX",
"cid": "QmQNyYkptGh7v7KK8o4qZ8gEbo2LAEwWASuVzrrhUS8U6C"
}]
}
- Key for item
- A string
- Small map
- Plain json key-value pair
- Large map
- Keys are grouped by their two bytes.
- Each key group refers to the cid of sub map file.
- Fixed split threshold (e.g. 1k~10k).
- Sub map file can further split when items exceeds threshold, same rule except keys are grouped by next two bytes.
- Dynamically transforms into map of maps when number exceeds limit.
{
"marks": {
"00" : "<cid of sub map file>",
"ab" : "<cid of sub map file>",
...
"xy" : "<cid of sub map file>"
}
}
Posts
{
"posts": [{
"type": "ARTICLE",
"cid": "QmRo5R6cCMcuekniEbV5QjRoqJnvAcDSxEVppisHPcndMR"
}, {
"type": "ARTICLE",
"cid": "QmR1hzM9jJYPH4Yp8P22d1VkLErPpCbdHjJBmRaASPYN4j"
}]
}
The first cid above ("QmRo5R6cCMcuekniEbV5QjRoqJnvAcDSxEVppisHPcndMR") is linked to following article content:
{
"title": "「众议院议长凯文·麦卡锡被罢免」专稿",
"content": "10月1日,麦卡锡争取民主党支持以通过临时支出法案,被指违背了年初当选议长时与党内极端保守派谈妥的条件。10月4日 Matt Gaetz 等共和党议员提出罢免麦卡锡众议院议长的动议...",
"attachments": [{
"type": "application/pdf",
"cid": "QmVa3vtWrkCZkivJ6FNzeEYbtwh59Ffu5fyW1iLXbxthdA"
}]
}
Finally, the attachment cid ("QmVa3vtWrkCZkivJ6FNzeEYbtwh59Ffu5fyW1iLXbxthdA") is linked to a pdf file in IPFS.
The updating process is in reverse order:
- use
<dataserver>/api/file/uploadto upload necessary attachments and get their cids. The API is one file per call. - use
<dataserver>/api/json/uploadto upload articles that include necessary attachment file cids. The API is one json per call, returning json file cid. - use
<dataserver>/api/json/uploadto upload article index file that has articles id lists. The API return is the index file cid, note this cid should repalce old cid inside the file in next step. - use
<dataserver>/api/json/uploadto upload final entry json file and get its cid, note this cid should replace old cid as entry file. - use
<dataserver>/api/pin/updateto unpin old cids and pin new cids. - finally use
<nameserver>/api/pin/publishto publish the latest entry file cid
Idols
Ordered by the time when follow action happened reverse chronologically.
{
"idols": [{
"type": "USER",
"id": "<idol user id>",
"nickname": "<nickname from user's perspective>",
}, {
"type": "USER",
"id": "",
"nickname": "",
}]
}
type:USER: A normal user account
id: Id of the targetnickname: Nickname for personalized display
Marks
Key: marked item cid
{
"marks": {
"<item_cid>": {
"like": true,
"comments": [{
"type": "AUDIO",
"cid": "<audio file cid>"
}, {
"type": "REQUEST",
"cid": "<request file cid>"
}, {
"type": "ARTICLE",
"cid": "<article file cid>"
}]
}
}
}
Type:
AUDIO: Audio reply.ARTICLE: Same format as a normal article post.REQUEST: Preformatted request messages.
TODO: Redesign? e.g. Embed AUDIO into ARTICLE, move REQUEST to new category like "tasks".