mirror of
https://gitlab.com/octospacc/WhichNot.git
synced 2025-06-27 09:02:56 +02:00
Update
This commit is contained in:
61
index.html
61
index.html
@ -1391,6 +1391,7 @@ render(html`<${App}/>`, document.body);
|
||||
.App.show-chat .ChatScreen { display: flex; }
|
||||
}
|
||||
</style>
|
||||
<script src="../Downloads/localforage.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
@ -1398,6 +1399,7 @@ import { h, render, createContext } from 'https://esm.sh/preact';
|
||||
import { useState, useEffect, useCallback, useRef, useContext } from 'https://esm.sh/preact/hooks';
|
||||
import htm from 'https://esm.sh/htm';
|
||||
const html = htm.bind(h), AppContext = createContext();
|
||||
localforage.config({ name: "WhichNot" });
|
||||
|
||||
const uuidv7 = () => {
|
||||
const bytes = new Uint8Array(16);
|
||||
@ -1482,11 +1484,11 @@ function App() {
|
||||
|
||||
// Load & decrypt
|
||||
useEffect(() => {
|
||||
const raw=JSON.parse(localStorage.getItem('notebooks')) || [],
|
||||
enc={}, msgs={};
|
||||
(async () => {
|
||||
const raw = await localforage.getItem('notebooks') || [],
|
||||
enc = {}, msgs = {};
|
||||
for (const notebook of raw) {
|
||||
const arr=JSON.parse(localStorage.getItem(`notebook-${notebook.id}`)) || [];
|
||||
const arr = await localforage.getItem(`notebook-${notebook.id}`) || [];
|
||||
enc[notebook.id] = arr;
|
||||
const rawKey = await getAesRawKey(notebook.aesKeyB64);
|
||||
const plain = {}; // [];
|
||||
@ -1502,11 +1504,11 @@ function App() {
|
||||
}, []);
|
||||
|
||||
// Persist notebooks meta
|
||||
useEffect(() => localStorage.setItem('notebooks', JSON.stringify(state.notebooks)), [state.notebooks]);
|
||||
useEffect(() => localforage.setItem('notebooks', state.notebooks), [state.notebooks]);
|
||||
// Persist encrypted store
|
||||
useEffect(() => {
|
||||
for (const id in state.encrypted) {
|
||||
localStorage.setItem(`notebook-${id}`, JSON.stringify(state.encrypted[id]));
|
||||
localforage.setItem(`notebook-${id}`, state.encrypted[id]);
|
||||
}
|
||||
}, [state.encrypted]);
|
||||
|
||||
@ -1559,6 +1561,13 @@ function App() {
|
||||
return (messageId ? messages[messageId] : messages);
|
||||
// return (messageId ? messages.find(message => (message.id === messageId)) : messages);
|
||||
}, [state.messages]);
|
||||
const saveMessage = (notebookId, message) => persistMessages(notebookId, Object.values({ ...getMessages(notebookId), [message.id]: message }));
|
||||
const deleteMessage = (notebookId, messageId) => {
|
||||
const messages = getMessages(notebookId);
|
||||
delete messages[messageId];
|
||||
persistMessages(notebookId, Object.values(messages));
|
||||
// setState(s => ({ ...s, messages: { ...s.messages, [nbId]: messages } }));
|
||||
};
|
||||
|
||||
const persistMessages = useCallback(async(nbId, plainArr) => {
|
||||
const notebook = getNotebook(nbId);
|
||||
@ -1584,12 +1593,22 @@ function App() {
|
||||
// }
|
||||
}, [state.notebooks]);
|
||||
|
||||
const addReaction = useCallback(idx => setState(s => ({ ...s, reactionInputFor: idx })), []);
|
||||
const addReaction = useCallback(messageId => setState(s => ({ ...s, reactionInputFor: messageId })), []);
|
||||
const confirmReaction = useCallback(async (idx, emoji) => {
|
||||
if(!emoji) return setState(s=>({...s,reactionInputFor:null}));
|
||||
const nbId=state.selectedNotebook, arr=state.messages[nbId]||[];
|
||||
const newArr=arr.map((m,i)=>i===idx?{...m,reactions:m.reactions.includes(emoji)?m.reactions:[...m.reactions,emoji]}:m);
|
||||
await persistMessages(nbId,newArr);
|
||||
if (!emoji) return;
|
||||
setState(s => ({ ...s, reactionInputFor: null }));
|
||||
const nbId = state.selectedNotebook;
|
||||
//const arr = state.messages[nbId] || [];
|
||||
//const newArr = arr.map((m, i) => i===idx ? { ...m, reactions: (m.reactions.includes(emoji) ? m.reactions : [...m.reactions, emoji]) } : m);
|
||||
//const newArr = getMessages(nbId);
|
||||
//const m = newArr[idx];
|
||||
//newArr[idx] = { ...m, reactions: (m.reactions.includes(emoji) ? m.reactions : [...m.reactions, emoji]) }
|
||||
//await persistMessages(nbId, newArr);
|
||||
const message = getMessages(nbId, idx);
|
||||
if (!message.reactions.includes(emoji)) {
|
||||
message.reactions = [...message.reactions, emoji];
|
||||
saveMessage(nbId, message);
|
||||
}
|
||||
setState(s => ({ ...s, reactionInputFor: null }));
|
||||
},[state.selectedNotebook, state.messages, persistMessages]);
|
||||
const removeReaction = useCallback(async (idx, emoji) => {
|
||||
@ -1606,7 +1625,6 @@ function App() {
|
||||
if (message) {
|
||||
inputRef.current.value = message.text;
|
||||
}
|
||||
console.log(state, message, state.messages[state.selectedNotebook]);
|
||||
}
|
||||
}, [state.editingMessage, state.selectedNotebook, state.messages]);
|
||||
|
||||
@ -1645,13 +1663,6 @@ function App() {
|
||||
await persistMessages(nbId, newArr);
|
||||
}, [state.selectedNotebook, state.editingMessage, state.replyingTo, state.messages, state.notebooks]);
|
||||
|
||||
const deleteMessage = (notebookId, messageId) => {
|
||||
const messages = getMessages(notebookId);
|
||||
delete messages[messageId];
|
||||
persistMessages(notebookId, Object.values(messages));
|
||||
// setState(s => ({ ...s, messages: { ...s.messages, [nbId]: messages } }));
|
||||
};
|
||||
|
||||
return html`
|
||||
<${AppContext.Provider} value=${{
|
||||
state, setState, createNotebook,
|
||||
@ -1681,7 +1692,7 @@ function ChatList() {
|
||||
<div class="ChatList">
|
||||
<div class="ChatList-header">
|
||||
<button onClick=${() => setState(s => ({ ...s, createModal: true }))}>+</button>
|
||||
<button onClick=${() => setState(s => ({ ...s, searchModal: { visible: true, global: true, query: '' } }))}>🔍</button>
|
||||
<!-- <button onClick=${() => setState(s => ({ ...s, searchModal: { visible: true, global: true, query: '' } }))}>🔍</button> -->
|
||||
<button onClick=${() => setState(s => ({ ...s, showAppSettings: true }))}>⚙️</button>
|
||||
</div>
|
||||
${state.notebooks.sort((a, b) => (sortNotebook(b) - sortNotebook(a))).map(notebook => html`
|
||||
@ -1733,13 +1744,13 @@ function ChatScreen({inputRef}) {
|
||||
</button>
|
||||
<div class="NotebookEmoji" style=${{ background: notebook.color }}>${notebook.emoji}</div>
|
||||
<h3>${notebook.name}</h3>
|
||||
<button class="SearchButton"
|
||||
<!-- <button class="SearchButton"
|
||||
onClick=${ev => {
|
||||
ev.stopPropagation();
|
||||
setState(s => ({ ...s, searchModal: { visible: true, global: false, query: '' }}));
|
||||
}}>
|
||||
🔍
|
||||
</button>
|
||||
</button> -->
|
||||
</div>
|
||||
<div class="Messages">
|
||||
${messages.map(message => html`
|
||||
@ -1918,7 +1929,7 @@ function SettingsModal() {
|
||||
const del = () => {
|
||||
if (confirm('Delete?')) {
|
||||
if (notebook.sourceType==='local') {
|
||||
localStorage.removeItem(`notebook-${notebook.id}`);
|
||||
localforage.removeItem(`notebook-${notebook.id}`);
|
||||
}
|
||||
setState(s => ({ ...s,
|
||||
notebooks: s.notebooks.filter(n => n.id!==notebook.id),
|
||||
@ -1973,14 +1984,14 @@ function SearchModal() {
|
||||
|
||||
function AppSettingsModal() {
|
||||
const {state,setState} = useContext(AppContext);
|
||||
const exportData = () => JSON.stringify({ notebooks: state.notebooks, encrypted: state.encrypted }, null, 2);
|
||||
const exportData = () => JSON.stringify({ notebooks: state.notebooks, encrypted: /* Object.fromEntries(Object.entries( */ state.encrypted /* ).map(([key, values]) => ([key, Object.values(values)]))) */ }, null, 2);
|
||||
const [txt,setTxt] = useState('');
|
||||
const doImport = () => {
|
||||
try {
|
||||
const obj = JSON.parse(txt);
|
||||
if (obj.notebooks && obj.encrypted) {
|
||||
localStorage.setItem('notebooks', JSON.stringify(obj.notebooks));
|
||||
Object.entries(obj.encrypted).forEach(([id,arr]) => localStorage.setItem(`notebook-${id}`, JSON.stringify(arr)));
|
||||
localforage.setItem('notebooks', obj.notebooks);
|
||||
Object.entries(obj.encrypted).forEach(([id,arr]) => localforage.setItem(`notebook-${id}`, arr));
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert('Invalid format');
|
||||
|
Reference in New Issue
Block a user