frontend,chat: chat redesign, all message styles are now beautiful
This commit is contained in:
1 parent
73b789b586
commit
98fbed03cc
3 files changed
+107
-80
No files matched your search
@@ -16,6 +16,7 @@ marked.use({
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['open-thread', 'open-menu', 'toggle-log', 'cancel'])
|
||||
const props = defineProps({
|
||||
message: {
|
||||
type: Object,
|
||||
@@ -39,7 +40,12 @@ function chatEntryClass(msg) {
|
||||
} else if (msg.type == 'resource') {
|
||||
return ['resource', 'resource-' + (msg.subkind || 'generic')];
|
||||
} else if (msg.type == 'log') {
|
||||
return ['message', 'log'];
|
||||
return ['log'];
|
||||
} else if (msg.type == 'thread-header') {
|
||||
let cls = ['thread'];
|
||||
if (!msg.active) cls.push('thread-open')
|
||||
if (msg.isFork) cls.push('thread-fork');
|
||||
return cls;
|
||||
} else {
|
||||
return ['info'];
|
||||
}
|
||||
@@ -50,6 +56,14 @@ function resourceLabel(msg) {
|
||||
return msg.subkind || 'Resource';
|
||||
}
|
||||
|
||||
function handleClick(msg) {
|
||||
if (msg.type == 'thread-header' || msg.type == 'fork-header') {
|
||||
if (!msg.active && msg.threadId != null) {
|
||||
emit('open-thread', msg.threadId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const format = ref(null);
|
||||
const content = ref("");
|
||||
|
||||
@@ -94,7 +108,7 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="chatEntryClass(message)" @contextmenu.prevent="$emit('open-menu', message, logMeta)">
|
||||
<div :class="chatEntryClass(message)" @contextmenu.prevent="$emit('open-menu', message, logMeta)" @click="handleClick(message)">
|
||||
<template v-if="message.type == 'message' || message.type == null">
|
||||
<div v-if="message.sender != 'user'" class="sender">{{message.sender}}</div>
|
||||
|
||||
@@ -119,18 +133,13 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
</template>
|
||||
|
||||
<template v-if="message.type == 'thread-header'">
|
||||
<div class="thread-header"
|
||||
:class="{ 'thread-active': message.active }"
|
||||
@click="!message.active && message.threadId != null && $emit('open-thread', message.threadId)"
|
||||
>
|
||||
<div class="thread-title">
|
||||
{{ message.threadId == null ? 'New Thread' : `Thread ${message.threadId}` }}
|
||||
<span v-if="message.messageCount" class="thread-count">({{ message.messageCount }} messages)</span>
|
||||
</div>
|
||||
<div v-if="message.preview" class="thread-preview">
|
||||
<span class="thread-preview-sender">{{ message.preview.sender }}:</span>
|
||||
{{ message.preview.content }}
|
||||
</div>
|
||||
<div class="thread-title">
|
||||
{{ message.threadId == null ? 'New Thread' : `Thread ${message.threadId}` }}
|
||||
<span v-if="message.messageCount" class="thread-count">({{ message.messageCount }} messages)</span>
|
||||
</div>
|
||||
<div v-if="message.preview" class="content">
|
||||
<span class="sender">{{ message.preview.sender }}:</span>
|
||||
{{ message.preview.content }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -139,21 +148,36 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.info {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.message {
|
||||
width: fit-content;
|
||||
max-width: 50em;
|
||||
padding: 10px;
|
||||
max-width: 100%;
|
||||
padding: 1em;
|
||||
border-radius: 8px;
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
|
||||
.note {
|
||||
/* non-messages all share basics */
|
||||
.note, .log, .info, .thread, .resource {
|
||||
padding: 0.6em 1.4em;
|
||||
align-self: center;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* solid entries have horizontal margin */
|
||||
.note, .thread-fork.thread-open, .resource {
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* content by default fits in the entry */
|
||||
.content {
|
||||
white-space: preserve;
|
||||
width: fit-content;
|
||||
padding: 10px;
|
||||
word-wrap: anywhere;
|
||||
max-width: 50em;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: var(--color-background-soft);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
@@ -168,7 +192,6 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
|
||||
.message .content {
|
||||
white-space: preserve;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.message ul, .message ol {
|
||||
@@ -180,18 +203,21 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
margin-top: -5px; /* half message padding */
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.message.log .content {
|
||||
.log .content {
|
||||
font-family: monospace;
|
||||
font-size: 80%;
|
||||
max-width: 70em;
|
||||
}
|
||||
.message.log .log-sender {
|
||||
.log .log-sender {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 80%;
|
||||
}
|
||||
.message.log .log-toggle {
|
||||
.log .log-toggle {
|
||||
font-family: monospace;
|
||||
font-size: 80%;
|
||||
cursor: pointer;
|
||||
@@ -199,10 +225,7 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
}
|
||||
|
||||
.resource {
|
||||
align-self: center;
|
||||
width: fit-content;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px dashed var(--color-border);
|
||||
background-color: var(--color-background-soft);
|
||||
font-size: 85%;
|
||||
@@ -220,58 +243,54 @@ watch(() => [props.message.format, props.message.content], ([newFormat, newConte
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.thread-header {
|
||||
align-self: center;
|
||||
width: fit-content;
|
||||
max-width: 40em;
|
||||
padding: 5px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed var(--color-border);
|
||||
background-color: var(--color-background-soft);
|
||||
font-size: 80%;
|
||||
.thread {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.thread-header:hover {
|
||||
border-style: solid;
|
||||
.thread.thread-open {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thread-header .thread-title {
|
||||
.thread-open:hover {
|
||||
border-top: 1px solid var(--color-heading);
|
||||
}
|
||||
|
||||
.thread.thread-fork {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.thread.thread-fork.thread-open {
|
||||
width: fit-content;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thread-title {
|
||||
font-weight: bold;
|
||||
opacity: 70%;
|
||||
}
|
||||
|
||||
.thread-header .thread-count {
|
||||
.thread-count {
|
||||
font-weight: normal;
|
||||
opacity: 80%;
|
||||
}
|
||||
|
||||
.thread-header .thread-preview {
|
||||
.thread .content {
|
||||
justify-self: center;
|
||||
font-style: italic;
|
||||
opacity: 60%;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
opacity: 80%;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.thread-header .thread-preview-sender {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.thread-header.thread-active {
|
||||
border-style: solid;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.thread-header.thread-active .thread-title {
|
||||
.thread:hover .content {
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
.thread-header:hover {
|
||||
border-style: solid;
|
||||
.thread .sender {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user