Skip to content

Commit b4ee6be

Browse files
committed
WIP: artifacts & update docs
1 parent 670b6ca commit b4ee6be

23 files changed

+865
-110
lines changed

docs/self-host/advanced.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pnpm install
8686
# 构建为 PWA,输出在 dist/pwa
8787
pnpm build -m pwa
8888
89-
# 构建为普通 SPA,输出在 dist/spa
89+
# 或者构建为普通 SPA,输出在 dist/spa
9090
pnpm build
9191
```
9292

docs/self-host/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ services:
3737
3838
下面是不同部署方式的功能对照表:
3939
40-
| 功能 \ 部署方式 | 静态部署(仅前端) | Docker 快速部署 | 进阶部署(自行构建) | aiaw.app |
40+
| 功能 \ 部署方式 | [静态部署](advanced#静态部署)(仅前端) | Docker 快速部署 | 进阶部署(自行构建) | aiaw.app |
4141
| --- | --- | --- | --- | --- |
4242
| 基本功能 | √ | √ | √ | √ |
4343
| 插件市场/助手市场/Gradio插件 | √ | √ | √ | √ |

docs/usage/assistants.md

+39-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,47 @@
1010

1111
## 分享助手
1212

13-
通过助手设置页面底部的「导出」按钮,可以将助手导出到剪贴板或是导出为文件。其他人则可以通过插件市场右上角加号,通过文件或者剪贴板导入助手。
13+
通过助手设置页面底部的「导出」按钮,可以将助手导出到剪贴板或是导出为文件。其他人则可以点击插件市场右上角加号,通过文件或者剪贴板导入助手。
1414

1515
你也可以将助手发布到助手市场,使得其他用户可以直接在市场中看到并添加。发布方法为:
1616

1717
- 补全助手的描述、作者等信息,然后导出
1818
- 将导出的 JSON 添加到源码的 `/public/assistants.json`,并提交 PR
19+
20+
需要注意的是,如果助手的头像类型为上传的图片,则在分享/发布前还需要修改 `avatar` 属性,因为上传的图片属于本地/个人数据,其他用户无法访问。
21+
22+
比如,若导出的 JSON 中,`avatar` 属性类似于:
23+
24+
```json
25+
{
26+
"type": "image", // 说明是上传的图片
27+
"imageId": "1ih5i1u6i87lr10kab"
28+
}
29+
```
30+
31+
则需要替换为图片链接,或是其他类型的头像:
32+
33+
::: code-group
34+
```json [示例:图片链接]
35+
{
36+
"type": "url",
37+
"url": "https://url.to.my/image.avif"
38+
}
39+
```
40+
```json [示例:图标]
41+
{
42+
"type": "icon",
43+
"icon": "sym_o_palette",
44+
"hue": 80
45+
}
46+
```
47+
```json [示例:文字]
48+
{
49+
"type": "text",
50+
"text": "🍉"
51+
}
52+
```
53+
:::
54+
对于 `icon` 类型的头像,可在 [Material Symbols](https://fonts.google.com/icons) 选取图标,将图标名称写为下划线格式,并添加 `sym_o_` 前缀。如名称为 `Photo Camera` 的图标,`icon` 属性值为 `sym_o_photo_camera`
55+
56+
可添加 `hue` 属性显示头像背景色;可在[设置页面](https://aiaw.app/settings#ui)的主题色对话框选取颜色,得到 hue 值;不填则没有背景色。

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
"dexie": "^4.0.10",
4141
"dexie-cloud-addon": "^4.0.8",
4242
"expr-eval": "^2.0.2",
43-
"highlight.js": "^11.10.0",
4443
"json-schema": "^0.4.0",
4544
"liquidjs": "^10.16.7",
4645
"md-editor-v3": "^5.0.2",

pnpm-lock.yaml

-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ArtifactsList.vue

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<template>
2+
<q-list>
3+
<div p="x-4 y-2">
4+
<q-input
5+
dense
6+
outlined
7+
v-model="filter"
8+
clearable
9+
placeholder="搜索 Artifacts..."
10+
/>
11+
</div>
12+
<q-item
13+
v-for="artifact in filteredArtifacts"
14+
:key="artifact.id"
15+
clickable
16+
@click="openArtifact(artifact)"
17+
:class="{ 'route-active': artifact.open }"
18+
item-rd
19+
min-h="32px"
20+
py-1
21+
>
22+
<q-item-section
23+
avatar
24+
min-w-0
25+
>
26+
<q-icon
27+
size="16px"
28+
name="sym_o_code"
29+
/>
30+
</q-item-section>
31+
<q-item-section>
32+
{{ artifact.name }}
33+
</q-item-section>
34+
<q-item-section side>
35+
<q-btn
36+
v-if="artifact.open"
37+
flat
38+
dense
39+
round
40+
icon="sym_o_close"
41+
title="关闭"
42+
size="sm"
43+
@click.prevent.stop="closeArtifact(artifact)"
44+
/>
45+
</q-item-section>
46+
<q-menu
47+
context-menu
48+
>
49+
<q-list style="min-width: 100px">
50+
<menu-item
51+
icon="sym_o_edit"
52+
label="重命名"
53+
@click="renameItem(artifact)"
54+
/>
55+
<menu-item
56+
icon="sym_o_move_item"
57+
label="移动至"
58+
@click="moveItem(artifact)"
59+
/>
60+
<menu-item
61+
icon="sym_o_delete"
62+
label="删除"
63+
@click="deleteItem(artifact)"
64+
hover:text-err
65+
/>
66+
</q-list>
67+
</q-menu>
68+
</q-item>
69+
</q-list>
70+
</template>
71+
72+
<script setup lang="ts">
73+
import { useQuasar } from 'quasar'
74+
import { db } from 'src/utils/db'
75+
import { caselessIncludes } from 'src/utils/functions'
76+
import { Artifact } from 'src/utils/types'
77+
import { dialogOptions } from 'src/utils/values'
78+
import { computed, inject, ref, Ref } from 'vue'
79+
import SelectWorkspaceDialog from './SelectWorkspaceDialog.vue'
80+
import MenuItem from './MenuItem.vue'
81+
import { useCloseArtifact } from 'src/composables/close-artifact'
82+
import { useRouter } from 'vue-router'
83+
84+
const artifacts: Ref<Artifact[]> = inject('artifacts')
85+
const filter = ref(null)
86+
const filteredArtifacts = computed(() => {
87+
return artifacts.value.filter(d => !filter.value || caselessIncludes(d.name, filter.value)).reverse()
88+
})
89+
90+
const $q = useQuasar()
91+
92+
function renameItem({ id, name }) {
93+
$q.dialog({
94+
title: '重命名',
95+
prompt: {
96+
model: name,
97+
type: 'text',
98+
label: '名称',
99+
isValid: v => v.trim() && v !== name
100+
},
101+
cancel: true,
102+
...dialogOptions
103+
}).onOk(newName => {
104+
db.canvases.update(id, { name: newName.trim() })
105+
})
106+
}
107+
function moveItem({ id }) {
108+
$q.dialog({
109+
component: SelectWorkspaceDialog,
110+
componentProps: {
111+
accept: 'workspace'
112+
}
113+
}).onOk(workspaceId => {
114+
db.canvases.update(id, { workspaceId })
115+
})
116+
}
117+
function deleteItem({ id, name }) {
118+
$q.dialog({
119+
title: '删除 Artifact',
120+
message: `确定要删除 Artifact「${name}」吗?`,
121+
cancel: true,
122+
ok: {
123+
label: '删除',
124+
color: 'err',
125+
flat: true
126+
},
127+
...dialogOptions
128+
}).onOk(() => {
129+
db.canvases.delete(id)
130+
})
131+
}
132+
const router = useRouter()
133+
function openArtifact({ id, open }) {
134+
!open && db.canvases.update(id, { open: true })
135+
router.push({ query: { artifactId: id } })
136+
}
137+
const { closeArtifact } = useCloseArtifact()
138+
</script>

src/components/AssistantList.vue

+6-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<menu-item
4242
icon="sym_o_delete"
4343
label="删除"
44-
@click="deleteItem(assistant.id)"
44+
@click="deleteItem(assistant)"
4545
hover:text-err
4646
/>
4747
</q-list>
@@ -75,6 +75,7 @@ import AAvatar from './AAvatar.vue'
7575
import SelectWorkspaceDialog from './SelectWorkspaceDialog.vue'
7676
import { useCreateDialog } from 'src/composables/create-dialog'
7777
import MenuItem from './MenuItem.vue'
78+
import { dialogOptions } from 'src/utils/values'
7879
7980
const props = defineProps<{
8081
workspaceId: string
@@ -107,16 +108,17 @@ function moveToWorkspace(id) {
107108
move(id, workspaceId)
108109
})
109110
}
110-
function deleteItem(id) {
111+
function deleteItem({ id, name }) {
111112
$q.dialog({
112113
title: '删除助手',
113-
message: '确定要删除助手吗?',
114+
message: `确定要删除助手「${name}」吗?`,
114115
cancel: true,
115116
ok: {
116117
label: '删除',
117118
color: 'err',
118119
flat: true
119-
}
120+
},
121+
...dialogOptions
120122
}).onOk(() => {
121123
assistantsStore.delete(id)
122124
})

src/components/CodeJar.vue

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<template>
2+
<div
3+
ref="el"
4+
class="code-jar hljs"
5+
/>
6+
</template>
7+
<script setup lang="ts">
8+
import { CodeJar } from 'codejar'
9+
import { withLineNumbers } from 'codejar-linenumbers'
10+
import 'codejar-linenumbers/js/codejar-linenumbers.css'
11+
12+
import { computed, onMounted, ref, watchEffect } from 'vue'
13+
14+
const props = defineProps<{
15+
language?: string
16+
}>()
17+
18+
const model = defineModel<string>()
19+
20+
const el = ref(null)
21+
22+
const tab = computed(() => /\n {2}\w/g.test(model.value) ? ' ' : ' ')
23+
24+
onMounted(() => {
25+
const jar = CodeJar(
26+
el.value,
27+
withLineNumbers(editor => {
28+
if (!window.hljs) return
29+
const code = editor.textContent
30+
const html = props.language && window.hljs.getLanguage(props.language)
31+
? window.hljs.highlight(code, { language: props.language, ignoreIllegals: true }).value
32+
: window.hljs.highlightAuto(code).value
33+
editor.innerHTML = html
34+
})
35+
)
36+
jar.onUpdate(code => {
37+
model.value = code
38+
})
39+
watchEffect(() => {
40+
if (model.value !== el.value?.textContent) jar.updateCode(model.value)
41+
})
42+
watchEffect(() => {
43+
jar.updateOptions({
44+
tab: tab.value
45+
})
46+
})
47+
})
48+
</script>
49+
50+
<style lang="scss">
51+
.codejar-wrap {
52+
height: 100%;
53+
border-radius: 0 6px 6px 6px;
54+
overflow: hidden;
55+
}
56+
.code-jar {
57+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
58+
color: var(--md-theme-code-block-color);
59+
background-color: var(--md-theme-code-block-bg-color);
60+
height: 100%;
61+
}
62+
63+
.codejar-linenumbers {
64+
background-color: var(--md-theme-code-block-bg-color) !important;
65+
text-align: right;
66+
padding-right: 8px;
67+
68+
.codejar-linenumber {
69+
color: #999 !important;
70+
}
71+
}
72+
.codejar-wrap {
73+
--md-theme-code-block-color: #747384;
74+
--md-theme-code-block-bg-color: #f8f8f8;
75+
}
76+
body.dark .codejar-wrap {
77+
--md-theme-code-block-color: #999;
78+
--md-theme-code-block-bg-color: #1a1a1a;
79+
}
80+
</style>

0 commit comments

Comments
 (0)