This commit is contained in:
2026-05-06 21:43:13 +03:00
parent 8b3a3964a5
commit 93a16ee916
23 changed files with 148 additions and 387 deletions
-3
View File
@@ -1,13 +1,10 @@
<script>
import RecordRow from "./RecordRow.svelte";
import { previewTitle } from "../records/Preview";
import { usernameById } from "../account/users";
import { getContext } from "svelte";
import Avatar from "../account/Avatar.svelte";
import { selectRecord, toggleAll } from "./functions/recordSelect.js";
import Checkbox from "../common/Checkbox.svelte";
import Preview from "../files/Preview.svelte";
import { fileurl } from "../files/imageserver.js";
const channel = getContext("channel");
@@ -1,9 +1,7 @@
<script>
import {createEventDispatcher, getContext} from "svelte";
import {previewTitle} from "../../records/Preview";
import { createEventDispatcher, getContext } from "svelte";
import Icon from "../../common/Icon.svelte";
const channel = getContext("channel");
const dispatch = createEventDispatcher();
export let schema;
export let operators;
@@ -19,13 +17,10 @@
isReference: key.startsWith("children"),
};
filter = [
extractOperator(key),
extractLabel(schema, key),
].reduce((mem, fn) => fn(mem), filter);
filter = [extractOperator(key), extractLabel(schema, key)].reduce(
(mem, fn) => fn(mem),
filter,
);
function extractOperator(key) {
return (filter) => {
@@ -50,18 +45,16 @@
const filterField = schema.fields.find((f) => f.name === fieldName);
filter.label = filterField?.label ?? fieldName;
return filter;
}
};
}
const filterRecord = extractFilterRecord(graph, value);
function extractFilterRecord(graph, value) {
if (!filter.isReference) {
return null;
}
return graph.records.find(r => r.id === value);
return graph.records.find((r) => r.id === value);
}
function removeFilter(k) {
@@ -78,19 +71,21 @@
</script>
<span class="applied-filter">
{#if filter.isReference && filterRecord}
{filter.label} is {filterRecord.data.name}
{:else}
{filter.label}
{operators.find((o) => o.name === filter.operator)?.symbol ?? ""}
{operators.find((o) => o.name === filter.operator)?.hasValue
? value
: ""}
{/if}
{#if filter.isReference && filterRecord}
{filter.label} is {previewTitle(channel.schemas, filterRecord)}
{:else}
{filter.label} {operators.find((o) => o.name === filter.operator)?.symbol ?? ""} {operators.find((o) => o.name === filter.operator)?.hasValue ? value : ""}
{/if}
<button
on:click|preventDefault={() => removeFilter(key)}
type="button"
class="button-text"
aria-label="Close"
><Icon width={12} height={12} icon="close"></Icon></button>
<button
on:click|preventDefault={() => removeFilter(key)}
type="button"
class="button-text"
aria-label="Close"
><Icon width={12} height={12} icon="close"></Icon></button
>
</span>
@@ -1,8 +1,6 @@
<script>
import {createEventDispatcher, getContext} from "svelte";
import {debounce} from "lodash";
import {previewTitle} from "../../records/Preview";
import { createEventDispatcher, getContext } from "svelte";
import { debounce } from "lodash";
const channel = getContext("channel");
const dispatch = createEventDispatcher();
@@ -10,9 +8,8 @@
export let value = "";
export let field;
let search = ""
$: searchOptions = []
let search = "";
$: searchOptions = [];
const updateResults = debounce((e) => {
axios
@@ -35,46 +32,36 @@
function apply(e, newOption) {
e.preventDefault();
value = newOption.id
value = newOption.id;
dispatch("addFilter");
value = ""
value = "";
}
</script>
<div class="reference-tags">
<input
type="search"
on:keyup={updateResults}
bind:value={search}
placeholder={"Search for "+field.label}
autocomplete="off"
type="search"
on:keyup={updateResults}
bind:value={search}
placeholder={"Search for " + field.label}
autocomplete="off"
/>
<div class="reference-tags-results">
{#if searchOptions}
{#each searchOptions as option (option.id)}
<div
class="reference-tags-option"
role="button"
tabindex="0"
on:click={(e) => apply(e, option)}
on:keypress={(e) => apply(e, option)}
class="reference-tags-option"
role="button"
tabindex="0"
on:click={(e) => apply(e, option)}
on:keypress={(e) => apply(e, option)}
>
{previewTitle(channel.schemas, option)}
{option.data.name}
</div>
{:else}
<div
class="start-typing">
Start typing...
</div>
<div class="start-typing">Start typing...</div>
{/each}
{/if}
</div>
</div>
+1 -2
View File
@@ -1,7 +1,6 @@
<script>
import { formatDistanceToNow, parseJSON } from "date-fns";
import Avatar from "../account/Avatar.svelte";
import { previewTitle } from "../records/Preview";
import Preview from "../files/Preview.svelte";
import { usernameById } from "../account/users";
import { getContext } from "svelte";
@@ -25,7 +24,7 @@
<Preview {record} size="tiny" showFilename={true} />
{:else}
<a href="{channel.lucentUrl}/records/{record.id}">
{previewTitle(channel.schemas, record, graph)}
{record.data.name}
</a>
{/if}
</div>
+8 -8
View File
@@ -1,5 +1,4 @@
<script>
import NavbarMenu from "./NavbarMenu.svelte";
import { getContext } from "svelte";
export let schema;
@@ -9,13 +8,14 @@
<div class="sidebar-top">
<a class="logo" href={channel.lucentUrl}>{channel.name}</a>
<a class="nav-item" href="{channel.lucentUrl}/profile"> </a>
</div>
<div class="sidebar">
<NavbarMenu
title="Content"
schemas={readableSchemas.filter((sc) => sc.isEntry)}
{schema}
expanded={true}
/>
{#each readableSchemas as aschema}
<a
class="sidebar-item"
class:active={aschema.name === schema?.name}
aria-current="page"
href="{channel.lucentUrl}/content/{aschema.name}">{aschema.label}</a
>
{/each}
</div>
-34
View File
@@ -1,34 +0,0 @@
<script>
import {getContext} from "svelte";
import Icon from "../common/Icon.svelte";
const channel = getContext("channel");
export let schemas;
export let title;
export let schema;
export let expanded = false;
if(schemas.find(s => s.name === schema?.name)){
expanded = true;
}
function toggleExpand(){
expanded = !expanded;
}
</script>
<button class="sidebar-header" tabindex="0" on:click={toggleExpand}>
{title}
{#if expanded}
<Icon icon="circle-chevron-up"></Icon>
{:else}
<Icon icon="circle-chevron-down"></Icon>
{/if}
</button>
{#if expanded}
{#each schemas as aschema}
<a class="sidebar-item" class:active={aschema.name === schema?.name}
aria-current="page"
href="{channel.lucentUrl}/content/{aschema.name}">{aschema.label}</a>
{/each}
{/if}
-33
View File
@@ -1,33 +0,0 @@
import Mustache from "mustache";
import { stripHtml } from "../../helpers";
export function previewTitle(schemas, record, graph) {
let schema = schemas.find((aSchema) => aSchema.name === record?.schema);
if (!schema?.cardTitle) {
return noTemplate(schema, record);
}
let recordData = record.data;
let render = Mustache.render(schema.cardTitle, recordData);
if (!render || render === "") {
return noTemplate(schema, record);
}
return stripHtml(render.slice(0, 300));
}
function noTemplate(schema, record) {
if (schema?.type === "files") {
return file.path;
}
let title = stripHtml(
record?.data[schema.fields.filter((f) => f.info.name === "text")[0]?.name],
).slice(0, 300);
if (title.trim() === "") {
return "~Untitled~";
}
return title;
}
@@ -1,21 +1,13 @@
<script>
import {previewTitle} from "./Preview";
import {getContext} from "svelte";
import { getContext } from "svelte";
const channel = getContext("channel");
export let record;
export let graph;
$: schema = channel.schemas.find((aschema) => aschema.name === record.schema);
$: title = previewTitle(channel.schemas, record, graph);
$: title = record.data.name;
</script>
{#if record?.data}
<a
href="{channel.lucentUrl}/records/{record.id}"
{title}
class="reference"
>
<a href="{channel.lucentUrl}/records/{record.id}" {title} class="reference">
{title}
</a>
{/if}
@@ -1,9 +1,8 @@
<script>
import {getContext} from "svelte";
import {debounce} from "lodash";
import {previewTitle} from "../Preview";
import {getErrorMessage} from "./errorMessage";
import {insertEdges} from "./reference.js";
import { getContext } from "svelte";
import { debounce } from "lodash";
import { getErrorMessage } from "./errorMessage";
import { insertEdges } from "./reference.js";
import Icon from "../../common/Icon.svelte";
const channel = getContext("channel");
@@ -15,20 +14,24 @@
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
$: references = graph.edges
.filter((edge) => edge.field === field.name)
.map((edge) => {
return graph.records.find((increc) => increc.id == edge.target && record.id == edge.source);
}).filter((rec) => (rec?.id ? true : false)) ?? [];
let search = ""
$: searchOptions = []
$: references =
graph.edges
.filter((edge) => edge.field === field.name)
.map((edge) => {
return graph.records.find(
(increc) =>
increc.id == edge.target && record.id == edge.source,
);
})
.filter((rec) => (rec?.id ? true : false)) ?? [];
let search = "";
$: searchOptions = [];
function removeReference(e, recordId) {
e.preventDefault();
graph.edges = graph.edges.filter(
(edge) => !(edge.target === recordId && edge.field === field.name)
(edge) => !(edge.target === recordId && edge.field === field.name),
);
}
@@ -41,14 +44,14 @@
schema: field.collections[0],
status: "published",
data: {
[field.searchField]: newValue
}
[field.searchField]: newValue,
},
},
})
.then((response) => {
searchOptions = [];
insert(e, response.data.records[0]);
console.log(response)
console.log(response);
})
.catch((error) => {
searchOptions = [];
@@ -58,10 +61,16 @@
function insert(e, insertRecord) {
e.preventDefault();
graph = insertEdges(graph, record, [insertRecord], field.name, e.detail.action);
search = ""
searchEl.focus()
searchEl.blur()
graph = insertEdges(
graph,
record,
[insertRecord],
field.name,
e.detail.action,
);
search = "";
searchEl.focus();
searchEl.blur();
}
const updateResults = debounce((e) => {
@@ -82,9 +91,8 @@
console.log(error);
});
}, 500);
</script>
<div class="reference-tags">
{#if errorMessage}
<div class="invalid-feedback d-block mb-3">
@@ -93,44 +101,39 @@
{/if}
<input
type="search"
bind:this={searchEl}
{id}
on:keyup={updateResults}
class:is-invalid={errorMessage}
bind:value={search}
placeholder={"Search for "+field.label}
autocomplete="off"
type="search"
bind:this={searchEl}
{id}
on:keyup={updateResults}
class:is-invalid={errorMessage}
bind:value={search}
placeholder={"Search for " + field.label}
autocomplete="off"
/>
<div class="reference-tags-results">
{#if searchOptions}
{#each searchOptions as option (option.id)}
<div
class="reference-tags-option"
role="button"
tabindex="0"
on:click={(e) => insert(e, option)}
on:keypress={(e) => insert(e, option)}
>
{previewTitle(channel.schemas, option ,graph)}
</div>
{:else}
<div
class="start-typing">
Start typing...
</div>
{/each}
{/if}
{#if search }
<div
class="reference-tags-option"
role="button"
tabindex="0"
on:click={(e) => saveNew(e,search)}
on:keypress={(e) => saveNew(e,search)}
on:click={(e) => insert(e, option)}
on:keypress={(e) => insert(e, option)}
>
{option.data.name}
</div>
{:else}
<div class="start-typing">Start typing...</div>
{/each}
{/if}
{#if search}
<div
class="reference-tags-option"
role="button"
tabindex="0"
on:click={(e) => saveNew(e, search)}
on:keypress={(e) => saveNew(e, search)}
>
Add "{search}"
</div>
@@ -142,26 +145,23 @@
<div style="display: flex;align-items: center;gap: 4px">
{#each references as record (record.id)}
<span class="reference-tags-selected-value">
<a
class="record-title"
href="{channel.lucentUrl}/records/{record.id}"
>
{previewTitle(channel.schemas, record)}
</a>
<a
class="record-title"
href="{channel.lucentUrl}/records/{record.id}"
>
{record.data.name}
</a>
<button
on:click|preventDefault={(e) => removeReference(e, record.id)}
type="button"
class="button-text"
aria-label="Close"
on:click|preventDefault={(e) =>
removeReference(e, record.id)}
type="button"
class="button-text"
aria-label="Close"
>
<Icon width={12} height={12} icon="close"></Icon>
</button>
<Icon width={12} height={12} icon="close"></Icon>
</button>
</span>
{/each}
</div>
{/if}
+5 -11
View File
@@ -1,27 +1,21 @@
<script>
import {getContext} from "svelte";
import {previewTitle} from "./../Preview";
import { getContext } from "svelte";
const channel = getContext("channel");
export let schema;
export let record;
export let isCreateMode;
</script>
<div class="record-header">
<a
class="schema-name"
href="{channel.lucentUrl}/content/{schema.name}"
>{schema.label.toUpperCase()}</a
<a class="schema-name" href="{channel.lucentUrl}/content/{schema.name}"
>{schema.label.toUpperCase()}</a
>
<span class="record-title">
{#if !isCreateMode}
{previewTitle(channel.schemas, record)}
{record.data.name}
{:else}
New Record
{/if}
</span>
</div>
</div>
@@ -3,9 +3,6 @@
import { createEventDispatcher, getContext } from "svelte";
import Preview from "../../files/Preview.svelte";
import { previewTitle } from "./../Preview";
import { fileurl, htmlurl } from "../../files/imageserver.js";
import Status from "./../Status.svelte";
import Dropdown from "../../common/Dropdown.svelte";
const dispatch = createEventDispatcher();
@@ -1,8 +1,7 @@
<script>
import Icon from "../../common/Icon.svelte";
import {createEventDispatcher, getContext} from "svelte";
import {previewTitle} from "./../Preview";
import { createEventDispatcher, getContext } from "svelte";
import Status from "./../Status.svelte";
import Preview from "../../files/Preview.svelte";
@@ -12,10 +11,15 @@
export let record;
export let hasDelete = false;
let schema = channel.schemas.find((aschema) => aschema.name === record.schema);
let cardTitle = previewTitle(channel.schemas, record, graph);
const cardImageEdge = graph.edges.find(e => e.source === record.id && e.field === schema.cardImage);
let cardImageRecord = graph.records.find(r => r.id === cardImageEdge?.target);
let schema = channel.schemas.find(
(aschema) => aschema.name === record.schema,
);
const cardImageEdge = graph.edges.find(
(e) => e.source === record.id && e.field === schema.cardImage,
);
let cardImageRecord = graph.records.find(
(r) => r.id === cardImageEdge?.target,
);
function remove(e) {
e.preventDefault();
@@ -23,43 +27,35 @@
}
</script>
<div class="preview-reference">
<div style="display: flex;align-items: center;gap: 10px;">
{#if cardImageRecord}
<div class="image">
<Preview record={cardImageRecord} size="small"/>
<Preview record={cardImageRecord} size="small" />
</div>
{/if}
<div class="title">
<div>
<a
class="record-title"
href="{channel.lucentUrl}/records/{record.id}"
class="record-title"
href="{channel.lucentUrl}/records/{record.id}"
>
{cardTitle}
{record.data.name}
</a>
<small class="d-block">
from {schema.label}
{#if record.status === "draft"}
<Status status={record.status}/>
<Status status={record.status} />
{/if}
</small>
</div>
</div>
</div>
{#if hasDelete}
<div class="reference-action">
<button
class="button"
on:click={remove}
>
<Icon icon="trash-can"/>
<button class="button" on:click={remove}>
<Icon icon="trash-can" />
</button>
</div>
{/if}
</div>