diff --git a/dist/index.js b/dist/index.js index 32326f8b..ee8862bc 100644 --- a/dist/index.js +++ b/dist/index.js @@ -427,6 +427,19 @@ var stringToOptionTag = (value) => { return /* @__PURE__ */ createElement("option", null, value); }; + function getRawObjectIndex(latest) { + const dateString = latest.date || "0000-00-00"; + const [year, month, date] = dateString.split("-"); + const timeString = latest.time || "00:00"; + const [hour, minute] = timeString.split(":"); + const hourInMinutes = parseInt(hour) * 60; + const minutesTotal = parseInt(minute) + hourInMinutes; + const paddedMinutes = minutesTotal.toString().padStart(4, "0"); + const priority = latest.priority ?? 0; + const priorityInverse = 100 - priority; + const paddedPriority = priorityInverse.toString().padStart(3, "0"); + return `${year}${month}${date}${paddedMinutes}${paddedPriority}`; + } // src/translations.ts var englishTranslations = { @@ -760,6 +773,14 @@ var translation = allTranslations[language] ?? allTranslations.en; // src/Model/chatModel.ts + var MessageObjectWithIndex = class { + constructor(messageObject, index = 0) { + this.id = messageObject.id; + this.title = messageObject.title; + this.contentVersions = messageObject.contentVersions; + this.index = new State(index); + } + }; var Chat = class { id; viewType; @@ -1582,7 +1603,7 @@ const [icon, value] = field; return /* @__PURE__ */ createElement("span", { class: "flex-row control-gap flex align-center padding-right ellipsis" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icon), /* @__PURE__ */ createElement("span", { class: "ellipsis" }, value)); }); - return /* @__PURE__ */ createElement( + const view = /* @__PURE__ */ createElement( "button", { class: "tile flex-no", @@ -1599,6 +1620,10 @@ ...fieldElements )) ); + messageObject.index.subscribe((newIndex) => { + view.style.order = newIndex; + }); + return view; } // src/Views/Objects/objectGridView.tsx @@ -1652,22 +1677,12 @@ messageObjects.value.forEach(processObject); }); const objectConverter = (messageObject) => { - const latest = chat.getMostRecentContent(messageObject); - const timeString = latest.time || "00:00"; - const [hour, minute] = timeString.split(":"); - const hourInMinutes = parseInt(hour) * 60; - const minutesTotal = parseInt(minute) + hourInMinutes; - const priority = latest.priority ?? 0; - const priorityInverse = 100 - priority; - const order = `${minutesTotal}${priorityInverse}`; - const view = ObjectEntryView( + return ObjectEntryView( chat, messageObject, selectedObject, isShowingObjectModal ); - view.style.order = order; - return view; }; return /* @__PURE__ */ createElement( "div", @@ -1701,16 +1716,10 @@ const isToday = today.getDate() == dateObject.getUTCDate() && today.getMonth() == dateObject.getUTCMonth() && today.getFullYear() == dateObject.getUTCFullYear(); messageObjects.handleAddition(processObject); const objectConverter = (messageObject) => { - const latest = chat.getMostRecentContent(messageObject); - const timeString = latest.time || "00:00"; - const [hour, minute] = timeString.split(":"); - const hourInMinutes = parseInt(hour) * 60; - const minutesTotal = parseInt(minute) + hourInMinutes; - const priority = latest.priority ?? 0; - const priorityInverse = 100 - priority; - const order = `${minutesTotal}${priorityInverse}`; const view = /* @__PURE__ */ createElement("span", { class: "secondary ellipsis" }, chat.getObjectTitle(messageObject)); - view.style.order = order; + messageObject.index.subscribe((newIndex) => { + view.style.order = newIndex; + }); return view; }; return /* @__PURE__ */ createElement( @@ -1774,7 +1783,6 @@ monthGridCells.value = []; currentDate.setUTCDate(1); currentDate.setUTCMonth(newSelectedDate.getMonth()); - console.log(currentDate); for (let i = 0; i < 7; i++) { monthGridCells.value.push( /* @__PURE__ */ createElement("b", { class: "secondary ellipsis width-100" }, translation.weekdays[i]) @@ -1917,14 +1925,12 @@ chat.addObjectAndSend(messageObject); } const itemToViewEntry = (kanbanBoardItem) => { - const view = ObjectEntryView( + return ObjectEntryView( chat, kanbanBoardItem.messageObject, selectedObject, isShowingObjectModal ); - view.style.order = kanbanBoardItem.priority * -1; - return view; }; return /* @__PURE__ */ createElement( "div", @@ -2291,7 +2297,7 @@ [appliedFilter, resultCount], () => translation.searchTitleText(appliedFilter.value, resultCount.value) ); - const showingMessageObjects = new MapState(); + const visibleMessageObjects = new MapState(); const isFilterEmpty = createProxyState( [appliedFilter], () => appliedFilter.value == "" @@ -2305,21 +2311,21 @@ if (!previousObjectSearches.value.has(appliedFilter.value)) previousObjectSearches.add(appliedFilter.value); const allObjects = [...chat.objects.value.values()]; - allObjects.forEach((object, i) => { - const doesMatch = checkIfMatchesFilter(object); + allObjects.forEach((messageObject, i) => { + const doesMatch = checkIfMatchesFilter(messageObject); if (doesMatch) { - showingMessageObjects.set(object.id, object); + visibleMessageObjects.set(messageObject.id, new MessageObjectWithIndex(messageObject)); } else { - showingMessageObjects.remove(object.id); + visibleMessageObjects.remove(messageObject.id); } }); - resultCount.value = showingMessageObjects.value.size; + resultCount.value = visibleMessageObjects.value.size; } chat.objects.handleAddition((messageObject) => { if (checkIfMatchesFilter(messageObject) == false) return; - showingMessageObjects.set(messageObject.id, messageObject); + visibleMessageObjects.set(messageObject.id, new MessageObjectWithIndex(messageObject)); chat.objects.handleRemoval(messageObject, () => { - showingMessageObjects.remove(messageObject.id); + visibleMessageObjects.remove(messageObject.id); }); }); function checkIfMatchesFilter(messageObject) { @@ -2347,6 +2353,16 @@ return true; } applyFilter(); + visibleMessageObjects.subscribe((visibleMessageObjects2) => { + let indices = [...visibleMessageObjects2.values()].map((messageObject) => { + const latest = chat.getMostRecentContent(messageObject); + return getRawObjectIndex(latest); + }).sort(); + visibleMessageObjects2.forEach((messageObject) => { + const latest = chat.getMostRecentContent(messageObject); + messageObject.index.value = indices.indexOf(getRawObjectIndex(latest)); + }); + }); const objectModal = createProxyState( [chat.objects, selectedObject], () => { @@ -2375,7 +2391,7 @@ } return getViewFunction()( chat, - showingMessageObjects, + visibleMessageObjects, selectedObject, isShowingObjectModal ); @@ -2432,7 +2448,7 @@ translation.reset ), /* @__PURE__ */ createElement("button", { class: "width-50 flex primary", "on:click": applyFilter }, translation.search, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("b", { class: "secondary", "subscribe:innerText": resultText }), ObjectGridView( chat, - showingMessageObjects, + visibleMessageObjects, selectedObject, isShowingObjectModal )), /* @__PURE__ */ createElement("button", { "on:click": closeFilters }, translation.close, /* @__PURE__ */ createElement("span", { class: "icon" }, "close")))), /* @__PURE__ */ createElement("div", { "children:set": objectModal })); diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts index 437385f6..2b078746 100644 --- a/src/Model/chatModel.ts +++ b/src/Model/chatModel.ts @@ -49,6 +49,19 @@ export interface MessageObjectContent { time?: string; } +export interface MessageObjectWithIndex extends MessageObject { + index: React.State; +} + +export class MessageObjectWithIndex implements MessageObjectWithIndex { + constructor(messageObject: MessageObject, index: number = 0) { + this.id = messageObject.id; + this.title = messageObject.title; + this.contentVersions = messageObject.contentVersions; + this.index = new React.State(index); + } +} + // chat export class Chat { id: string; diff --git a/src/Views/Objects/allObjectsView.tsx b/src/Views/Objects/allObjectsView.tsx index fc2a43fa..bba231e0 100644 --- a/src/Views/Objects/allObjectsView.tsx +++ b/src/Views/Objects/allObjectsView.tsx @@ -1,13 +1,13 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectGridView } from "./objectGridView"; import { translation } from "../../translations"; export function AllObjectsView( chat: Chat, - messageObjects: React.MapState, + messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { diff --git a/src/Views/Objects/calendarView.tsx b/src/Views/Objects/calendarView.tsx index 6011d3ab..7dc0a35f 100644 --- a/src/Views/Objects/calendarView.tsx +++ b/src/Views/Objects/calendarView.tsx @@ -1,6 +1,6 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { DayView } from "./dayView"; import { MiniatureDayView } from "./miniatureDayView"; @@ -9,7 +9,7 @@ import { translation } from "../../translations"; export function CalendarView( chat: Chat, - messageObjects: React.MapState, + messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { diff --git a/src/Views/Objects/dayView.tsx b/src/Views/Objects/dayView.tsx index 2e05c73d..65a0d16f 100644 --- a/src/Views/Objects/dayView.tsx +++ b/src/Views/Objects/dayView.tsx @@ -1,6 +1,6 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectEntryView } from "./objectEntryView"; import { dayInCalendar } from "../../Model/model"; @@ -8,14 +8,14 @@ import { dayInCalendar } from "../../Model/model"; export function DayView( chat: Chat, messageObjects: - | React.ListState - | React.MapState, + | React.ListState + | React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { - const objectsForDayView = new React.ListState(); + const objectsForDayView = new React.ListState(); - function processObject(messageObject: MessageObject) { + function processObject(messageObject: MessageObjectWithIndex) { const latest = chat.getMostRecentContent(messageObject); if (!latest.date || latest.date != dayInCalendar.value) return; @@ -31,26 +31,15 @@ export function DayView( messageObjects.value.forEach(processObject); }) - const objectConverter: React.StateItemConverter = ( + const objectConverter: React.StateItemConverter = ( messageObject ) => { - const latest = chat.getMostRecentContent(messageObject); - const timeString = latest.time || "00:00"; - const [hour, minute] = timeString.split(":"); - const hourInMinutes = parseInt(hour) * 60; - const minutesTotal = parseInt(minute) + hourInMinutes; - const priority = latest.priority ?? 0; - const priorityInverse = 100 - priority; - const order = `${minutesTotal}${priorityInverse}`; - - const view = ObjectEntryView( + return ObjectEntryView( chat, messageObject, selectedObject, isShowingObjectModal ); - view.style.order = order; - return view; }; return ( diff --git a/src/Views/Objects/kanbanView.tsx b/src/Views/Objects/kanbanView.tsx index 605cfce1..0194f66f 100644 --- a/src/Views/Objects/kanbanView.tsx +++ b/src/Views/Objects/kanbanView.tsx @@ -1,6 +1,6 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectEntryView } from "./objectEntryView"; import { RenameView } from "../renameView"; @@ -17,7 +17,7 @@ interface KanbanBoardItem { export function KanbanView( chat: Chat, - messageObjects: React.MapState, + messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { @@ -116,14 +116,12 @@ function KanbanBoardView( const itemToViewEntry: React.StateItemConverter = ( kanbanBoardItem ) => { - const view = ObjectEntryView( + return ObjectEntryView( chat, kanbanBoardItem.messageObject, selectedObject, isShowingObjectModal ); - view.style.order = kanbanBoardItem.priority * -1; - return view; }; return ( diff --git a/src/Views/Objects/miniatureDayView.tsx b/src/Views/Objects/miniatureDayView.tsx index 8034d087..870756dd 100644 --- a/src/Views/Objects/miniatureDayView.tsx +++ b/src/Views/Objects/miniatureDayView.tsx @@ -1,21 +1,22 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { dayInCalendar } from "../../Model/model"; +import { getRawObjectIndex } from "../../utility"; export function MiniatureDayView( chat: Chat, messageObjects: - | React.ListState - | React.MapState, + | React.ListState + | React.MapState, dateObject: Date ) { const objectsForDayView = new React.ListState(); const dateString = dateObject.toISOString().split("T")[0]; - function processObject(messageObject: MessageObject) { + function processObject(messageObject: MessageObjectWithIndex) { const latest = chat.getMostRecentContent(messageObject); if (!latest.date || latest.date != dateString) return; @@ -41,24 +42,17 @@ export function MiniatureDayView( messageObjects.handleAddition(processObject); - const objectConverter: React.StateItemConverter = ( + const objectConverter: React.StateItemConverter = ( messageObject ) => { - const latest = chat.getMostRecentContent(messageObject); - const timeString = latest.time || "00:00"; - const [hour, minute] = timeString.split(":"); - const hourInMinutes = parseInt(hour) * 60; - const minutesTotal = parseInt(minute) + hourInMinutes; - const priority = latest.priority ?? 0; - const priorityInverse = 100 - priority; - const order = `${minutesTotal}${priorityInverse}`; - const view = ( {chat.getObjectTitle(messageObject)} ); - view.style.order = order; + messageObject.index.subscribe(newIndex => { + view.style.order = newIndex; + }) return view; }; diff --git a/src/Views/Objects/noteObjectsView.tsx b/src/Views/Objects/noteObjectsView.tsx index d6c23db8..75b6ff42 100644 --- a/src/Views/Objects/noteObjectsView.tsx +++ b/src/Views/Objects/noteObjectsView.tsx @@ -1,12 +1,12 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectGridView } from "./objectGridView"; export function NoteObjectsView( chat: Chat, - messageObjects: React.MapState, + messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { diff --git a/src/Views/Objects/objectEntryView.tsx b/src/Views/Objects/objectEntryView.tsx index 33e0e7b9..47b43cba 100644 --- a/src/Views/Objects/objectEntryView.tsx +++ b/src/Views/Objects/objectEntryView.tsx @@ -4,13 +4,14 @@ import { Chat, MessageObject, MessageObjectContent, + MessageObjectWithIndex, } from "../../Model/chatModel"; import { icons } from "../../icons"; export function ObjectEntryView( chat: Chat, - messageObject: MessageObject, + messageObject: MessageObjectWithIndex, selectedObject: React.State, isShowingObjectModal: React.State ) { @@ -54,7 +55,7 @@ export function ObjectEntryView( ); }); - return ( + const view = ( ); + messageObject.index.subscribe(newIndex => { + view.style.order = newIndex; + }) + return view; } diff --git a/src/Views/Objects/objectGridView.tsx b/src/Views/Objects/objectGridView.tsx index abff1d79..85dd7b75 100644 --- a/src/Views/Objects/objectGridView.tsx +++ b/src/Views/Objects/objectGridView.tsx @@ -1,18 +1,18 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectEntryView } from "./objectEntryView"; export function ObjectGridView( chat: Chat, messageObjects: - | React.ListState - | React.MapState, + | React.ListState + | React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { - const objectConverter: React.StateItemConverter = ( + const objectConverter: React.StateItemConverter = ( messageObject ) => { return ObjectEntryView( diff --git a/src/Views/Objects/objectPane.tsx b/src/Views/Objects/objectPane.tsx index b0de9f2c..ebd97357 100644 --- a/src/Views/Objects/objectPane.tsx +++ b/src/Views/Objects/objectPane.tsx @@ -1,6 +1,11 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { + Chat, + MessageObject, + MessageObjectWithIndex, +} from "../../Model/chatModel"; +import { getRawObjectIndex, stringToOptionTag } from "../../utility"; import { objectFilterInput, previousObjectSearches } from "../../Model/model"; import { AllObjectsView } from "./allObjectsView"; @@ -11,7 +16,6 @@ import { ObjectDetailModal } from "./objectDetailModal"; import { ObjectGridView } from "./objectGridView"; import { StatusView } from "./statusView"; import { icons } from "../../icons"; -import { stringToOptionTag } from "../../utility"; import { translation } from "../../translations"; export const viewTypes = { @@ -51,7 +55,7 @@ export function ObjectPane(chat: Chat) { const resultText = React.createProxyState([appliedFilter, resultCount], () => translation.searchTitleText(appliedFilter.value, resultCount.value) ); - const showingMessageObjects = new React.MapState(); + const visibleMessageObjects = new React.MapState(); const isFilterEmpty = React.createProxyState( [appliedFilter], () => appliedFilter.value == "" @@ -68,22 +72,22 @@ export function ObjectPane(chat: Chat) { previousObjectSearches.add(appliedFilter.value); const allObjects = [...chat.objects.value.values()]; - allObjects.forEach((object, i) => { - const doesMatch = checkIfMatchesFilter(object); + allObjects.forEach((messageObject, i) => { + const doesMatch = checkIfMatchesFilter(messageObject); if (doesMatch) { - showingMessageObjects.set(object.id, object); + visibleMessageObjects.set(messageObject.id, new MessageObjectWithIndex(messageObject)); } else { - showingMessageObjects.remove(object.id); + visibleMessageObjects.remove(messageObject.id); } }); - resultCount.value = showingMessageObjects.value.size; + resultCount.value = visibleMessageObjects.value.size; } chat.objects.handleAddition((messageObject) => { if (checkIfMatchesFilter(messageObject) == false) return; - showingMessageObjects.set(messageObject.id, messageObject); + visibleMessageObjects.set(messageObject.id, new MessageObjectWithIndex(messageObject)); chat.objects.handleRemoval(messageObject, () => { - showingMessageObjects.remove(messageObject.id); + visibleMessageObjects.remove(messageObject.id); }); }); @@ -122,6 +126,21 @@ export function ObjectPane(chat: Chat) { applyFilter(); + // sorting + visibleMessageObjects.subscribe((visibleMessageObjects) => { + let indices = [...visibleMessageObjects.values()] + .map((messageObject) => { + const latest = chat.getMostRecentContent(messageObject); + return getRawObjectIndex(latest); + }) + .sort(); + + visibleMessageObjects.forEach((messageObject) => { + const latest = chat.getMostRecentContent(messageObject); + messageObject.index.value = indices.indexOf(getRawObjectIndex(latest)); + }); + }); + // view const objectModal = React.createProxyState( [chat.objects, selectedObject], @@ -154,7 +173,7 @@ export function ObjectPane(chat: Chat) { return getViewFunction()( chat, - showingMessageObjects, + visibleMessageObjects, selectedObject, isShowingObjectModal ); @@ -238,7 +257,7 @@ export function ObjectPane(chat: Chat) { {ObjectGridView( chat, - showingMessageObjects, + visibleMessageObjects, selectedObject, isShowingObjectModal )} diff --git a/src/Views/Objects/statusView.tsx b/src/Views/Objects/statusView.tsx index 5fb386bc..63fd1896 100644 --- a/src/Views/Objects/statusView.tsx +++ b/src/Views/Objects/statusView.tsx @@ -1,6 +1,6 @@ import * as React from "bloatless-react"; -import { Chat, MessageObject } from "../../Model/chatModel"; +import { Chat, MessageObject, MessageObjectWithIndex } from "../../Model/chatModel"; import { ObjectEntryView } from "./objectEntryView"; import { RenameView } from "../renameView"; @@ -29,7 +29,7 @@ interface StatusData { export function StatusView( chat: Chat, - messageObjects: React.MapState, + messageObjects: React.MapState, selectedObject: React.State, isShowingObjectModal: React.State ) { diff --git a/src/utility.tsx b/src/utility.tsx index 84e72a42..ca32dcf7 100644 --- a/src/utility.tsx +++ b/src/utility.tsx @@ -1,7 +1,6 @@ import * as React from "bloatless-react"; -import { MessageObject } from "./Model/chatModel"; -import { ObjectEntryView } from "./Views/Objects/objectEntryView"; +import { MessageObjectContent } from "./Model/chatModel"; export const storageKeys = { viewType(id: string): string { @@ -47,4 +46,26 @@ export const storageKeys = { export const stringToOptionTag: React.StateItemConverter = (value) => { return ; -}; \ No newline at end of file +}; + +export function getRawObjectIndex(latest: MessageObjectContent): string { + // date + const dateString = latest.date || "0000-00-00"; + const [year, month, date] = dateString.split("-") + + // time + const timeString = latest.time || "00:00"; + const [hour, minute] = timeString.split(":"); + + const hourInMinutes = parseInt(hour) * 60; + const minutesTotal = parseInt(minute) + hourInMinutes; + const paddedMinutes = minutesTotal.toString().padStart(4, "0") + + // priority + const priority = latest.priority ?? 0; + const priorityInverse = 100 - priority; + const paddedPriority = priorityInverse.toString().padStart(3, "0"); + + // final + return `${year}${month}${date}${paddedMinutes}${paddedPriority}`; +}