prepare layout for object views
This commit is contained in:
Vendored
+138
-33
@@ -975,7 +975,7 @@
|
|||||||
serverAddress: "Server Address",
|
serverAddress: "Server Address",
|
||||||
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
||||||
connectToServer: "Connect",
|
connectToServer: "Connect",
|
||||||
disconnect: "Disonnect",
|
disconnect: "Disconnect",
|
||||||
mailbox: "Mailbox",
|
mailbox: "Mailbox",
|
||||||
requestMailbox: "Enable",
|
requestMailbox: "Enable",
|
||||||
deleteMailbox: "Disable",
|
deleteMailbox: "Disable",
|
||||||
@@ -1009,6 +1009,10 @@
|
|||||||
showObjects: "show objects",
|
showObjects: "show objects",
|
||||||
createObject: "create object",
|
createObject: "create object",
|
||||||
untitledObject: "Untitled Object",
|
untitledObject: "Untitled Object",
|
||||||
|
viewAll: "All",
|
||||||
|
viewNotes: "Notes",
|
||||||
|
noObjects: "No objects",
|
||||||
|
noNotes: "No notes",
|
||||||
objectTitle: "Object title",
|
objectTitle: "Object title",
|
||||||
objectTitlePlaceholder: "My object",
|
objectTitlePlaceholder: "My object",
|
||||||
objectVersion: "Object version",
|
objectVersion: "Object version",
|
||||||
@@ -1022,18 +1026,20 @@
|
|||||||
es: {
|
es: {
|
||||||
// general
|
// general
|
||||||
set: "Guardar",
|
set: "Guardar",
|
||||||
|
save: "Guardar",
|
||||||
back: "Atr\xE1s",
|
back: "Atr\xE1s",
|
||||||
undoChanges: "Deshacer",
|
undoChanges: "Deshacer",
|
||||||
close: "Cerrar",
|
close: "Cerrar",
|
||||||
|
discard: "Descartar",
|
||||||
// overview
|
// overview
|
||||||
overview: "Resumen",
|
overview: "Resumen",
|
||||||
connection: "Conexion",
|
connection: "Conexi\xF3n",
|
||||||
chats: "Chats",
|
chats: "Chats",
|
||||||
yourName: "Tu nombre",
|
yourName: "Tu nombre",
|
||||||
namePlaceholder: "Juan P\xE9rez",
|
namePlaceholder: "Juan P\xE9rez",
|
||||||
encryptionUnavailableTitle: "Cifrado no disponible",
|
encryptionUnavailableTitle: "Cifrado no disponible",
|
||||||
encryptionUnavailableMessage: "Obt\xE9n esta aplicaci\xF3n a traves de HTTPS o contin\xFAa sin cifrado",
|
encryptionUnavailableMessage: "Obt\xE9n esta aplicaci\xF3n a traves de HTTPS o contin\xFAa sin cifrado",
|
||||||
serverAddress: "Direccion del servidor",
|
serverAddress: "Direcci\xF3n del servidor",
|
||||||
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
||||||
connectToServer: "Conectar",
|
connectToServer: "Conectar",
|
||||||
disconnect: "Desconectar",
|
disconnect: "Desconectar",
|
||||||
@@ -1044,33 +1050,48 @@
|
|||||||
primaryChannel: "Canal principal",
|
primaryChannel: "Canal principal",
|
||||||
primaryChannelPlaceholder: "mi-canal",
|
primaryChannelPlaceholder: "mi-canal",
|
||||||
addChat: "A\xF1adir",
|
addChat: "A\xF1adir",
|
||||||
// messages
|
// chat
|
||||||
showChatOptions: "Mostrar opciones del chat",
|
showChatOptions: "Mostrar opciones del chat",
|
||||||
configureChatTitle: "Configurar chat",
|
configureChatTitle: "Configurar chat",
|
||||||
secondaryChannel: "Canal segundario",
|
secondaryChannel: "Canal secundario",
|
||||||
secondaryChannelPlaceholder: "A\xF1adir canal segundario",
|
secondaryChannelPlaceholder: "A\xF1adir canal secundario",
|
||||||
addSecondaryChannel: "A\xF1adir canal segundario",
|
addSecondaryChannel: "A\xF1adir canal secundario",
|
||||||
removeSecondaryChannel: "Eliminar canal segundario",
|
removeSecondaryChannel: "Eliminar canal secundario",
|
||||||
encryptionKey: "Clave de cifrado",
|
encryptionKey: "Clave de cifrado",
|
||||||
encryptionKeyPlaceholder: "n10d2482dg283hg",
|
encryptionKeyPlaceholder: "n10d2482dg283hg",
|
||||||
showKey: "Mostrar clave",
|
showKey: "Mostrar clave",
|
||||||
|
clearObjects: "Eliminar todos los objetos",
|
||||||
|
clearChatMessages: "Eliminar todos los mensajes",
|
||||||
removeChat: "Eliminar chat",
|
removeChat: "Eliminar chat",
|
||||||
clearChatMessages: "Eliminar todos mensajes",
|
|
||||||
noChatSelected: "Selecciona un chat",
|
|
||||||
messageInOutbox: "Pendiente",
|
messageInOutbox: "Pendiente",
|
||||||
|
noChatSelected: "Selecciona un chat",
|
||||||
composerPlaceholder: "Escribe un mensaje...",
|
composerPlaceholder: "Escribe un mensaje...",
|
||||||
sendMessage: "Enviar",
|
sendMessage: "Enviar",
|
||||||
resendMessage: "Enviar de nuevo",
|
// messages
|
||||||
|
resendMessage: "Reenviar mensaje",
|
||||||
decryptMessage: "Descifrar mensaje",
|
decryptMessage: "Descifrar mensaje",
|
||||||
copyMessage: "Copiar mensaje",
|
copyMessage: "Copiar mensaje",
|
||||||
deleteMessage: "Eliminar este mensaje"
|
deleteMessage: "Eliminar este mensaje",
|
||||||
|
// objects
|
||||||
|
showObjects: "mostrar objetos",
|
||||||
|
createObject: "a\xF1adir nuevo objeto",
|
||||||
|
untitledObject: "Sin T\xEDtulo",
|
||||||
|
objectTitle: "T\xEDtulo",
|
||||||
|
objectTitlePlaceholder: "Mi objeto",
|
||||||
|
objectVersion: "Version del objeto",
|
||||||
|
noteContent: "Nota",
|
||||||
|
noteContentPlaceholder: "Toma nota...",
|
||||||
|
resendObjects: "Reenviar todos objetos",
|
||||||
|
deleteObject: "Eliminar objeto"
|
||||||
},
|
},
|
||||||
de: {
|
de: {
|
||||||
// general
|
// general
|
||||||
set: "OK",
|
set: "OK",
|
||||||
|
save: "Sichern",
|
||||||
back: "Zur\xFCck",
|
back: "Zur\xFCck",
|
||||||
undoChanges: "\xC4nderungen verwerfen",
|
undoChanges: "\xC4nderungen verwerfen",
|
||||||
close: "Schlie\xDFen",
|
close: "Schlie\xDFen",
|
||||||
|
discard: "Verwerfen",
|
||||||
// overview
|
// overview
|
||||||
overview: "\xDCbersicht",
|
overview: "\xDCbersicht",
|
||||||
connection: "Verbindung",
|
connection: "Verbindung",
|
||||||
@@ -1090,7 +1111,7 @@
|
|||||||
primaryChannel: "Hauptkanal",
|
primaryChannel: "Hauptkanal",
|
||||||
primaryChannelPlaceholder: "mein-kanal",
|
primaryChannelPlaceholder: "mein-kanal",
|
||||||
addChat: "Hinzuf\xFCgen",
|
addChat: "Hinzuf\xFCgen",
|
||||||
// messages
|
// chat
|
||||||
showChatOptions: "Chatoptionen einblenden",
|
showChatOptions: "Chatoptionen einblenden",
|
||||||
configureChatTitle: "Chat konfigurieren",
|
configureChatTitle: "Chat konfigurieren",
|
||||||
secondaryChannel: "Zweitkanal",
|
secondaryChannel: "Zweitkanal",
|
||||||
@@ -1100,21 +1121,80 @@
|
|||||||
encryptionKey: "Schl\xFCssel",
|
encryptionKey: "Schl\xFCssel",
|
||||||
encryptionKeyPlaceholder: "n10d2482dg283hg",
|
encryptionKeyPlaceholder: "n10d2482dg283hg",
|
||||||
showKey: "Schl\xFCssel anzeigen",
|
showKey: "Schl\xFCssel anzeigen",
|
||||||
removeChat: "Chat l\xF6schen",
|
clearObjects: "Alle Objekte l\xF6schen",
|
||||||
clearChatMessages: "Nachrichtenverlauf leeren",
|
clearChatMessages: "Nachrichtenverlauf leeren",
|
||||||
noChatSelected: "Kein Chat ausgew\xE4hlt",
|
removeChat: "Chat l\xF6schen",
|
||||||
messageInOutbox: "Ausstehend",
|
messageInOutbox: "Ausstehend",
|
||||||
|
noChatSelected: "Kein Chat ausgew\xE4hlt",
|
||||||
composerPlaceholder: "Neue Nachricht...",
|
composerPlaceholder: "Neue Nachricht...",
|
||||||
sendMessage: "Senden",
|
sendMessage: "Senden",
|
||||||
|
// messages
|
||||||
resendMessage: "Erneut senden",
|
resendMessage: "Erneut senden",
|
||||||
decryptMessage: "Nachricht entschl\xFCsseln",
|
decryptMessage: "Nachricht entschl\xFCsseln",
|
||||||
copyMessage: "Nachricht kopieren",
|
copyMessage: "Nachricht kopieren",
|
||||||
deleteMessage: "Nachricht l\xF6schen"
|
deleteMessage: "Nachricht l\xF6schen",
|
||||||
|
// objects
|
||||||
|
showObjects: "Objekte anzeigen",
|
||||||
|
createObject: "Neues Objekt erstellen",
|
||||||
|
untitledObject: "Unbenannt",
|
||||||
|
objectTitle: "Titel",
|
||||||
|
objectTitlePlaceholder: "Mein Objekt",
|
||||||
|
objectVersion: "Version des Objekts",
|
||||||
|
noteContent: "Notiz",
|
||||||
|
noteContentPlaceholder: "Notiz eingeben...",
|
||||||
|
resendObjects: "Objekte erneut senden",
|
||||||
|
deleteObject: "Objekt l\xF6schen"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var language = navigator.language.substring(0, 2);
|
var language = navigator.language.substring(0, 2);
|
||||||
var translation = allTranslations[language] ?? allTranslations.en;
|
var translation = allTranslations[language] ?? allTranslations.en;
|
||||||
|
|
||||||
|
// 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, messageObject.title), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id)));
|
||||||
|
};
|
||||||
|
const content = createProxyState(
|
||||||
|
[chat.objects],
|
||||||
|
() => chat.objects.value.size == 0 ? /* @__PURE__ */ createElement("div", { class: "flex-column width-100 height-100 align-center justify-center secondary" }, translation.noObjects) : /* @__PURE__ */ createElement(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "grid gap padding",
|
||||||
|
style: "grid-template-columns: repeat(auto-fit, minmax(350px, 1fr))",
|
||||||
|
"children:prepend": [chat.objects, objectConverter]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return /* @__PURE__ */ createElement("div", { class: "width-100 height-100", "children:set": content });
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/Views/Objects/noteObjectsView.tsx
|
||||||
|
function NoteObjectsView(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, messageObject.title), /* @__PURE__ */ createElement("span", { class: "secondary" }, messageObject.id)));
|
||||||
|
};
|
||||||
|
const content = createProxyState(
|
||||||
|
[chat.objects],
|
||||||
|
() => chat.objects.value.size == 0 ? /* @__PURE__ */ createElement("div", { class: "flex-column width-100 height-100 align-center justify-center secondary" }, translation.noNotes) : /* @__PURE__ */ createElement(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "grid gap padding",
|
||||||
|
style: "grid-template-columns: repeat(auto-fit, minmax(350px, 1fr))",
|
||||||
|
"children:prepend": [chat.objects, objectConverter]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return /* @__PURE__ */ createElement("div", { class: "width-100 height-100", "children:set": content });
|
||||||
|
}
|
||||||
|
|
||||||
// src/Views/Objects/objectDetailModal.tsx
|
// src/Views/Objects/objectDetailModal.tsx
|
||||||
function ObjectDetailModal(chat, messageObject, isPresented) {
|
function ObjectDetailModal(chat, messageObject, isPresented) {
|
||||||
const editingTitle = new State(messageObject.title);
|
const editingTitle = new State(messageObject.title);
|
||||||
@@ -1165,6 +1245,7 @@
|
|||||||
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(
|
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",
|
"input",
|
||||||
{
|
{
|
||||||
|
autofocus: true,
|
||||||
"bind:value": editingTitle,
|
"bind:value": editingTitle,
|
||||||
placeholder: translation.objectTitlePlaceholder
|
placeholder: translation.objectTitlePlaceholder
|
||||||
}
|
}
|
||||||
@@ -1180,12 +1261,11 @@
|
|||||||
))), /* @__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("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
|
// src/Views/Objects/chatObjectView.tsx
|
||||||
|
var viewTypes = {
|
||||||
|
all: [translation.viewAll, "grid_view"],
|
||||||
|
notes: [translation.viewNotes, "sticky_note_2"]
|
||||||
|
};
|
||||||
function ChatObjectView(chat) {
|
function ChatObjectView(chat) {
|
||||||
const isShowingObjectModal = new State(false);
|
const isShowingObjectModal = new State(false);
|
||||||
const selectedObject = new State(void 0);
|
const selectedObject = new State(void 0);
|
||||||
@@ -1200,36 +1280,61 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const selectedViewType = new State("all");
|
||||||
|
const mainView = createProxyState([selectedViewType], () => {
|
||||||
|
function getViewFunction() {
|
||||||
|
switch (selectedViewType.value) {
|
||||||
|
case "notes":
|
||||||
|
return NoteObjectsView;
|
||||||
|
default:
|
||||||
|
return AllObjectsView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getViewFunction()(chat, selectedObject, isShowingObjectModal);
|
||||||
|
});
|
||||||
function createObject() {
|
function createObject() {
|
||||||
const newObject = chat.createObjectFromTitle(translation.untitledObject);
|
const newObject = chat.createObjectFromTitle(translation.untitledObject);
|
||||||
chat.addObjectAndSend(newObject);
|
chat.addObjectAndSend(newObject);
|
||||||
selectedObject.value = newObject;
|
selectedObject.value = newObject;
|
||||||
isShowingObjectModal.value = true;
|
isShowingObjectModal.value = true;
|
||||||
}
|
}
|
||||||
const objectConverter = (messageObject) => {
|
return /* @__PURE__ */ createElement("div", { class: "chat-object-view flex-column" }, /* @__PURE__ */ createElement("div", { class: "flex-row align-center border-bottom" }, /* @__PURE__ */ createElement(
|
||||||
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",
|
"button",
|
||||||
{
|
{
|
||||||
class: "primary",
|
class: "primary height-100",
|
||||||
"on:click": createObject,
|
"on:click": createObject,
|
||||||
"aria-label": translation.createObject
|
"aria-label": translation.createObject
|
||||||
},
|
},
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "add")
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "add")
|
||||||
|
), /* @__PURE__ */ createElement("div", { class: "padding-sm flex flex-row gap justify-center scroll-h width-100" }, ...Object.keys(viewTypes).map(
|
||||||
|
(key) => ViewTypeToggle(key, selectedViewType)
|
||||||
|
)), /* @__PURE__ */ createElement(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "height-100",
|
||||||
|
"on:click": createObject,
|
||||||
|
"aria-label": translation.createObject
|
||||||
|
},
|
||||||
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "visibility")
|
||||||
)), /* @__PURE__ */ createElement(
|
)), /* @__PURE__ */ createElement(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "grid gap padding",
|
class: "width-100 height-100 flex-1 scroll-h",
|
||||||
style: "grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))",
|
"children:set": mainView
|
||||||
"children:prepend": [chat.objects, objectConverter]
|
|
||||||
}
|
}
|
||||||
), /* @__PURE__ */ createElement("div", { "children:set": objectModal }));
|
), /* @__PURE__ */ createElement("div", { "children:set": objectModal }));
|
||||||
}
|
}
|
||||||
|
function ViewTypeToggle(key, selection) {
|
||||||
|
const [label, icon] = viewTypes[key];
|
||||||
|
function select() {
|
||||||
|
selection.value = key;
|
||||||
|
}
|
||||||
|
const isSelected = createProxyState(
|
||||||
|
[selection],
|
||||||
|
() => selection.value == key
|
||||||
|
);
|
||||||
|
return /* @__PURE__ */ createElement("button", { "aria-label": label, "on:click": select, "toggle:selected": isSelected }, /* @__PURE__ */ createElement("span", { class: "icon" }, icon));
|
||||||
|
}
|
||||||
|
|
||||||
// src/Views/Chat/chatOptionModal.tsx
|
// src/Views/Chat/chatOptionModal.tsx
|
||||||
function ChatOptionModal(chat, isPresented) {
|
function ChatOptionModal(chat, isPresented) {
|
||||||
|
|||||||
Vendored
+5
-2
@@ -489,7 +489,7 @@ input[type="radio"],
|
|||||||
}
|
}
|
||||||
|
|
||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center !important;
|
justify-content: safe center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.justify-end {
|
.justify-end {
|
||||||
@@ -586,6 +586,10 @@ textarea,
|
|||||||
padding: var(--control-padding) !important;
|
padding: var(--control-padding) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.padding-sm {
|
||||||
|
padding: var(--gap-between-tiles) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.modal main {
|
.modal main {
|
||||||
padding: var(--modal-padding);
|
padding: var(--modal-padding);
|
||||||
}
|
}
|
||||||
@@ -972,7 +976,6 @@ main {
|
|||||||
overflow-y: scroll !important;
|
overflow-y: scroll !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.ellipsis {
|
.ellipsis {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { Chat, MessageObject } from "../../Model/chatModel";
|
||||||
|
|
||||||
|
import { translation } from "../../translations";
|
||||||
|
|
||||||
|
export function AllObjectsView(
|
||||||
|
chat: Chat,
|
||||||
|
selectedObject: React.State<MessageObject | undefined>,
|
||||||
|
isShowingObjectModal: React.State<boolean>
|
||||||
|
) {
|
||||||
|
const objectConverter: React.StateItemConverter<MessageObject> = (
|
||||||
|
messageObject
|
||||||
|
) => {
|
||||||
|
function select() {
|
||||||
|
selectedObject.value = messageObject;
|
||||||
|
isShowingObjectModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button class="tile" on:click={select}>
|
||||||
|
<div>
|
||||||
|
<b>{messageObject.title}</b>
|
||||||
|
<span class="secondary">{messageObject.id}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const content = React.createProxyState([chat.objects], () =>
|
||||||
|
chat.objects.value.size == 0 ? (
|
||||||
|
<div class="flex-column width-100 height-100 align-center justify-center secondary">
|
||||||
|
{translation.noObjects}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
class="grid gap padding"
|
||||||
|
style="grid-template-columns: repeat(auto-fit, minmax(350px, 1fr))"
|
||||||
|
children:prepend={[chat.objects, objectConverter]}
|
||||||
|
></div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div class="width-100 height-100" children:set={content}></div>;
|
||||||
|
}
|
||||||
@@ -2,11 +2,18 @@ import * as React from "bloatless-react";
|
|||||||
|
|
||||||
import { Chat, MessageObject } from "../../Model/chatModel";
|
import { Chat, MessageObject } from "../../Model/chatModel";
|
||||||
|
|
||||||
|
import { AllObjectsView } from "./allObjectsView";
|
||||||
|
import { NoteObjectsView } from "./noteObjectsView";
|
||||||
import { ObjectDetailModal } from "./objectDetailModal";
|
import { ObjectDetailModal } from "./objectDetailModal";
|
||||||
import { ObjectListEntry } from "./objectListEntry";
|
|
||||||
import { translation } from "../../translations";
|
import { translation } from "../../translations";
|
||||||
|
|
||||||
|
export const viewTypes = {
|
||||||
|
all: [translation.viewAll, "grid_view"],
|
||||||
|
notes: [translation.viewNotes, "sticky_note_2"],
|
||||||
|
};
|
||||||
|
|
||||||
export function ChatObjectView(chat: Chat) {
|
export function ChatObjectView(chat: Chat) {
|
||||||
|
// selection and modal
|
||||||
const isShowingObjectModal = new React.State(false);
|
const isShowingObjectModal = new React.State(false);
|
||||||
const selectedObject = new React.State<MessageObject | undefined>(undefined);
|
const selectedObject = new React.State<MessageObject | undefined>(undefined);
|
||||||
const objectModal = React.createProxyState(
|
const objectModal = React.createProxyState(
|
||||||
@@ -22,6 +29,22 @@ export function ChatObjectView(chat: Chat) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// view type
|
||||||
|
const selectedViewType = new React.State<keyof typeof viewTypes>("all");
|
||||||
|
const mainView = React.createProxyState([selectedViewType], () => {
|
||||||
|
function getViewFunction() {
|
||||||
|
switch (selectedViewType.value) {
|
||||||
|
case "notes":
|
||||||
|
return NoteObjectsView;
|
||||||
|
default:
|
||||||
|
return AllObjectsView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getViewFunction()(chat, selectedObject, isShowingObjectModal);
|
||||||
|
});
|
||||||
|
|
||||||
|
// methods
|
||||||
function createObject() {
|
function createObject() {
|
||||||
const newObject = chat.createObjectFromTitle(translation.untitledObject);
|
const newObject = chat.createObjectFromTitle(translation.untitledObject);
|
||||||
chat.addObjectAndSend(newObject);
|
chat.addObjectAndSend(newObject);
|
||||||
@@ -29,36 +52,60 @@ export function ChatObjectView(chat: Chat) {
|
|||||||
isShowingObjectModal.value = true;
|
isShowingObjectModal.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectConverter: React.StateItemConverter<MessageObject> = (
|
|
||||||
messageObject
|
|
||||||
) => {
|
|
||||||
function select() {
|
|
||||||
selectedObject.value = messageObject;
|
|
||||||
isShowingObjectModal.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ObjectListEntry(messageObject, select);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="chat-object-view flex-column">
|
<div class="chat-object-view flex-column">
|
||||||
<div class="flex-row align-center scroll-h border-bottom">
|
<div class="flex-row align-center border-bottom">
|
||||||
<button
|
<button
|
||||||
class="primary"
|
class="primary height-100"
|
||||||
on:click={createObject}
|
on:click={createObject}
|
||||||
aria-label={translation.createObject}
|
aria-label={translation.createObject}
|
||||||
>
|
>
|
||||||
<span class="icon">add</span>
|
<span class="icon">add</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div class="padding-sm flex flex-row gap justify-center scroll-h width-100">
|
||||||
|
{...Object.keys(viewTypes).map((key: any) =>
|
||||||
|
ViewTypeToggle(key, selectedViewType)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="height-100"
|
||||||
|
on:click={createObject}
|
||||||
|
aria-label={translation.createObject}
|
||||||
|
>
|
||||||
|
<span class="icon">visibility</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="grid gap padding"
|
class="width-100 height-100 flex-1 scroll-h"
|
||||||
style="grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))"
|
children:set={mainView}
|
||||||
children:prepend={[chat.objects, objectConverter]}
|
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div children:set={objectModal}></div>
|
<div children:set={objectModal}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ViewTypeToggle(
|
||||||
|
key: keyof typeof viewTypes,
|
||||||
|
selection: React.State<keyof typeof viewTypes>
|
||||||
|
) {
|
||||||
|
const [label, icon] = viewTypes[key];
|
||||||
|
|
||||||
|
function select() {
|
||||||
|
selection.value = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSelected = React.createProxyState(
|
||||||
|
[selection],
|
||||||
|
() => selection.value == key
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button aria-label={label} on:click={select} toggle:selected={isSelected}>
|
||||||
|
<span class="icon">{icon}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { Chat, MessageObject } from "../../Model/chatModel";
|
||||||
|
|
||||||
|
import { translation } from "../../translations";
|
||||||
|
|
||||||
|
export function NoteObjectsView(
|
||||||
|
chat: Chat,
|
||||||
|
selectedObject: React.State<MessageObject | undefined>,
|
||||||
|
isShowingObjectModal: React.State<boolean>
|
||||||
|
) {
|
||||||
|
const objectConverter: React.StateItemConverter<MessageObject> = (
|
||||||
|
messageObject
|
||||||
|
) => {
|
||||||
|
function select() {
|
||||||
|
selectedObject.value = messageObject;
|
||||||
|
isShowingObjectModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button class="tile" on:click={select}>
|
||||||
|
<div>
|
||||||
|
<b>{messageObject.title}</b>
|
||||||
|
<span class="secondary">{messageObject.id}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const content = React.createProxyState([chat.objects], () =>
|
||||||
|
chat.objects.value.size == 0 ? (
|
||||||
|
<div class="flex-column width-100 height-100 align-center justify-center secondary">
|
||||||
|
{translation.noNotes}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
class="grid gap padding"
|
||||||
|
style="grid-template-columns: repeat(auto-fit, minmax(350px, 1fr))"
|
||||||
|
children:prepend={[chat.objects, objectConverter]}
|
||||||
|
></div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div class="width-100 height-100" children:set={content}></div>;
|
||||||
|
}
|
||||||
@@ -83,6 +83,7 @@ export function ObjectDetailModal(
|
|||||||
<div>
|
<div>
|
||||||
<span>{translation.objectTitle}</span>
|
<span>{translation.objectTitle}</span>
|
||||||
<input
|
<input
|
||||||
|
autofocus
|
||||||
bind:value={editingTitle}
|
bind:value={editingTitle}
|
||||||
placeholder={translation.objectTitlePlaceholder}
|
placeholder={translation.objectTitlePlaceholder}
|
||||||
></input>
|
></input>
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import * as React from "bloatless-react";
|
|
||||||
|
|
||||||
import { MessageObject } from "../../Model/chatModel";
|
|
||||||
|
|
||||||
export function ObjectListEntry(
|
|
||||||
messageObject: MessageObject,
|
|
||||||
onclick: () => void
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<button class="tile" on:click={onclick}>
|
|
||||||
<div>
|
|
||||||
<b>{messageObject.title}</b>
|
|
||||||
<span class="secondary">{messageObject.id}</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -71,6 +71,12 @@ const englishTranslations = {
|
|||||||
createObject: "create object",
|
createObject: "create object",
|
||||||
untitledObject: "Untitled Object",
|
untitledObject: "Untitled Object",
|
||||||
|
|
||||||
|
viewAll: "All",
|
||||||
|
viewNotes: "Notes",
|
||||||
|
|
||||||
|
noObjects: "No objects",
|
||||||
|
noNotes: "No notes",
|
||||||
|
|
||||||
objectTitle: "Object title",
|
objectTitle: "Object title",
|
||||||
objectTitlePlaceholder: "My object",
|
objectTitlePlaceholder: "My object",
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user