feat: improve onboarding and copy ux
This commit is contained in:
parent
026588bba3
commit
88dc7e02a4
@ -4,7 +4,7 @@ import os
|
||||
import shlex
|
||||
|
||||
_DEFAULT_ALLOWED_EXTENSIONS = (
|
||||
".txt,.md,.rst,.py,.js,.ts,.json,.yml,.yaml,.ini,.cfg,.conf,"
|
||||
".txt,.md,.rst,.py,.js,.ts,.json,.yml,.yaml,.ini,.cfg,.conf,.ipynb"
|
||||
".csv,.tsv,.log,.mdx,.env,.sh,.bat,.ps1,.sql,.html,.css,"
|
||||
".svg,.png,.jpg,.jpeg,.gif,.bmp,.webp,.ico,.pdf,.pptx,.docx,"
|
||||
".xlsx,.mp3,.wav,.flac,.mp4,.mov,.mkv,.avi,.webm,"
|
||||
|
||||
1
static/icons/flask-conical.svg
Normal file
1
static/icons/flask-conical.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="opacity:1;"><path fill="none" d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2M6.453 15h11.094M8.5 2h7"/></svg>
|
||||
|
After Width: | Height: | Size: 356 B |
1
static/icons/graduation-cap.svg
Normal file
1
static/icons/graduation-cap.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="opacity:1;"><path d="M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0zM22 10v6"/><path d="M6 12.5V16a6 3 0 0 0 12 0v-3.5"/></svg>
|
||||
|
After Width: | Height: | Size: 381 B |
@ -12,12 +12,18 @@
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
// 全局复制代码块函数
|
||||
function decodeHtmlEntities(text) {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.innerHTML = text || '';
|
||||
return textarea.value;
|
||||
}
|
||||
function copyCodeBlock(blockId) {
|
||||
const codeElement = document.querySelector(`[data-code-id="${blockId}"]`);
|
||||
if (!codeElement) return;
|
||||
const button = document.querySelector(`[data-code="${blockId}"]`);
|
||||
if (button && button.classList.contains('copied')) return;
|
||||
const codeContent = codeElement?.dataset?.originalCode || codeElement?.textContent || '';
|
||||
const raw = codeElement?.dataset?.originalCode || codeElement?.textContent || '';
|
||||
const codeContent = decodeHtmlEntities(raw);
|
||||
if (!button) {
|
||||
navigator.clipboard.writeText(codeContent).catch((err) => console.error('复制失败:', err));
|
||||
return;
|
||||
|
||||
195
static/src/components/personalization/ExperienceOnboarding.vue
Normal file
195
static/src/components/personalization/ExperienceOnboarding.vue
Normal file
@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<transition name="overlay-fade">
|
||||
<div v-if="open" class="exp-overlay">
|
||||
<div class="exp-card">
|
||||
<div class="exp-header">
|
||||
<div>
|
||||
<div class="title">第一次使用?选择适合您的模式</div>
|
||||
<div class="subtitle">速度、联网与工具范围各不相同,随时可在个人空间切换。</div>
|
||||
</div>
|
||||
<button class="confirm-btn" type="button" @click="confirmSelection">确认并开始</button>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div
|
||||
v-for="item in modes"
|
||||
:key="item.id"
|
||||
class="mode-card"
|
||||
:class="{ active: selected === item.id }"
|
||||
@click="selected = item.id"
|
||||
>
|
||||
<div class="badge">{{ item.badge }}</div>
|
||||
<div class="icon" v-html="item.icon" aria-hidden="true"></div>
|
||||
<h3>{{ item.title }}</h3>
|
||||
<p>{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
type Mode = 'fast' | 'thinking' | 'research' | 'expert';
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean;
|
||||
initial?: Mode;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'close'): void;
|
||||
(event: 'confirm', mode: Mode): void;
|
||||
}>();
|
||||
|
||||
const selected = ref<Mode>(props.initial || 'fast');
|
||||
|
||||
watch(
|
||||
() => props.initial,
|
||||
(val) => {
|
||||
if (val) selected.value = val;
|
||||
}
|
||||
);
|
||||
|
||||
const modes = [
|
||||
{
|
||||
id: 'fast',
|
||||
badge: '极速',
|
||||
title: '快速回答',
|
||||
desc: '快速回答您的问题,会上网搜索,不会写文件。',
|
||||
icon: `<svg viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2"><path d="M13 2 5 14h6l-2 8 10-12h-6z"/></svg>`
|
||||
},
|
||||
{
|
||||
id: 'thinking',
|
||||
badge: '思考',
|
||||
title: '思考后再答',
|
||||
desc: '经过思考后完成任务,会上网搜索,不会写文件,回复时间较长。',
|
||||
icon: `<svg viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2"><path d="M12 18V5"/><path d="M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4"/><path d="M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5"/><path d="M17.997 5.125a4 4 0 0 1 2.526 5.77"/><path d="M18 18a4 4 0 0 0 2-7.464"/><path d="M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517"/><path d="M6 18a4 4 0 0 1-2-7.464"/><path d="M6.003 5.125a4 4 0 0 0-2.526 5.77"/></svg>`
|
||||
},
|
||||
{
|
||||
id: 'research',
|
||||
badge: '研究',
|
||||
title: '多步骤研究',
|
||||
desc: '多步骤思考与 20+ 工具完成复杂任务,回复时间可能很长。',
|
||||
icon: `<svg viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2"><path d="M9 3v5l-4 9a2 2 0 0 0 1.8 3h10.4A2 2 0 0 0 19 17l-4-9V3"/><path d="M9 8h6"/></svg>`
|
||||
},
|
||||
{
|
||||
id: 'expert',
|
||||
badge: '专家',
|
||||
title: '全功能探索',
|
||||
desc: '自由探索所有配置选项,适合智能体专家与从业者。',
|
||||
icon: `<svg viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2"><path d="M3 9 12 5l9 4-9 4-9-4Z"/><path d="M6 10v5c0 .6.4 1.2 1 1.4l5 2.1 5-2.1c.6-.2 1-.8 1-1.4v-5"/><path d="M12 13v6"/></svg>`
|
||||
}
|
||||
] as const;
|
||||
|
||||
function confirmSelection() {
|
||||
emit('confirm', selected.value);
|
||||
emit('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.exp-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(33, 24, 14, 0.55);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
z-index: 1200;
|
||||
}
|
||||
.exp-card {
|
||||
width: min(1100px, 96vw);
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 18px;
|
||||
padding: 24px 28px;
|
||||
box-shadow: 0 20px 50px rgba(33, 24, 14, 0.25);
|
||||
border: 1px solid rgba(118, 103, 84, 0.25);
|
||||
}
|
||||
.exp-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 18px;
|
||||
gap: 12px;
|
||||
}
|
||||
.title {
|
||||
font-size: 22px;
|
||||
color: #3d3929;
|
||||
font-weight: 700;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #7f7766;
|
||||
}
|
||||
.confirm-btn {
|
||||
border: none;
|
||||
background: #da7756;
|
||||
color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 10px 18px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
.mode-card {
|
||||
border: 1px solid rgba(118, 103, 84, 0.25);
|
||||
border-radius: 14px;
|
||||
padding: 16px 14px;
|
||||
cursor: pointer;
|
||||
transition: .2s ease;
|
||||
box-shadow: 0 8px 18px rgba(61, 57, 41, 0.06);
|
||||
background: #fff;
|
||||
}
|
||||
.mode-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 16px 30px rgba(61, 57, 41, 0.12);
|
||||
}
|
||||
.mode-card.active {
|
||||
border-color: #da7756;
|
||||
box-shadow: 0 18px 36px rgba(218, 119, 86, 0.25);
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: #bd5d3a;
|
||||
background: rgba(218, 119, 86, 0.14);
|
||||
padding: 4px 10px;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 14px;
|
||||
background: rgba(218, 119, 86, 0.12);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
color: #bd5d3a;
|
||||
}
|
||||
.icon svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.mode-card h3 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 17px;
|
||||
color: #3d3929;
|
||||
}
|
||||
.mode-card p {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #7f7766;
|
||||
}
|
||||
</style>
|
||||
@ -636,6 +636,9 @@
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
line-height: 1.55;
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
scrollbar-gutter: stable both-edges;
|
||||
}
|
||||
|
||||
.text-output pre code {
|
||||
@ -777,6 +780,9 @@
|
||||
font-variant-ligatures: none;
|
||||
font-feature-settings: 'liga' 0, 'calt' 0;
|
||||
line-height: 1.55;
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
scrollbar-gutter: stable both-edges;
|
||||
}
|
||||
|
||||
.code-block-wrapper pre code {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user