社区集市
在思源中, 开发者希望把自己开发的作品上架到集市 (bazaar),除了核心的代码文件之外, 还必须提交如下内容
- 清单文件 (不同类型资源的清单文件文件名不同)
icon.json
plugin.json
template.json
theme.json
widget.json
- 说明文件
README.md
- 图标图片
icon.png
- 预览图片
preview.png
清单文件
bazaar 读取特定 json 文件来获悉社区资源的具体配置。
- 图标资源:
icon.json
- 插件资源:
plugin.json
- 模板资源:
template.json
- 主题资源:
theme.json
- 挂件资源:
widget.json
基本字段
不同类型的社区资源有不同的清单文件,但是他们有一些共同的字段。
{
"$schema": "https://docs.siyuan-note.club/schemas/manifest/base.schema.json",
"name": "example-name",
"author": "Author Name Example",
"url": "https://github.com/example-username/example-repository-name",
"version": "0.1.0",
"minAppVersion": "2.8.8",
"keywords": [
"example",
"示例"
],
"displayName": {
"default": "Example Name",
"zh_CHT": "示例名稱",
"zh_CN": "示例名称"
},
"description": {
"default": "Descriptive information about this example",
"zh_CHT": "關於本示例的描述信息",
"zh_CN": "关于本示例的描述信息"
},
"readme": {
"default": "README.md",
"en_US": "README_en_US.md",
"zh_CN": "README_zh_CN.md"
},
"funding": {
"openCollective": "siyuan",
"patreon": "",
"github": "88250",
"custom": [
"https://ld246.com/sponsor"
]
}
}
/**
* Basic definition of community resource manifest file
*/
export interface IBase {
/**
* The name of the author
*/
readonly author: string;
/**
* The description of the resource
*/
readonly description?: ILocalizedText;
/**
* The display name of the resource
*/
readonly displayName?: ILocalizedText;
/**
* The funding of the resource
*/
readonly funding?: IFunding;
/**
* The keywords of the resource used for search
*/
readonly keywords?: string[];
/**
* The minimum version of SiYuan that the resource is compatible with
*/
readonly minAppVersion?: string;
/**
* The name of the resource
*/
readonly name: string;
/**
* The readme file name of the resource
*/
readonly readme?: ILocalizedText;
/**
* The GitHub repository URL of the resource
*/
readonly url: string;
/**
* The version of the resource
*/
readonly version: string;
[property: string]: any;
}
/**
* The description of the resource
*
* Localize text fields
*
* The display name of the resource
*
* The readme file name of the resource
*/
export interface ILocalizedText {
/**
* The default text
*/
readonly default: string;
/**
* The English text
*/
readonly en_US?: string;
/**
* The Traditional Chinese text
*/
readonly zh_CHT?: string;
/**
* The Simplified Chinese text
*/
readonly zh_CN?: string;
[property: string]: any;
}
/**
* The funding of the resource
*/
export interface IFunding {
/**
* The custom funding URLs
*/
readonly custom?: string[];
/**
* The GitHub sponsors username, such as https://github.com/sponsors/<username>
*/
readonly github?: string;
/**
* The Open Collective username, such as https://opencollective.com/<username>
*/
readonly openCollective?: string;
/**
* The Patreon username, such as https://www.patreon.com/<username>
*/
readonly patreon?: string;
}
/**
* 基础属性
*/
{
$schema: 'https://json-schema.org/draft/2020-12/schema',
$id: 'https://github.com/siyuan-community/siyuan-sdk/raw/main/schemas/manifest/base.schema.json5',
$comment: 'v1.0.1',
$ref: '#/$defs/root',
$defs: {
root: {
// 社区资源清单文件基本定义
title: 'IBase',
description: 'Basic definition of community resource manifest file',
$ref: '#/$defs/base',
},
base: {
type: 'object',
additionalProperties: true,
required: [
'author',
'name',
'url',
'version',
],
properties: {
author: {
// 作者名
type: 'string',
description: 'The name of the author',
},
description: {
// 资源描述
description: 'The description of the resource',
$ref: '#/$defs/_localized_text_',
},
displayName: {
// 显示名称
description: 'The display name of the resource',
$ref: '#/$defs/_localized_text_',
},
funding: {
// 资助途径
type: 'object',
title: 'IFunding',
description: 'The funding of the resource',
additionalProperties: false,
required: [],
properties: {
custom: {
// 自定义捐助途径 URL
type: 'array',
description: 'The custom funding URLs',
items: {
type: 'string',
description: 'The custom funding URL',
format: 'uri',
examples: [
'https://afdian.net/a/<username>', // 爱发电
'https://ko-fi.com/<username>', // Ko-fi
'https://tidelift.com/subscription/<platform-name>/<package-name>', // Tidelift
'https://funding.communitybridge.org/projects/<project-name>', // Community Bridge
'https://liberapay.com/<username>', // Liberapay
'https://issuehunt.io/r/<username>', // IssueHunt
'https://crowdfunding.lfx.linuxfoundation.org/projects/<project-name>', // LFX Crowdfunding
],
},
},
github: {
// GitHub sponsors 用户名
type: 'string',
description: 'The GitHub sponsors username, such as https://github.com/sponsors/<username>',
examples: [
'88250',
],
},
openCollective: {
// Open Collective 用户名
type: 'string',
description: 'The Open Collective username, such as https://opencollective.com/<username>',
examples: [
'siyuan',
],
},
patreon: {
// Patreon 用户名
type: 'string',
description: 'The Patreon username, such as https://www.patreon.com/<username>',
},
},
},
keywords: {
// 用于搜索的关键词
type: 'array',
description: 'The keywords of the resource used for search',
items: {
type: 'string',
description: 'The keyword used for search',
},
},
minAppVersion: {
// 兼容的最低思源版本
type: 'string',
description: 'The minimum version of SiYuan that the resource is compatible with',
pattern: '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$',
},
name: {
// 资源名称
type: 'string',
description: 'The name of the resource',
pattern: '^[^\\\\/:*?"<>|. ][^\\\\/:*?"<>|]*[^\\\\/:*?"<>|. ]$',
},
readme: {
// 资源说明文档名称
description: 'The readme file name of the resource',
$ref: '#/$defs/_localized_text_',
},
url: {
// 资源仓库地址
type: 'string',
description: 'The GitHub repository URL of the resource',
format: 'uri',
examples: [
'https://github.com/siyuan-note/icon-sample',
'https://github.com/siyuan-note/plugin-sample',
'https://github.com/siyuan-note/template-sample',
'https://github.com/siyuan-note/theme-sample',
'https://github.com/siyuan-note/widget-sample',
],
},
version: {
// 资源版本号
type: 'string',
description: 'The version of the resource',
// REF: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
pattern: '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$',
},
},
},
_localized_text_: {
// 本地化文本
type: 'object',
title: 'ILocalizedText',
description: 'Localize text fields',
additionalProperties: true,
required: [
'default',
],
properties: {
default: {
// 默认文本
type: 'string',
description: 'The default text',
},
en_US: {
// 英文文本
type: 'string',
description: 'The English text',
},
zh_CHT: {
// 繁体中文文本
type: 'string',
description: 'The Traditional Chinese text',
},
zh_CN: {
// 简体中文文本
type: 'string',
description: 'The Simplified Chinese text',
},
},
},
},
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/siyuan-community/siyuan-sdk/raw/main/schemas/manifest/base.schema.json",
"$comment": "v1.0.1",
"$ref": "#/$defs/root",
"$defs": {
"root": {
"title": "IBase",
"description": "Basic definition of community resource manifest file",
"$ref": "#/$defs/base"
},
"base": {
"type": "object",
"additionalProperties": true,
"required": [
"author",
"name",
"url",
"version"
],
"properties": {
"author": {
"type": "string",
"description": "The name of the author"
},
"description": {
"description": "The description of the resource",
"$ref": "#/$defs/_localized_text_"
},
"displayName": {
"description": "The display name of the resource",
"$ref": "#/$defs/_localized_text_"
},
"funding": {
"type": "object",
"title": "IFunding",
"description": "The funding of the resource",
"additionalProperties": false,
"required": [],
"properties": {
"custom": {
"type": "array",
"description": "The custom funding URLs",
"items": {
"type": "string",
"description": "The custom funding URL",
"format": "uri",
"examples": [
"https://afdian.net/a/<username>",
"https://ko-fi.com/<username>",
"https://tidelift.com/subscription/<platform-name>/<package-name>",
"https://funding.communitybridge.org/projects/<project-name>",
"https://liberapay.com/<username>",
"https://issuehunt.io/r/<username>",
"https://crowdfunding.lfx.linuxfoundation.org/projects/<project-name>"
]
}
},
"github": {
"type": "string",
"description": "The GitHub sponsors username, such as https://github.com/sponsors/<username>",
"examples": [
"88250"
]
},
"openCollective": {
"type": "string",
"description": "The Open Collective username, such as https://opencollective.com/<username>",
"examples": [
"siyuan"
]
},
"patreon": {
"type": "string",
"description": "The Patreon username, such as https://www.patreon.com/<username>"
}
}
},
"keywords": {
"type": "array",
"description": "The keywords of the resource used for search",
"items": {
"type": "string",
"description": "The keyword used for search"
}
},
"minAppVersion": {
"type": "string",
"description": "The minimum version of SiYuan that the resource is compatible with",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
},
"name": {
"type": "string",
"description": "The name of the resource",
"pattern": "^[^\\\\/:*?\"<>|. ][^\\\\/:*?\"<>|]*[^\\\\/:*?\"<>|. ]$"
},
"readme": {
"description": "The readme file name of the resource",
"$ref": "#/$defs/_localized_text_"
},
"url": {
"type": "string",
"description": "The GitHub repository URL of the resource",
"format": "uri",
"examples": [
"https://github.com/siyuan-note/icon-sample",
"https://github.com/siyuan-note/plugin-sample",
"https://github.com/siyuan-note/template-sample",
"https://github.com/siyuan-note/theme-sample",
"https://github.com/siyuan-note/widget-sample"
]
},
"version": {
"type": "string",
"description": "The version of the resource",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
}
}
},
"_localized_text_": {
"type": "object",
"title": "ILocalizedText",
"description": "Localize text fields",
"additionalProperties": true,
"required": [
"default"
],
"properties": {
"default": {
"type": "string",
"description": "The default text"
},
"en_US": {
"type": "string",
"description": "The English text"
},
"zh_CHT": {
"type": "string",
"description": "The Traditional Chinese text"
},
"zh_CN": {
"type": "string",
"description": "The Simplified Chinese text"
}
}
}
}
}
- 基础字段
name
: 资源名称,必须全局唯一(集市中不能有同名图标)author
: 资源作者名url
: 资源 GitHub 仓库 URLversion
: 资源版本号,建议遵循 semver 规范minAppVersion
: 资源兼容的最低思源笔记版本号keywords
: 用于在集市中搜索的关键词列表displayName
: 资源显示名称,主要用于集市列表中显示,支持多语言default
: 默认语言,必须存在zh_CN
、en_US
等其他语言: 可选,建议至少提供中文和英文
description
: 资源描述,主要用于资源集市列表中显示,支持多语言default
: 默认语言,必须存在zh_CN
、en_US
等其他语言: 可选,建议至少提供中文和英文
readme
: 自述文件名,主要用于资源集市详情页中显示,支持多语言default
: 默认语言,必须存在zh_CN
、en_US
等其他语言: 可选,建议至少提供中文和英文
funding
: 项目赞助渠道openCollective
: Open Collective 名称patreon
: Patreon 名称github
: GitHub 用户名custom
: 自定义赞助链接列表
附加字段
以下是各清单文件详细定义说明,不同类型的社区资源的清单文件可能存在一些额外的字段。
- 图标: icon.json
- 插件: plugin.json
backends
: 插件支持的后端环境列表frontends
: 插件支持的前端环境列表
- 模板: template.json
- 主题: theme.json
modes
: 主题支持的模式
- 挂件: widget.json
说明文件
README 说明文件会被解析为集市中项目的介绍文档。思源支持 i18n 国际化,所以一个项目中可能不止有一个 README 文件,需要配置 json
文件中 readme
字段。
"readme": {
"default": "README.md",
"zh_CN": "README_zh_CN.md"
},
README 文件中的图片
思源在解析 README 的时候遇到相对链接的图片,不会在本地查找,而是会通过网络访问远程仓库中的图片资源。
由于众所周知的原因, 中国大陆内访问 github 仓库会出现波动情况。所以思源会根据 json 文件 url
配置把本地图片资源解析成 cdn 链接。xx.png
会被处理为 https://cdn.jsdelivr.net/gh/<author>/<repo>/xx.png
所以大部分情况下,我们只需要在 README 里使用相对路径引用图片即可。
不过 jsdeliver cdn 本身也存在波动,你也可以选择在 zh_CN 的文档中使用自建图床的链接地址,来提供更加文档的访问。
需要注意的是,思源的集市里的介绍文档是访问 cdn 托管的网络资源。但是「已下载」当中的介绍文档则是访问本地下载下来的 README.md 文件,所以如果你不是很在乎在集市里的显示的话,还有一种方案, 是把所有的 asset 图片打包到发布包当中,然后指定思源内部网络访问的 uri,这样用户下载了集市中的产品后可以在本地看到完整的介绍文档。
例如以下的 url:
/appearance/themes/<ThemeX>/preview-light.png`
会访问思源工作空间目录下, 主题 ThemeX
的安装路径 /appearance/themes/<ThemeX>/
下属的图片 preview-light.png
。
图标图片
图标图片用于在社区资源集市列表与详情页中展示你的项目。
图标图片需要满足如下要求:
- 文件名称:
icon.png
- 图片格式:
image/png
- 图片尺寸: 160×160 (推荐)
预览图片
预览图片用于在社区资源集市详情页面中展示你的项目。
预览图片需要满足如下定要求:
- 文件名称:
preview.png
- 图片格式:
image/png
- 图片尺寸: 1024×768 (推荐)
Tips: 一次性制作符合要求尺寸的图片可能比较麻烦,你可以试着分别制作两个 1:1 和 4:3 的图片,然后使用图片编辑软件 (比如 windows 自带的画图) 缩放到指定尺寸。