forked from NextGraph/nextgraph-rs
parent
ef93afe4cb
commit
6fe3624ba0
@ -0,0 +1,116 @@ |
||||
<!-- |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||
// All rights reserved. |
||||
// Licensed under the Apache License, Version 2.0 |
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0> |
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
||||
// at your option. All files in the project carrying such |
||||
// notice may not be copied, modified, or distributed except |
||||
// according to those terms. |
||||
--> |
||||
|
||||
<script lang="ts"> |
||||
|
||||
import ng from "../api"; |
||||
import { link } from "svelte-spa-router"; |
||||
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; |
||||
import{ PlusCircle } from "svelte-heros-v2"; |
||||
import { push } from "svelte-spa-router"; |
||||
import{ QrCode } from "svelte-heros-v2"; |
||||
import { t } from "svelte-i18n"; |
||||
import { |
||||
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab |
||||
} from "../tab"; |
||||
import DataClassIcon from "../lib/icons/DataClassIcon.svelte"; |
||||
import { |
||||
openModalCreate, |
||||
sparql_query, |
||||
active_session, |
||||
scanned_qr_code, |
||||
check_has_camera, |
||||
toast_error, |
||||
display_error, |
||||
} from "../store"; |
||||
import { onDestroy, onMount, tick } from "svelte"; |
||||
|
||||
export let commits; |
||||
|
||||
const open_scanner = () => { |
||||
push("#/scanqr"); |
||||
}; |
||||
|
||||
let container: HTMLElement; |
||||
let has_camera = false; |
||||
let has_name = undefined; |
||||
let has_email = undefined; |
||||
|
||||
async function scrollToTop() { |
||||
await tick(); |
||||
if (container) container.scrollIntoView(); |
||||
} |
||||
onMount(async () => { |
||||
if (!$active_session) { |
||||
push("#/"); |
||||
return; |
||||
} |
||||
has_camera = await check_has_camera(); |
||||
console.log("has_camera",has_camera) |
||||
if ($scanned_qr_code) { |
||||
on_qr_scanned($scanned_qr_code); |
||||
scanned_qr_code.set(""); |
||||
} |
||||
await scrollToTop(); |
||||
|
||||
}); |
||||
|
||||
$: if (commits) { contained(commits.graph) } |
||||
|
||||
async function on_qr_scanned(text: string) { |
||||
try { |
||||
console.log("got QR",text, "did:ng:"+$cur_tab.doc.nuri); |
||||
await ng.import_contact_from_qrcode($active_session.session_id, "did:ng:"+$cur_tab.doc.nuri, text); |
||||
} catch (e) { |
||||
console.error(e) |
||||
toast_error(display_error(e)); |
||||
} |
||||
} |
||||
|
||||
function contained(graph) { |
||||
let ret = []; |
||||
for (const g of graph) { |
||||
if (g.substring(57,91) === "http://www.w3.org/2006/vcard/ns#fn") { |
||||
has_name = g.substring(94, g.length-1); |
||||
} else if (g.substring(57,97) === "http://www.w3.org/2006/vcard/ns#hasEmail") { |
||||
has_email = g.substring(100, g.length-1); |
||||
} |
||||
} |
||||
ret.sort((a, b) => a.hash.localeCompare(b.hash)); |
||||
return ret; |
||||
} |
||||
|
||||
async function test() { |
||||
if (!has_camera) { |
||||
await on_qr_scanned("AgBPtkD9jg11uDj7FTK0VqWb_aVxYvoyjFyIWs5VwCOICwAAABsxv_FXViA-5LUMNjARLJCiS3nOc7WYdoVQYgWn2ukcB25vIG5hbWUBDmZha2VAZW1haWwuY29t"); |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
<div class="flex-col p-5" bind:this={container}> |
||||
{#if !has_camera && !has_name} |
||||
<Alert class="m-2" color="red">No camera available. You cannot import with QR-code</Alert> |
||||
{/if} |
||||
{#if !has_name} |
||||
<Button |
||||
on:click={test} |
||||
on:keypress={open_scanner} |
||||
class="select-none ml-2 mt-2 mb-2 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
> |
||||
<QrCode tabindex="-1" class="mr-2 focus:outline-none" /> |
||||
Import with QR-code |
||||
</Button><br/> |
||||
{/if} |
||||
Name: {has_name || ""}<br/> |
||||
{#if has_email} |
||||
Email: {has_email}<br/> |
||||
{/if} |
||||
</div> |
@ -0,0 +1,88 @@ |
||||
<!-- |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||
// All rights reserved. |
||||
// Licensed under the Apache License, Version 2.0 |
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0> |
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
||||
// at your option. All files in the project carrying such |
||||
// notice may not be copied, modified, or distributed except |
||||
// according to those terms. |
||||
--> |
||||
|
||||
<script lang="ts"> |
||||
|
||||
import ng from "../api"; |
||||
import { link } from "svelte-spa-router"; |
||||
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; |
||||
import{ PlusCircle } from "svelte-heros-v2"; |
||||
import { t } from "svelte-i18n"; |
||||
import { |
||||
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab |
||||
} from "../tab"; |
||||
import DataClassIcon from "../lib/icons/DataClassIcon.svelte"; |
||||
import { |
||||
openModalCreate, |
||||
sparql_query, |
||||
active_session |
||||
} from "../store"; |
||||
import { |
||||
Clipboard |
||||
} from "svelte-heros-v2"; |
||||
|
||||
export let commits; |
||||
|
||||
function contained(graph) { |
||||
let ret = []; |
||||
for (const g of graph) { |
||||
if (g.substring(57,90) === "http://www.w3.org/ns/ldp#contains") { |
||||
let nuri = g.substring(93,146); |
||||
let repo = nuri; |
||||
nuri = nuri + ":" + $cur_tab.store.overlay; |
||||
let hash = nuri.substring(9,16); |
||||
ret.push({nuri,hash,repo}); |
||||
} |
||||
} |
||||
ret.sort((a, b) => a.hash.localeCompare(b.hash)); |
||||
return ret; |
||||
} |
||||
|
||||
async function fetch_header(repo) { |
||||
try { |
||||
let res = await ng.fetch_header($active_session.session_id, repo); |
||||
return res; |
||||
}catch(e){ |
||||
console.error(e); |
||||
return {}; |
||||
} |
||||
} |
||||
|
||||
const create = () => { |
||||
openModalCreate(); |
||||
} |
||||
const config = { |
||||
class: "mr-2 w-6 h-6 shrink-0 focus:outline-none" |
||||
} |
||||
|
||||
</script> |
||||
<div class="flex-col p-5"> |
||||
{#each contained(commits.graph) as doc} |
||||
{#await fetch_header(doc.repo)} |
||||
<div class="flex"> <Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/><div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div> </div> |
||||
{:then header} |
||||
<div class="flex" title="{header.about || ''}"> {#if header.class}<DataClassIcon {config} dataClass={header.class}/>{:else}<Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/>{/if}<div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{header.title || doc.hash}</a> </div></div> |
||||
{/await} |
||||
{/each} |
||||
{#if commits.graph.length == 0 || contained(commits.graph).length == 0} |
||||
<p>{$t("doc.empty_container")}</p> |
||||
{#if $cur_tab_doc_can_edit} |
||||
<button |
||||
on:click={create} |
||||
on:keypress={create} |
||||
class="select-none ml-0 mt-2 mb-10 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
> |
||||
<PlusCircle tabindex="-1" class="mr-2 focus:outline-none" /> |
||||
{$t("doc.create")} |
||||
</button> |
||||
{/if} |
||||
{/if} |
||||
</div> |
@ -0,0 +1,84 @@ |
||||
<!-- |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||
// All rights reserved. |
||||
// Licensed under the Apache License, Version 2.0 |
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0> |
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
||||
// at your option. All files in the project carrying such |
||||
// notice may not be copied, modified, or distributed except |
||||
// according to those terms. |
||||
--> |
||||
|
||||
<script lang="ts"> |
||||
|
||||
import ng from "../api"; |
||||
import { link, push } from "svelte-spa-router"; |
||||
import { onDestroy, onMount, tick } from "svelte"; |
||||
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; |
||||
import{ PlusCircle, ArrowLeft } from "svelte-heros-v2"; |
||||
|
||||
import { t } from "svelte-i18n"; |
||||
import { |
||||
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab |
||||
} from "../tab"; |
||||
import { |
||||
openModalCreate, |
||||
sparql_query, |
||||
active_session |
||||
} from "../store"; |
||||
|
||||
|
||||
export let commits; |
||||
|
||||
let container: HTMLElement; |
||||
let generation_state: "before_start" | "loading" | "generated" = |
||||
"before_start"; |
||||
let generated_qr: string | undefined = undefined; |
||||
|
||||
async function scrollToTop() { |
||||
await tick(); |
||||
container.scrollIntoView(); |
||||
} |
||||
|
||||
onMount(async () => { |
||||
if (!$active_session) { |
||||
push("#/"); |
||||
return; |
||||
} |
||||
await scrollToTop(); |
||||
await generate_qr_code(); |
||||
}); |
||||
|
||||
async function generate_qr_code() { |
||||
generation_state = "loading"; |
||||
console.log(container.clientWidth); |
||||
generated_qr = await ng.get_qrcode_for_profile( |
||||
$active_session.session_id, |
||||
$cur_tab.store.store_type == "public", // are we public or protected? |
||||
Math.min(container.clientWidth, 800) |
||||
); |
||||
generation_state = "generated"; |
||||
} |
||||
|
||||
function back_to_profile_viewer() { |
||||
set_viewer("n:g:z:profile"); |
||||
} |
||||
|
||||
</script> |
||||
<div class="flex-col" bind:this={container}> |
||||
{#if generation_state == "generated"} |
||||
<div class="mx-auto"> |
||||
{@html generated_qr} |
||||
</div> |
||||
|
||||
<button |
||||
on:click={back_to_profile_viewer} |
||||
on:keypress={back_to_profile_viewer} |
||||
class="select-none mx-6 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
><ArrowLeft |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/>{$t("buttons.back")}</button |
||||
> |
||||
{/if} |
||||
</div> |
@ -0,0 +1,88 @@ |
||||
<!-- |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||
// All rights reserved. |
||||
// Licensed under the Apache License, Version 2.0 |
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0> |
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
||||
// at your option. All files in the project carrying such |
||||
// notice may not be copied, modified, or distributed except |
||||
// according to those terms. |
||||
--> |
||||
|
||||
<script lang="ts"> |
||||
|
||||
import ng from "../api"; |
||||
import { link } from "svelte-spa-router"; |
||||
import { Button, Progressbar, Spinner, Alert } from "flowbite-svelte"; |
||||
import{ PlusCircle } from "svelte-heros-v2"; |
||||
import { t } from "svelte-i18n"; |
||||
import { |
||||
in_memory_discrete, open_viewer, set_viewer, set_editor, set_view_or_edit, cur_tab_branch_class, cur_tab_doc_can_edit, cur_tab |
||||
} from "../tab"; |
||||
import DataClassIcon from "../lib/icons/DataClassIcon.svelte"; |
||||
import { |
||||
openModalCreate, |
||||
sparql_query, |
||||
active_session |
||||
} from "../store"; |
||||
import { |
||||
Clipboard |
||||
} from "svelte-heros-v2"; |
||||
|
||||
export let commits; |
||||
|
||||
function contained(graph) { |
||||
let ret = []; |
||||
for (const g of graph) { |
||||
if (g.substring(57,90) === "http://www.w3.org/ns/ldp#contains") { |
||||
let nuri = g.substring(93,146); |
||||
let repo = nuri; |
||||
nuri = nuri + ":" + $cur_tab.store.overlay; |
||||
let hash = nuri.substring(9,16); |
||||
ret.push({nuri,hash,repo}); |
||||
} |
||||
} |
||||
ret.sort((a, b) => a.hash.localeCompare(b.hash)); |
||||
return ret; |
||||
} |
||||
|
||||
async function fetch_header(repo) { |
||||
try { |
||||
let res = await ng.fetch_header($active_session.session_id, repo); |
||||
return res; |
||||
}catch(e){ |
||||
console.error(e); |
||||
return {}; |
||||
} |
||||
} |
||||
|
||||
const create = () => { |
||||
openModalCreate(); |
||||
} |
||||
const config = { |
||||
class: "mr-2 w-6 h-6 shrink-0 focus:outline-none" |
||||
} |
||||
|
||||
</script> |
||||
<div class="flex-col p-5"> |
||||
{#each contained(commits.graph) as doc} |
||||
{#await fetch_header(doc.repo)} |
||||
<div class="flex"> <Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/><div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{doc.hash}</a> </div> </div> |
||||
{:then header} |
||||
<div class="flex" title="{header.about || ''}"> {#if header.class}<DataClassIcon {config} dataClass={header.class}/>{:else}<Clipboard tabindex="-1" class="mr-2 w-6 h-6 shrink-0 focus:outline-none"/>{/if}<div class="flex font-mono mb-3"> <a use:link href="/{doc.nuri}">{header.title || doc.hash}</a> </div></div> |
||||
{/await} |
||||
{/each} |
||||
{#if commits.graph.length == 0 || contained(commits.graph).length == 0} |
||||
<p>{$t("doc.empty_container")}</p> |
||||
{#if $cur_tab_doc_can_edit} |
||||
<button |
||||
on:click={create} |
||||
on:keypress={create} |
||||
class="select-none ml-0 mt-2 mb-10 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
> |
||||
<PlusCircle tabindex="-1" class="mr-2 focus:outline-none" /> |
||||
{$t("doc.create")} |
||||
</button> |
||||
{/if} |
||||
{/if} |
||||
</div> |
Loading…
Reference in new issue