implemented sharing of bookmarks

This commit is contained in:
2025-08-03 22:42:37 +02:00
parent 783eaf3303
commit d7fe16c46e
10 changed files with 118 additions and 28 deletions

View File

@@ -3,7 +3,7 @@
import { tick } from "svelte";
let {
getCandidates = text => {},
getCandidates = async text => { conole.log('no handler for getCandidates('+text+')'); return {};},
onSelect = text => []
} = $props();
@@ -18,6 +18,7 @@
let result = {};
result[key] = text;
options = {};
text = '';
onSelect(result);
}
@@ -49,10 +50,11 @@
min-width: 200px;
}
</style>
<select size={Object.keys(options).length<2?2:Object.keys(options).length+1} {onkeyup} {ondblclick} autofocus width="40">
{#if options}
<select size={Object.keys(options).length<2?2:Object.keys(options).length+1} {onkeyup} {ondblclick} width="40">
<option>{text}</option>
{#each Object.entries(options) as [val,caption]}
<option value={val}>{caption}</option>
{/each}
</select>
{/if}

View File

@@ -8,11 +8,11 @@
import PermissionSelector from './PermissionSelector.svelte';
let {
members,
getCandidates = text => {},
updatePermission = (uid,perm) => console.log(`no handler for updatePermission(${uid}, ${perm})`),
addMember = (entry) => console.log(`no handler for addMember(${entry})`),
dropMember = (member) => console.log(`no handler for dropMember(${member})`),
addMember = (entry) => console.log(`no handler for addMember(${entry})`)
getCandidates = text => {},
members,
updatePermission = (uid,perm) => console.log(`no handler for updatePermission(${uid}, ${perm})`)
} = $props();
let error = $state(null);

View File

@@ -0,0 +1,50 @@
<script>
import { api } from '../urls.svelte.js';
import { t } from '../translations.svelte.js';
import { user } from '../user.svelte.js';
import Autocomplete from './Autocomplete.svelte';
let error = $state(null);
let {
getCandidates = async text => {},
heading = t('add_user'),
users = $bindable({})
} = $props();
function dropUser(id){
delete users[id];
}
function onSelect(entry){
for (let [k,v] of Object.entries(entry)){
users[k] = {name:v,id:k};
}
}
let sortedUsers = $derived.by(() => Object.values(users).sort((a, b) => a.name.localeCompare(b.name)));
</script>
{#if error}
<span class="error">{error}</span>
{/if}
<table>
<tbody>
{#each sortedUsers as usr,idx}
<tr>
<td>{usr.name}</td>
<td>
{#if usr.id != user.id}
<button onclick={() => dropUser(usr.id)}>x</button>
{/if}
</td>
</tr>
{/each}
<tr>
<td>{heading}</td>
<td>
<Autocomplete {getCandidates} {onSelect} />
</td>
</tr>
</tbody>
</table>

View File

@@ -5,6 +5,7 @@
import { t } from '../../translations.svelte.js';
import Editor from '../../Components/MarkdownEditor.svelte';
import Users from '../../Components/UserSelector.svelte';
import Tags from '../tags/TagList.svelte';
import Template from './Template.svelte';
@@ -15,20 +16,36 @@
rendered:null
},
tags:[],
url:null
url:null,
users:{}
});
let error = $state(null);
async function getCandidates(text){
const url = api('user/search');
const resp = await fetch(url,{
credentials : 'include',
method : 'POST',
body : text
});
if (resp.ok){
error = null;
const input = await resp.json();
return Object.fromEntries(
Object.entries(input).map(([key, value]) => [key, value.name])
);
} else {
error = await resp.text();
return {};
}
}
async function loadBookmarks(){
const url = api('bookmark/list');
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
const raw = await resp.json();
bookmarks = Object.values(raw)
.sort(
(a, b) => new Date(b.timestamp) - new Date(a.timestamp)
);
bookmarks = Object.values(raw).sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
error = false;
} else {
error = await resp.html();
@@ -37,12 +54,14 @@
async function onclick(ev){
delete new_bookmark.comment.rendered;
const url = api('bookmark/save');
const url = api('bookmark');
const data = {
comment : new_bookmark.comment.source,
url : new_bookmark.url,
tags : new_bookmark.tags
}
const share = Object.keys(new_bookmark.users).map(id => +id);
if (share.length>0) data.share = share;
const resp = await fetch(url,{
credentials : 'include',
method : 'POST',
@@ -66,17 +85,21 @@
{/if}
<label>
{t('URL')}
<input bind:value={new_bookmark.url} />
<input bind:value={new_bookmark.url} autofocus />
</label>
<label>
{t('Comment')}
<Editor simple={true} bind:value={new_bookmark.comment} />
</label>
<label>
{t('share_with')}
<Users {getCandidates} users={new_bookmark.users} />
</label>
<Tags module="bookmark" bind:tags={new_bookmark.tags} />
<button {onclick}>{t('save')}</button>
{#if bookmarks}
{#each bookmarks as bookmark}
<Template {bookmark} />
<Template {bookmark} />
{/each}
{/if}
</fieldset>

View File

@@ -101,7 +101,7 @@
<div class="taglist">
<span class="tag editor">
<input type="text" bind:value={newTag} onkeyup={typed} autofocus />
<input type="text" bind:value={newTag} onkeyup={typed} />
</span>
{#each tags as tag,idx}
<span class="tag">
@@ -109,4 +109,4 @@
<button onclick={() => drop(tag)} class="symbol"></button>
</span>
{/each}
</div>
</div>