From 1bf2f4ced20336ceda60e332b68bb613dd606786 Mon Sep 17 00:00:00 2001 From: marlon-erler Date: Thu, 11 Jul 2024 22:27:15 +0200 Subject: [PATCH] fix bugs, improve UI --- dist/index.css | 20 ++--- dist/index.js | 101 ++++++++++++++++++------ src/Model/chatModel.ts | 6 +- src/Tabs/messageTab.tsx | 1 - src/Views/Chat/threadView.tsx | 5 +- src/Views/Objects/allObjectsView.tsx | 18 ++--- src/Views/Objects/chatObjectView.tsx | 3 +- src/Views/Objects/noteObjectsView.tsx | 22 ++---- src/Views/Objects/objectDetailModal.tsx | 31 +++++--- src/Views/Objects/objectEntryView.tsx | 62 +++++++++++++++ src/icons.ts | 10 +++ src/styles.css | 20 ++--- 12 files changed, 209 insertions(+), 90 deletions(-) create mode 100644 src/Views/Objects/objectEntryView.tsx create mode 100644 src/icons.ts diff --git a/dist/index.css b/dist/index.css index 42256fb0..f354d064 100644 --- a/dist/index.css +++ b/dist/index.css @@ -1,6 +1,6 @@ /* src/styles.css */ [unread] { - border-left: 10px solid var(--text-warning); + border-left: 10px solid var(--text-warn); } :root { --thread-view-height-with-tools: 8rem; @@ -17,21 +17,21 @@ .chat-object-view { display: none; } -[showingchattools] :is(.thread-view, .chat-object-view) { +#message-tab:has([showingchattools]) :is(.thread-view, .chat-object-view) { overflow: scroll; position: absolute; padding: 0px; } -[showingchattools] header { +#message-tab:has([showingchattools]) header { border-bottom: 1px solid var(--border); } -[showingchattools] .chat-object-view { +#message-tab:has([showingchattools]) .chat-object-view { display: flex; top: var(--header-height); bottom: calc(var(--thread-view-height-with-tools) + var(--footer-top-line)); border-bottom: 1px solid var(--border); } -[showingchattools] .thread-view { +#message-tab:has([showingchattools]) .thread-view { display: flex; height: var(--thread-view-height-with-tools); top: unset; @@ -39,25 +39,25 @@ flex: 1; } @media (min-width: 640px) and (max-width: 1400px) { - main.split:has([showingchattools]) { + main.split:has(#message-tab [showingchattools]) { display: flex; } - main.split:has([showingchattools]) #settings-tab { + main.split:has(#message-tab [showingchattools]) #settings-tab { display: none; } } @media (min-width: 640px) { - [showingchattools] :is(.thread-view, .chat-object-view) { + #message-tab:has([showingchattools]) :is(.thread-view, .chat-object-view) { top: var(--header-height); bottom: var(--footer-top-line); } - [showingchattools] .chat-object-view { + #message-tab:has([showingchattools]) .chat-object-view { left: 0px; right: var(--thread-view-width-with-tools); border-bottom: none; border-right: 1px solid var(--border); } - [showingchattools] .thread-view { + #message-tab:has([showingchattools]) .thread-view { display: flex; left: unset; right: 0px; diff --git a/dist/index.js b/dist/index.js index b374ef1f..467962be 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1232,14 +1232,54 @@ connect(); } + // src/icons.ts + var icons = { + objectTitle: "label", + objectHistory: "history", + noteContent: "sticky_note_2", + categoryName: "category", + priority: "priority_high", + date: "calendar_month", + time: "schedule" + }; + + // src/Views/Objects/objectEntryView.tsx + function ObjectEntryView(chat, messageObject, selectedObject, isShowingObjectModal) { + const latest = chat.getMostRecentContent(messageObject); + function select() { + selectedObject.value = messageObject; + isShowingObjectModal.value = true; + } + const fields = { + [icons.noteContent]: "---", + [icons.priority]: "---", + [icons.categoryName]: "---", + [icons.date]: "---", + [icons.time]: "---" + }; + Object.entries(latest).forEach((entry) => { + let [key, value] = entry; + if (!value) return; + const icon = icons[key]; + if (!icon) return; + fields[icon] = value; + }); + const fieldElements = Object.entries(fields).map((field) => { + const [icon, value] = field; + return /* @__PURE__ */ createElement("span", { class: "flex-row control-gap align-center" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icon), value); + }); + return /* @__PURE__ */ createElement("button", { class: "tile justify-start", "on:click": select }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, chat.getObjectTitle(messageObject)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("span", { class: "flex-column gap height-100 flex secondary ellipsis " }, ...fieldElements))); + } + // src/Views/Objects/allObjectsView.tsx function AllObjectsView(chat, selectedObject, isShowingObjectModal) { const objectConverter = (messageObject) => { - function select() { - selectedObject.value = messageObject; - isShowingObjectModal.value = true; - } - return /* @__PURE__ */ createElement("button", { class: "tile", "on:click": select }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, chat.getObjectTitle(messageObject)), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id))); + return ObjectEntryView( + chat, + messageObject, + selectedObject, + isShowingObjectModal + ); }; const content = createProxyState( [chat.objects], @@ -1258,12 +1298,12 @@ // src/Views/Objects/noteObjectsView.tsx function NoteObjectsView(chat, selectedObject, isShowingObjectModal) { const objectConverter = (messageObject) => { - const latest = chat.getMostRecentContent(messageObject); - function select() { - selectedObject.value = messageObject; - isShowingObjectModal.value = true; - } - return /* @__PURE__ */ createElement("button", { class: "tile", "on:click": select }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, chat.getObjectTitle(messageObject)), /* @__PURE__ */ createElement("span", { class: "secondary ellipsis" }, latest.noteContent.split("\n")[0]))); + return ObjectEntryView( + chat, + messageObject, + selectedObject, + isShowingObjectModal + ); }; const notes = new ListState(); chat.objects.subscribe(() => { @@ -1309,18 +1349,24 @@ ); const editingDate = createProxyState( [selectedMessageObject], - () => selectedMessageObject.value.isoDate ?? (/* @__PURE__ */ new Date()).toISOString() + () => selectedMessageObject.value.date ?? "" ); const editingTime = createProxyState( [selectedMessageObject], - () => selectedMessageObject.value.isoTime ?? (/* @__PURE__ */ new Date()).toISOString() + () => selectedMessageObject.value.time ?? "" ); const editingPriority = createProxyState( [selectedMessageObject], () => selectedMessageObject.value.priority ?? 0 ); bulkSubscribe( - [editingNoteContent, editingCategory, editingDate, editingPriority], + [ + editingNoteContent, + editingCategory, + editingDate, + editingTime, + editingPriority + ], () => didEditContent.value = true ); function handleKeyDown(e) { @@ -1344,8 +1390,8 @@ noteContent: editingNoteContent.value, priority: editingPriority.value, categoryName: editingCategory.value, - isoDate: editingDate.value, - isoTime: editingTime.value + date: editingDate.value, + time: editingTime.value }); } chat.addObjectAndSend(messageObject); @@ -1363,35 +1409,35 @@ } ); isPresented.subscribe(() => setTimeout(() => input.focus(), 100)); - return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented, "on:keydown": handleKeyDown }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, chat.getObjectTitle(messageObject)), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "label"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.objectTitle), input)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "history"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.objectVersion), /* @__PURE__ */ createElement("select", { "bind:value": selectedMessageObjectId }, ...chat.getSortedContents(messageObject).map((content) => /* @__PURE__ */ createElement("option", { value: content.id }, new Date( + return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented, "on:keydown": handleKeyDown }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, chat.getObjectTitle(messageObject)), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.objectTitle), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.objectTitle), input)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.objectHistory), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.objectVersion), /* @__PURE__ */ createElement("select", { "bind:value": selectedMessageObjectId }, ...chat.getSortedContents(messageObject).map((content) => /* @__PURE__ */ createElement("option", { value: content.id }, new Date( content.isoDateVersionCreated - ).toLocaleString()))), /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_drop_down"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "sticky_note_2"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.note), /* @__PURE__ */ createElement( + ).toLocaleString()))), /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_drop_down"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.noteContent), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.note), /* @__PURE__ */ createElement( "textarea", { rows: "5", "bind:value": editingNoteContent, placeholder: translation.noteContentPlaceholder } - ))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "category"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.category), /* @__PURE__ */ createElement( + ))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.categoryName), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.category), /* @__PURE__ */ createElement( "input", { "bind:value": editingCategory, placeholder: translation.categoryPlaceholder } - ))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "priority_high"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.priority), /* @__PURE__ */ createElement( + ))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.priority), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.priority), /* @__PURE__ */ createElement( "input", { type: "number", "bind:value": editingPriority, placeholder: translation.priorityPlaceholder } - ))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "calendar_month"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.date), /* @__PURE__ */ createElement("input", { type: "date", "bind:value": editingDate }))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "schedule"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.time), /* @__PURE__ */ createElement("input", { type: "time", "bind:value": editingTime }))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("button", { class: "danger width-input", "on:click": deleteAndClose }, translation.deleteObject, /* @__PURE__ */ createElement("span", { class: "icon" }, "delete")))), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement("button", { class: "flex-1 width-100 danger", "on:click": closeModal }, translation.discard), /* @__PURE__ */ createElement("button", { class: "flex-1 width-100 primary", "on:click": saveAndClose }, translation.save, /* @__PURE__ */ createElement("span", { class: "icon" }, "save"))))); + ))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.date), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.date), /* @__PURE__ */ createElement("input", { type: "date", "bind:value": editingDate }))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icons.time), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.time), /* @__PURE__ */ createElement("input", { type: "time", "bind:value": editingTime }))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("button", { class: "danger width-input", "on:click": deleteAndClose }, translation.deleteObject, /* @__PURE__ */ createElement("span", { class: "icon" }, "delete")))), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement("button", { class: "flex-1 width-100 danger", "on:click": closeModal }, translation.discard), /* @__PURE__ */ createElement("button", { class: "flex-1 width-100 primary", "on:click": saveAndClose }, translation.save, /* @__PURE__ */ createElement("span", { class: "icon" }, "save"))))); } // src/Views/Objects/chatObjectView.tsx var viewTypes = { all: [translation.viewAll, "grid_view"], - notes: [translation.viewNotes, "sticky_note_2"] + notes: [translation.viewNotes, icons.noteContent] }; function ChatObjectView(chat) { const isShowingObjectModal = new State(false); @@ -1648,7 +1694,15 @@ "children:append": [chat.outbox, outboxMessageConverter] } ); - const listWrapper = /* @__PURE__ */ createElement("div", { class: "thread-view flex-column gap" }, messageList, outboxList); + const listWrapper = /* @__PURE__ */ createElement( + "div", + { + class: "thread-view flex-column gap", + "toggle:showingchattools": isShowingObjects + }, + messageList, + outboxList + ); function scrollToBottom() { listWrapper.scrollTop = listWrapper.scrollHeight; } @@ -1700,7 +1754,6 @@ return /* @__PURE__ */ createElement( "article", { - "toggle:showingchattools": isShowingObjects, id: "message-tab", "children:set": messageTabContent } diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts index 8933e565..b52007a2 100644 --- a/src/Model/chatModel.ts +++ b/src/Model/chatModel.ts @@ -39,10 +39,10 @@ export interface MessageObjectContent { id: string; noteContent?: string; - categoryName?: string; - isoDate?: string; - isoTime?: string; priority?: number; + categoryName?: string; + date?: string; + time?: string; } // chat diff --git a/src/Tabs/messageTab.tsx b/src/Tabs/messageTab.tsx index c14d49a9..dc04a5c7 100644 --- a/src/Tabs/messageTab.tsx +++ b/src/Tabs/messageTab.tsx @@ -61,7 +61,6 @@ export function MessageTab() { return (
diff --git a/src/Views/Chat/threadView.tsx b/src/Views/Chat/threadView.tsx index baa9ba06..c1a8761b 100644 --- a/src/Views/Chat/threadView.tsx +++ b/src/Views/Chat/threadView.tsx @@ -117,7 +117,10 @@ export function ThreadView(chat: Chat) { > ); const listWrapper = ( -
+
{messageList} {outboxList}
diff --git a/src/Views/Objects/allObjectsView.tsx b/src/Views/Objects/allObjectsView.tsx index 1c826334..730ab634 100644 --- a/src/Views/Objects/allObjectsView.tsx +++ b/src/Views/Objects/allObjectsView.tsx @@ -2,6 +2,7 @@ import * as React from "bloatless-react"; import { Chat, MessageObject } from "../../Model/chatModel"; +import { ObjectEntryView } from "./objectEntryView"; import { translation } from "../../translations"; export function AllObjectsView( @@ -12,18 +13,11 @@ export function AllObjectsView( const objectConverter: React.StateItemConverter = ( messageObject ) => { - function select() { - selectedObject.value = messageObject; - isShowingObjectModal.value = true; - } - - return ( - + return ObjectEntryView( + chat, + messageObject, + selectedObject, + isShowingObjectModal ); }; diff --git a/src/Views/Objects/chatObjectView.tsx b/src/Views/Objects/chatObjectView.tsx index d39b7745..78e2d75f 100644 --- a/src/Views/Objects/chatObjectView.tsx +++ b/src/Views/Objects/chatObjectView.tsx @@ -5,11 +5,12 @@ import { Chat, MessageObject } from "../../Model/chatModel"; import { AllObjectsView } from "./allObjectsView"; import { NoteObjectsView } from "./noteObjectsView"; import { ObjectDetailModal } from "./objectDetailModal"; +import { icons } from "../../icons"; import { translation } from "../../translations"; export const viewTypes = { all: [translation.viewAll, "grid_view"], - notes: [translation.viewNotes, "sticky_note_2"], + notes: [translation.viewNotes, icons.noteContent], }; export function ChatObjectView(chat: Chat) { diff --git a/src/Views/Objects/noteObjectsView.tsx b/src/Views/Objects/noteObjectsView.tsx index 0083f5fd..17a8eaea 100644 --- a/src/Views/Objects/noteObjectsView.tsx +++ b/src/Views/Objects/noteObjectsView.tsx @@ -2,6 +2,7 @@ import * as React from "bloatless-react"; import { Chat, MessageObject } from "../../Model/chatModel"; +import { ObjectEntryView } from "./objectEntryView"; import { translation } from "../../translations"; export function NoteObjectsView( @@ -12,22 +13,11 @@ export function NoteObjectsView( const objectConverter: React.StateItemConverter = ( messageObject ) => { - const latest = chat.getMostRecentContent(messageObject); - - function select() { - selectedObject.value = messageObject; - isShowingObjectModal.value = true; - } - - return ( - + return ObjectEntryView( + chat, + messageObject, + selectedObject, + isShowingObjectModal ); }; diff --git a/src/Views/Objects/objectDetailModal.tsx b/src/Views/Objects/objectDetailModal.tsx index d38b6758..d22b6c26 100644 --- a/src/Views/Objects/objectDetailModal.tsx +++ b/src/Views/Objects/objectDetailModal.tsx @@ -2,6 +2,7 @@ import * as React from "bloatless-react"; import { Chat, MessageObject } from "../../Model/chatModel"; +import { icons } from "../../icons"; import { translation } from "../../translations"; export function ObjectDetailModal( @@ -33,18 +34,24 @@ export function ObjectDetailModal( ); const editingDate = React.createProxyState( [selectedMessageObject], - () => selectedMessageObject.value.isoDate ?? new Date().toISOString() + () => selectedMessageObject.value.date ?? "" ); const editingTime = React.createProxyState( [selectedMessageObject], - () => selectedMessageObject.value.isoTime ?? new Date().toISOString() + () => selectedMessageObject.value.time ?? "" ); const editingPriority = React.createProxyState( [selectedMessageObject], () => selectedMessageObject.value.priority ?? 0 ); React.bulkSubscribe( - [editingNoteContent, editingCategory, editingDate, editingPriority], + [ + editingNoteContent, + editingCategory, + editingDate, + editingTime, + editingPriority, + ], () => (didEditContent.value = true) ); @@ -75,8 +82,8 @@ export function ObjectDetailModal( noteContent: editingNoteContent.value, priority: editingPriority.value, categoryName: editingCategory.value, - isoDate: editingDate.value, - isoTime: editingTime.value, + date: editingDate.value, + time: editingTime.value, }); } @@ -108,7 +115,7 @@ export function ObjectDetailModal(