diff --git a/dist/index.css b/dist/index.css index 28e13c14..33593a85 100644 --- a/dist/index.css +++ b/dist/index.css @@ -14,10 +14,10 @@ display: flex; flex-direction: column; } -.chat-tool-view { +.chat-object-view { display: none; } -[showingchattools] :is(.thread-view, .chat-tool-view) { +[showingchattools] :is(.thread-view, .chat-object-view) { overflow: scroll; position: absolute; padding: 0px; @@ -25,7 +25,7 @@ [showingchattools] header { border-bottom: 1px solid var(--border); } -[showingchattools] .chat-tool-view { +[showingchattools] .chat-object-view { display: flex; top: var(--header-height); bottom: calc(var(--thread-view-height-with-tools) + var(--footer-top-line)); @@ -47,11 +47,11 @@ } } @media (min-width: 640px) { - [showingchattools] :is(.thread-view, .chat-tool-view) { + [showingchattools] :is(.thread-view, .chat-object-view) { top: var(--header-height); bottom: var(--footer-top-line); } - [showingchattools] .chat-tool-view { + [showingchattools] .chat-object-view { left: 0px; right: var(--thread-view-width-with-tools); border-bottom: none; diff --git a/dist/index.js b/dist/index.js index f20702f2..7213222a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1006,7 +1006,9 @@ copyMessage: "Copy message", deleteMessage: "Delete message", // objects - toggleChatTools: "toggle chat tools", + showObjects: "show objects", + createObject: "create object", + untitledObject: "Untitled Object", objectTitle: "Object title", objectTitlePlaceholder: "My object", objectVersion: "Object version", @@ -1113,6 +1115,122 @@ var language = navigator.language.substring(0, 2); var translation = allTranslations[language] ?? allTranslations.en; + // src/Views/Objects/objectDetailModal.tsx + function ObjectDetailModal(chat, messageObject, isPresented) { + const editingTitle = new State(messageObject.title); + const selectedMessageObjectId = new State( + chat.getMostRecentContentId(messageObject) + ); + const selectedMessageObject = createProxyState( + [selectedMessageObjectId], + () => chat.getObjectContentFromId(messageObject, selectedMessageObjectId.value) + ); + const didEditContent = new State(false); + const editingNoteContent = createProxyState( + [selectedMessageObject], + () => selectedMessageObject.value.noteContent ?? "" + ); + bulkSubscribe( + [editingNoteContent], + () => didEditContent.value = true + ); + function handleKeyDown(e) { + if (!e.metaKey && !e.ctrlKey) return; + switch (e.key) { + case "s": + e.preventDefault(); + saveAndClose(); + break; + } + } + function closeModal() { + isPresented.value = false; + } + function saveAndClose() { + messageObject.title = editingTitle.value; + if (didEditContent.value == true) { + chat.addObjectContent(messageObject, { + isoDateVersionCreated: (/* @__PURE__ */ new Date()).toISOString(), + id: UUID(), + noteContent: editingNoteContent.value + }); + } + chat.addObjectAndSend(messageObject); + closeModal(); + } + function deleteAndClose() { + chat.deleteObject(messageObject); + closeModal(); + } + return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented, "on:keydown": handleKeyDown }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, messageObject.title), /* @__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), /* @__PURE__ */ createElement( + "input", + { + "bind:value": editingTitle, + placeholder: translation.objectTitlePlaceholder + } + ))), /* @__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( + content.isoDateVersionCreated + ).toLocaleString()))), /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_drop_down"))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "sticky_note_2"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.noteContent), /* @__PURE__ */ createElement( + "textarea", + { + rows: "5", + "bind:value": editingNoteContent, + placeholder: translation.noteContentPlaceholder + } + ))), /* @__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/objectListEntry.tsx + function ObjectListEntry(messageObject, onclick) { + return /* @__PURE__ */ createElement("button", { class: "tile", "on:click": onclick }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, messageObject.title), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id))); + } + + // src/Views/Objects/chatObjectView.tsx + function ChatObjectView(chat) { + const isShowingObjectModal = new State(false); + const selectedObject = new State(void 0); + const objectModal = createProxyState( + [chat.objects, selectedObject], + () => { + if (selectedObject.value == void 0) return /* @__PURE__ */ createElement("div", null); + return ObjectDetailModal( + chat, + selectedObject.value, + isShowingObjectModal + ); + } + ); + function createObject() { + const newObject = chat.createObjectFromTitle(translation.untitledObject); + chat.addObjectAndSend(newObject); + selectedObject.value = newObject; + isShowingObjectModal.value = true; + } + const objectConverter = (messageObject) => { + function select() { + selectedObject.value = messageObject; + isShowingObjectModal.value = true; + } + return ObjectListEntry(messageObject, select); + }; + return /* @__PURE__ */ createElement("div", { class: "chat-object-view flex-column" }, /* @__PURE__ */ createElement("div", { class: "flex-row align-center scroll-h border-bottom" }, /* @__PURE__ */ createElement( + "button", + { + class: "primary", + "on:click": createObject, + "aria-label": translation.createObject + }, + /* @__PURE__ */ createElement("span", { class: "icon" }, "add") + )), /* @__PURE__ */ createElement( + "div", + { + class: "grid gap padding", + style: "grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))", + "children:prepend": [chat.objects, objectConverter] + } + ), /* @__PURE__ */ createElement("div", { "children:set": objectModal })); + } + // src/Views/Chat/chatOptionModal.tsx function ChatOptionModal(chat, isPresented) { function closeModal() { @@ -1221,105 +1339,6 @@ ), /* @__PURE__ */ createElement("button", { class: "danger", "on:click": deleteChat }, translation.removeChat, /* @__PURE__ */ createElement("span", { class: "icon" }, "delete_forever")))), /* @__PURE__ */ createElement("button", { "on:click": closeModal }, translation.close, /* @__PURE__ */ createElement("span", { class: "icon" }, "close")))); } - // src/Views/Objects/objectDetailModal.tsx - function ObjectDetailModal(chat, messageObject, isPresented) { - const editingTitle = new State(messageObject.title); - const selectedMessageObjectId = new State( - chat.getMostRecentContentId(messageObject) - ); - const selectedMessageObject = createProxyState( - [selectedMessageObjectId], - () => chat.getObjectContentFromId(messageObject, selectedMessageObjectId.value) - ); - const didEditContent = new State(false); - const editingNoteContent = createProxyState( - [selectedMessageObject], - () => selectedMessageObject.value.noteContent ?? "" - ); - bulkSubscribe( - [editingNoteContent], - () => didEditContent.value = true - ); - function handleKeyDown(e) { - if (!e.metaKey && !e.ctrlKey) return; - switch (e.key) { - case "s": - e.preventDefault(); - saveAndClose(); - break; - } - } - function closeModal() { - isPresented.value = false; - } - function saveAndClose() { - messageObject.title = editingTitle.value; - if (didEditContent.value == true) { - chat.addObjectContent(messageObject, { - isoDateVersionCreated: (/* @__PURE__ */ new Date()).toISOString(), - id: UUID(), - noteContent: editingNoteContent.value - }); - } - chat.addObjectAndSend(messageObject); - closeModal(); - } - function deleteAndClose() { - chat.deleteObject(messageObject); - closeModal(); - } - return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented, "on:keydown": handleKeyDown }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, messageObject.title), /* @__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), /* @__PURE__ */ createElement( - "input", - { - "bind:value": editingTitle, - placeholder: translation.objectTitlePlaceholder - } - ))), /* @__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( - content.isoDateVersionCreated - ).toLocaleString()))), /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_drop_down"))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "sticky_note_2"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.noteContent), /* @__PURE__ */ createElement( - "textarea", - { - rows: "5", - "bind:value": editingNoteContent, - placeholder: translation.noteContentPlaceholder - } - ))), /* @__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/objectListEntry.tsx - function ObjectListEntry(messageObject, onclick) { - return /* @__PURE__ */ createElement("button", { class: "tile", "on:click": onclick }, /* @__PURE__ */ createElement("b", null, messageObject.title)); - } - - // src/Views/Objects/objectListView.tsx - function ChatToolView(chat) { - const isShowingObjectModal = new State(false); - const selectedObject = new State(void 0); - const objectModal = createProxyState( - [chat.objects, selectedObject], - () => { - if (selectedObject.value == void 0) return /* @__PURE__ */ createElement("div", null); - return ObjectDetailModal( - chat, - selectedObject.value, - isShowingObjectModal - ); - } - ); - function createItem() { - const newObject = chat.createObjectFromTitle("New item"); - chat.addObjectAndSend(newObject); - } - const itemConverter = (messageObject) => { - function select() { - selectedObject.value = messageObject; - isShowingObjectModal.value = true; - } - return ObjectListEntry(messageObject, select); - }; - return /* @__PURE__ */ createElement("div", { class: "chat-tool-view" }, /* @__PURE__ */ createElement("button", { "on:click": createItem }, "+"), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { "children:prepend": [chat.objects, itemConverter] }), /* @__PURE__ */ createElement("div", { "children:set": objectModal })); - } - // src/Views/Chat/messageComposer.tsx function MessageComposer(chat) { return /* @__PURE__ */ createElement("div", { class: "flex-row width-100" }, " ", /* @__PURE__ */ createElement( @@ -1435,7 +1454,7 @@ /* @__PURE__ */ createElement("header", { class: "padding-0" }, /* @__PURE__ */ createElement("span", { class: "flex-row align-center" }, /* @__PURE__ */ createElement("button", { "aria-label": translation.back, "on:click": closeChatView }, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")), /* @__PURE__ */ createElement("span", { "subscribe:innerText": chat.primaryChannel })), /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement( "button", { - "aria-label": translation.toggleChatTools, + "aria-label": translation.showObjects, "on:click": toggleChatTools, "toggle:selected": isShowingChatTools }, @@ -1448,7 +1467,7 @@ }, /* @__PURE__ */ createElement("span", { class: "icon" }, "tune") ))), - ChatToolView(chat), + ChatObjectView(chat), ThreadView(chat), /* @__PURE__ */ createElement("footer", null, MessageComposer(chat)), ChatOptionModal(chat, isShowingOptions) diff --git a/dist/styles.css b/dist/styles.css index 32951f47..4d35cb09 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -323,6 +323,10 @@ hr { border-bottom: 1px solid var(--border); } +.border-bottom { + border-bottom: 1px solid var(--border) !important; +} + input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus:not( label.tile * ), @@ -960,6 +964,15 @@ main { overflow-x: scroll; } +.scroll-h { + overflow-x: scroll !important; +} + +.scroll-v { + overflow-y: scroll !important; +} + + .ellipsis { text-overflow: ellipsis; } diff --git a/src/Tabs/messageTab.tsx b/src/Tabs/messageTab.tsx index aed4bee9..6fde89f5 100644 --- a/src/Tabs/messageTab.tsx +++ b/src/Tabs/messageTab.tsx @@ -2,8 +2,8 @@ import * as React from "bloatless-react"; import { closeChatView, isShowingChatTools, selectedChat, toggleChatTools } from "../Model/model"; +import { ChatObjectView } from "../Views/Objects/chatObjectView"; import { ChatOptionModal } from "../Views/Chat/chatOptionModal"; -import { ChatToolView } from "../Views/Objects/objectListView"; import { MessageComposer } from "../Views/Chat/messageComposer"; import { ThreadView } from "../Views/Chat/threadView"; import { translation } from "../translations"; @@ -35,7 +35,7 @@ export function MessageTab() { -
-
+
+
+ +
+ +
diff --git a/src/Views/Objects/objectListEntry.tsx b/src/Views/Objects/objectListEntry.tsx index 406072c4..35b379c3 100644 --- a/src/Views/Objects/objectListEntry.tsx +++ b/src/Views/Objects/objectListEntry.tsx @@ -8,7 +8,10 @@ export function ObjectListEntry( ) { return ( ); } diff --git a/src/styles.css b/src/styles.css index 797d1fff..9f47312b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -18,11 +18,11 @@ flex-direction: column; } -.chat-tool-view { +.chat-object-view { display: none; } -[showingchattools] :is(.thread-view, .chat-tool-view) { +[showingchattools] :is(.thread-view, .chat-object-view) { overflow: scroll; position: absolute; @@ -33,7 +33,7 @@ border-bottom: 1px solid var(--border); } -[showingchattools] .chat-tool-view { +[showingchattools] .chat-object-view { display: flex; top: var(--header-height); @@ -64,12 +64,12 @@ } @media (min-width: 640px) { - [showingchattools] :is(.thread-view, .chat-tool-view) { + [showingchattools] :is(.thread-view, .chat-object-view) { top: var(--header-height); bottom: var(--footer-top-line); } - [showingchattools] .chat-tool-view { + [showingchattools] .chat-object-view { left: 0px; right: var(--thread-view-width-with-tools); diff --git a/src/translations.ts b/src/translations.ts index 820cca19..64bfdf8c 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -67,7 +67,9 @@ const englishTranslations = { deleteMessage: "Delete message", // objects - toggleChatTools: "toggle chat tools", + showObjects: "show objects", + createObject: "create object", + untitledObject: "Untitled Object", objectTitle: "Object title", objectTitlePlaceholder: "My object",