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
-1
View File
@@ -1 +0,0 @@
LUCENT_AUTH=lucent // or lunar
-3
View File
@@ -1,13 +1,10 @@
<script> <script>
import RecordRow from "./RecordRow.svelte"; import RecordRow from "./RecordRow.svelte";
import { previewTitle } from "../records/Preview";
import { usernameById } from "../account/users"; import { usernameById } from "../account/users";
import { getContext } from "svelte"; import { getContext } from "svelte";
import Avatar from "../account/Avatar.svelte"; import Avatar from "../account/Avatar.svelte";
import { selectRecord, toggleAll } from "./functions/recordSelect.js"; import { selectRecord, toggleAll } from "./functions/recordSelect.js";
import Checkbox from "../common/Checkbox.svelte"; import Checkbox from "../common/Checkbox.svelte";
import Preview from "../files/Preview.svelte";
import { fileurl } from "../files/imageserver.js";
const channel = getContext("channel"); const channel = getContext("channel");
@@ -1,9 +1,7 @@
<script> <script>
import {createEventDispatcher, getContext} from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import {previewTitle} from "../../records/Preview";
import Icon from "../../common/Icon.svelte"; import Icon from "../../common/Icon.svelte";
const channel = getContext("channel");
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let schema; export let schema;
export let operators; export let operators;
@@ -19,13 +17,10 @@
isReference: key.startsWith("children"), isReference: key.startsWith("children"),
}; };
filter = [ filter = [extractOperator(key), extractLabel(schema, key)].reduce(
extractOperator(key), (mem, fn) => fn(mem),
extractLabel(schema, key), filter,
].reduce((mem, fn) => fn(mem), filter); );
function extractOperator(key) { function extractOperator(key) {
return (filter) => { return (filter) => {
@@ -50,18 +45,16 @@
const filterField = schema.fields.find((f) => f.name === fieldName); const filterField = schema.fields.find((f) => f.name === fieldName);
filter.label = filterField?.label ?? fieldName; filter.label = filterField?.label ?? fieldName;
return filter; return filter;
} };
} }
const filterRecord = extractFilterRecord(graph, value); const filterRecord = extractFilterRecord(graph, value);
function extractFilterRecord(graph, value) { function extractFilterRecord(graph, value) {
if (!filter.isReference) { if (!filter.isReference) {
return null; return null;
} }
return graph.records.find(r => r.id === value); return graph.records.find((r) => r.id === value);
} }
function removeFilter(k) { function removeFilter(k) {
@@ -78,19 +71,21 @@
</script> </script>
<span class="applied-filter"> <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} <button
{filter.label} is {previewTitle(channel.schemas, filterRecord)} on:click|preventDefault={() => removeFilter(key)}
{:else} type="button"
{filter.label} {operators.find((o) => o.name === filter.operator)?.symbol ?? ""} {operators.find((o) => o.name === filter.operator)?.hasValue ? value : ""} class="button-text"
{/if} 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> </span>
@@ -1,8 +1,6 @@
<script> <script>
import {createEventDispatcher, getContext} from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import {debounce} from "lodash"; import { debounce } from "lodash";
import {previewTitle} from "../../records/Preview";
const channel = getContext("channel"); const channel = getContext("channel");
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@@ -10,9 +8,8 @@
export let value = ""; export let value = "";
export let field; export let field;
let search = "" let search = "";
$: searchOptions = [] $: searchOptions = [];
const updateResults = debounce((e) => { const updateResults = debounce((e) => {
axios axios
@@ -35,46 +32,36 @@
function apply(e, newOption) { function apply(e, newOption) {
e.preventDefault(); e.preventDefault();
value = newOption.id value = newOption.id;
dispatch("addFilter"); dispatch("addFilter");
value = "" value = "";
} }
</script> </script>
<div class="reference-tags"> <div class="reference-tags">
<input <input
type="search" type="search"
on:keyup={updateResults} on:keyup={updateResults}
bind:value={search} bind:value={search}
placeholder={"Search for "+field.label} placeholder={"Search for " + field.label}
autocomplete="off" autocomplete="off"
/> />
<div class="reference-tags-results"> <div class="reference-tags-results">
{#if searchOptions} {#if searchOptions}
{#each searchOptions as option (option.id)} {#each searchOptions as option (option.id)}
<div <div
class="reference-tags-option" class="reference-tags-option"
role="button" role="button"
tabindex="0" tabindex="0"
on:click={(e) => apply(e, option)} on:click={(e) => apply(e, option)}
on:keypress={(e) => apply(e, option)} on:keypress={(e) => apply(e, option)}
> >
{previewTitle(channel.schemas, option)} {option.data.name}
</div> </div>
{:else} {:else}
<div <div class="start-typing">Start typing...</div>
class="start-typing">
Start typing...
</div>
{/each} {/each}
{/if} {/if}
</div> </div>
</div> </div>
+1 -2
View File
@@ -1,7 +1,6 @@
<script> <script>
import { formatDistanceToNow, parseJSON } from "date-fns"; import { formatDistanceToNow, parseJSON } from "date-fns";
import Avatar from "../account/Avatar.svelte"; import Avatar from "../account/Avatar.svelte";
import { previewTitle } from "../records/Preview";
import Preview from "../files/Preview.svelte"; import Preview from "../files/Preview.svelte";
import { usernameById } from "../account/users"; import { usernameById } from "../account/users";
import { getContext } from "svelte"; import { getContext } from "svelte";
@@ -25,7 +24,7 @@
<Preview {record} size="tiny" showFilename={true} /> <Preview {record} size="tiny" showFilename={true} />
{:else} {:else}
<a href="{channel.lucentUrl}/records/{record.id}"> <a href="{channel.lucentUrl}/records/{record.id}">
{previewTitle(channel.schemas, record, graph)} {record.data.name}
</a> </a>
{/if} {/if}
</div> </div>
+8 -8
View File
@@ -1,5 +1,4 @@
<script> <script>
import NavbarMenu from "./NavbarMenu.svelte";
import { getContext } from "svelte"; import { getContext } from "svelte";
export let schema; export let schema;
@@ -9,13 +8,14 @@
<div class="sidebar-top"> <div class="sidebar-top">
<a class="logo" href={channel.lucentUrl}>{channel.name}</a> <a class="logo" href={channel.lucentUrl}>{channel.name}</a>
<a class="nav-item" href="{channel.lucentUrl}/profile"> </a>
</div> </div>
<div class="sidebar"> <div class="sidebar">
<NavbarMenu {#each readableSchemas as aschema}
title="Content" <a
schemas={readableSchemas.filter((sc) => sc.isEntry)} class="sidebar-item"
{schema} class:active={aschema.name === schema?.name}
expanded={true} aria-current="page"
/> href="{channel.lucentUrl}/content/{aschema.name}">{aschema.label}</a
>
{/each}
</div> </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> <script>
import {previewTitle} from "./Preview"; import { getContext } from "svelte";
import {getContext} from "svelte";
const channel = getContext("channel"); const channel = getContext("channel");
export let record; export let record;
export let graph; $: title = record.data.name;
$: schema = channel.schemas.find((aschema) => aschema.name === record.schema);
$: title = previewTitle(channel.schemas, record, graph);
</script> </script>
{#if record?.data} {#if record?.data}
<a <a href="{channel.lucentUrl}/records/{record.id}" {title} class="reference">
href="{channel.lucentUrl}/records/{record.id}"
{title}
class="reference"
>
{title} {title}
</a> </a>
{/if} {/if}
@@ -1,9 +1,8 @@
<script> <script>
import {getContext} from "svelte"; import { getContext } from "svelte";
import {debounce} from "lodash"; import { debounce } from "lodash";
import {previewTitle} from "../Preview"; import { getErrorMessage } from "./errorMessage";
import {getErrorMessage} from "./errorMessage"; import { insertEdges } from "./reference.js";
import {insertEdges} from "./reference.js";
import Icon from "../../common/Icon.svelte"; import Icon from "../../common/Icon.svelte";
const channel = getContext("channel"); const channel = getContext("channel");
@@ -15,20 +14,24 @@
export let validationErrors; export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name); $: errorMessage = getErrorMessage(validationErrors, field.name);
$: references = graph.edges $: references =
.filter((edge) => edge.field === field.name) graph.edges
.map((edge) => { .filter((edge) => edge.field === field.name)
return graph.records.find((increc) => increc.id == edge.target && record.id == edge.source); .map((edge) => {
}).filter((rec) => (rec?.id ? true : false)) ?? []; return graph.records.find(
(increc) =>
let search = "" increc.id == edge.target && record.id == edge.source,
$: searchOptions = [] );
})
.filter((rec) => (rec?.id ? true : false)) ?? [];
let search = "";
$: searchOptions = [];
function removeReference(e, recordId) { function removeReference(e, recordId) {
e.preventDefault(); e.preventDefault();
graph.edges = graph.edges.filter( 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], schema: field.collections[0],
status: "published", status: "published",
data: { data: {
[field.searchField]: newValue [field.searchField]: newValue,
} },
}, },
}) })
.then((response) => { .then((response) => {
searchOptions = []; searchOptions = [];
insert(e, response.data.records[0]); insert(e, response.data.records[0]);
console.log(response) console.log(response);
}) })
.catch((error) => { .catch((error) => {
searchOptions = []; searchOptions = [];
@@ -58,10 +61,16 @@
function insert(e, insertRecord) { function insert(e, insertRecord) {
e.preventDefault(); e.preventDefault();
graph = insertEdges(graph, record, [insertRecord], field.name, e.detail.action); graph = insertEdges(
search = "" graph,
searchEl.focus() record,
searchEl.blur() [insertRecord],
field.name,
e.detail.action,
);
search = "";
searchEl.focus();
searchEl.blur();
} }
const updateResults = debounce((e) => { const updateResults = debounce((e) => {
@@ -82,9 +91,8 @@
console.log(error); console.log(error);
}); });
}, 500); }, 500);
</script> </script>
<div class="reference-tags"> <div class="reference-tags">
{#if errorMessage} {#if errorMessage}
<div class="invalid-feedback d-block mb-3"> <div class="invalid-feedback d-block mb-3">
@@ -93,44 +101,39 @@
{/if} {/if}
<input <input
type="search" type="search"
bind:this={searchEl} bind:this={searchEl}
{id} {id}
on:keyup={updateResults} on:keyup={updateResults}
class:is-invalid={errorMessage} class:is-invalid={errorMessage}
bind:value={search} bind:value={search}
placeholder={"Search for "+field.label} placeholder={"Search for " + field.label}
autocomplete="off" autocomplete="off"
/> />
<div class="reference-tags-results"> <div class="reference-tags-results">
{#if searchOptions} {#if searchOptions}
{#each searchOptions as option (option.id)} {#each searchOptions as option (option.id)}
<div <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" class="reference-tags-option"
role="button" role="button"
tabindex="0" tabindex="0"
on:click={(e) => saveNew(e,search)} on:click={(e) => insert(e, option)}
on:keypress={(e) => saveNew(e,search)} 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}" Add "{search}"
</div> </div>
@@ -142,26 +145,23 @@
<div style="display: flex;align-items: center;gap: 4px"> <div style="display: flex;align-items: center;gap: 4px">
{#each references as record (record.id)} {#each references as record (record.id)}
<span class="reference-tags-selected-value"> <span class="reference-tags-selected-value">
<a <a
class="record-title" class="record-title"
href="{channel.lucentUrl}/records/{record.id}" href="{channel.lucentUrl}/records/{record.id}"
> >
{previewTitle(channel.schemas, record)} {record.data.name}
</a> </a>
<button <button
on:click|preventDefault={(e) => removeReference(e, record.id)} on:click|preventDefault={(e) =>
type="button" removeReference(e, record.id)}
class="button-text" type="button"
aria-label="Close" class="button-text"
aria-label="Close"
> >
<Icon width={12} height={12} icon="close"></Icon> <Icon width={12} height={12} icon="close"></Icon>
</button> </button>
</span> </span>
{/each} {/each}
</div> </div>
{/if} {/if}
+5 -11
View File
@@ -1,27 +1,21 @@
<script> <script>
import {getContext} from "svelte"; import { getContext } from "svelte";
import {previewTitle} from "./../Preview";
const channel = getContext("channel"); const channel = getContext("channel");
export let schema; export let schema;
export let record; export let record;
export let isCreateMode; export let isCreateMode;
</script> </script>
<div class="record-header"> <div class="record-header">
<a class="schema-name" href="{channel.lucentUrl}/content/{schema.name}"
<a >{schema.label.toUpperCase()}</a
class="schema-name"
href="{channel.lucentUrl}/content/{schema.name}"
>{schema.label.toUpperCase()}</a
> >
<span class="record-title"> <span class="record-title">
{#if !isCreateMode} {#if !isCreateMode}
{previewTitle(channel.schemas, record)} {record.data.name}
{:else} {:else}
New Record New Record
{/if} {/if}
</span> </span>
</div>
</div>
@@ -3,9 +3,6 @@
import { createEventDispatcher, getContext } from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import Preview from "../../files/Preview.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"; import Dropdown from "../../common/Dropdown.svelte";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@@ -1,8 +1,7 @@
<script> <script>
import Icon from "../../common/Icon.svelte"; import Icon from "../../common/Icon.svelte";
import {createEventDispatcher, getContext} from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import {previewTitle} from "./../Preview";
import Status from "./../Status.svelte"; import Status from "./../Status.svelte";
import Preview from "../../files/Preview.svelte"; import Preview from "../../files/Preview.svelte";
@@ -12,10 +11,15 @@
export let record; export let record;
export let hasDelete = false; export let hasDelete = false;
let schema = channel.schemas.find((aschema) => aschema.name === record.schema); let schema = channel.schemas.find(
let cardTitle = previewTitle(channel.schemas, record, graph); (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); 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) { function remove(e) {
e.preventDefault(); e.preventDefault();
@@ -23,43 +27,35 @@
} }
</script> </script>
<div class="preview-reference"> <div class="preview-reference">
<div style="display: flex;align-items: center;gap: 10px;"> <div style="display: flex;align-items: center;gap: 10px;">
{#if cardImageRecord} {#if cardImageRecord}
<div class="image"> <div class="image">
<Preview record={cardImageRecord} size="small"/> <Preview record={cardImageRecord} size="small" />
</div> </div>
{/if} {/if}
<div class="title"> <div class="title">
<div> <div>
<a <a
class="record-title" class="record-title"
href="{channel.lucentUrl}/records/{record.id}" href="{channel.lucentUrl}/records/{record.id}"
> >
{cardTitle} {record.data.name}
</a> </a>
<small class="d-block"> <small class="d-block">
from {schema.label} from {schema.label}
{#if record.status === "draft"} {#if record.status === "draft"}
<Status status={record.status}/> <Status status={record.status} />
{/if} {/if}
</small> </small>
</div> </div>
</div> </div>
</div> </div>
{#if hasDelete} {#if hasDelete}
<div class="reference-action"> <div class="reference-action">
<button <button class="button" on:click={remove}>
class="button" <Icon icon="trash-can" />
on:click={remove}
>
<Icon icon="trash-can"/>
</button> </button>
</div> </div>
{/if} {/if}
</div> </div>
+2
View File
@@ -2,7 +2,9 @@
return [ return [
"env" => env("LUCENT_ENV", "production"), "env" => env("LUCENT_ENV", "production"),
// lucent or lunar
"auth" => env("LUCENT_AUTH", "lucent"), "auth" => env("LUCENT_AUTH", "lucent"),
"disk" => env("LUCENT_DISK", "public"),
"schemas_path" => env("LUCENT_SCHEMAS_PATH", "resources/lucent/schemas"), "schemas_path" => env("LUCENT_SCHEMAS_PATH", "resources/lucent/schemas"),
"database" => env("LUCENT_DB_CONNECTION", env("DB_CONNECTION", "sqlite")), "database" => env("LUCENT_DB_CONNECTION", env("DB_CONNECTION", "sqlite")),
"name" => env("LUCENT_NAME", "Lucent"), "name" => env("LUCENT_NAME", "Lucent"),
-3
View File
@@ -16,10 +16,7 @@ class Schema
public array $visible, public array $visible,
public array $groups, public array $groups,
public Collection $fields, public Collection $fields,
public bool $isEntry = false,
public string $color = "",
public string $sortBy = "-_sys.updatedAt", public string $sortBy = "-_sys.updatedAt",
public ?string $cardTitle = null,
public ?string $cardImage = null, public ?string $cardImage = null,
public int $revisions = 0, public int $revisions = 0,
public array $read = [], public array $read = [],
+1 -3
View File
@@ -21,7 +21,6 @@ use Lucent\Schema\System;
use Lucent\Schema\Ui\Reference; use Lucent\Schema\Ui\Reference;
use Lucent\Schema\Validator\ValidatorException; use Lucent\Schema\Validator\ValidatorException;
use Lucent\Svelte\Svelte; use Lucent\Svelte\Svelte;
use Lucent\ViewModel\ViewModel;
use function Lucent\Response\fail; use function Lucent\Response\fail;
use function Lucent\Response\ok; use function Lucent\Response\ok;
@@ -36,7 +35,6 @@ class RecordController extends Controller
private readonly Query $query, private readonly Query $query,
private readonly Manager $recordManager, private readonly Manager $recordManager,
private readonly OperatorRegistry $operatorRegistry, private readonly OperatorRegistry $operatorRegistry,
private readonly ViewModel $viewModel,
) {} ) {}
public function index(Request $request) public function index(Request $request)
@@ -217,7 +215,7 @@ class RecordController extends Controller
$c[] = ""; $c[] = "";
} elseif (count($fieldRecords) === 1) { } elseif (count($fieldRecords) === 1) {
$c[] = data_get($fieldRecords, "0.id"); $c[] = data_get($fieldRecords, "0.id");
$c[] = $this->viewModel->getRecordName($fieldRecords[0]); $c[] = $fieldRecords[0]->data["name"];
} else { } else {
$c[] = collect($fieldRecords)->pluck("id")->join("::"); $c[] = collect($fieldRecords)->pluck("id")->join("::");
$c[] = collect($fieldRecords) $c[] = collect($fieldRecords)
-3
View File
@@ -8,7 +8,6 @@ use Illuminate\Support\Facades\View;
use Lucent\Account\AccountService; use Lucent\Account\AccountService;
use Lucent\Account\AuthService; use Lucent\Account\AuthService;
use Lucent\Channel\ChannelService; use Lucent\Channel\ChannelService;
use Lucent\ViewModel\ViewModel;
readonly class AuthMiddleware readonly class AuthMiddleware
{ {
@@ -16,7 +15,6 @@ readonly class AuthMiddleware
private AuthService $authService, private AuthService $authService,
private AccountService $accountService, private AccountService $accountService,
private ChannelService $channelService, private ChannelService $channelService,
private ViewModel $viewModel,
) {} ) {}
public function handle(Request $request, Closure $next) public function handle(Request $request, Closure $next)
@@ -38,7 +36,6 @@ readonly class AuthMiddleware
) )
->values(), ->values(),
); );
View::share("viewModel", $this->viewModel);
return $next($request); return $next($request);
} }
-33
View File
@@ -1,33 +0,0 @@
<?php
namespace Lucent\Schema;
use Lucent\Primitive\Collection;
class CollectionSchema implements Schema
{
public Type $type = Type::COLLECTION;
/**
* @param Collection<FieldInterface> $fields
* @param array<string> $visible
*/
function __construct(
public string $name,
public string $label,
public array $visible,
public array $groups,
public Collection $fields,
public bool $isEntry = false,
public string $color = "",
public string $sortBy = "-_sys.updatedAt",
public ?string $cardTitle = null,
public ?string $cardImage = null,
public int $revisions = 0,
public array $read = [],
public array $write = [],
)
{
}
}
-36
View File
@@ -1,36 +0,0 @@
<?php
namespace Lucent\Schema;
use Lucent\Primitive\Collection;
class FilesSchema implements Schema
{
public Type $type = Type::FILES;
/**
* @param Collection<FieldInterface> $fields
* @param array<string> $groups
*/
function __construct(
public string $name,
public string $label,
public Collection $fields,
public string $disk,
public string $path,
public array $groups,
public bool $isEntry = false,
public string $sortBy = "-_sys.updatedAt",
public string $color = "",
public ?string $cardTitle = null,
public ?string $cardImage = null,
public int $revisions = 0,
public array $read = [],
public array $write = [],
)
{
}
}
-9
View File
@@ -1,9 +0,0 @@
<?php
namespace Lucent\Schema;
interface Schema
{
}
-4
View File
@@ -31,11 +31,7 @@ class SchemaService
$this, $this,
"mapFields", "mapFields",
]), ]),
isEntry: $schemaArr["isEntry"] ?? false,
color: $schemaArr["color"] ?? "",
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt", sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
cardTitle: $schemaArr["titleTemplate"] ??
($schemaArr["cardTitle"] ?? null),
cardImage: $schemaArr["cardImage"] ?? null, cardImage: $schemaArr["cardImage"] ?? null,
revisions: $schemaArr["revisions"] ?? 0, revisions: $schemaArr["revisions"] ?? 0,
read: $schemaArr["read"] ?? [], read: $schemaArr["read"] ?? [],
+1 -1
View File
@@ -38,7 +38,7 @@ class Slug implements FieldInterface, RequiredInterface
$value = Str::slug($input[$this->source]); $value = Str::slug($input[$this->source]);
} }
$output[$this->name] = new Nullable( $output[$this->name] = Nullable::make(
$this->nullable, $this->nullable,
$value, $value,
"", "",
-40
View File
@@ -1,40 +0,0 @@
<?php
namespace Lucent\ViewModel;
use Lucent\Channel\ChannelService;
use Lucent\Record\QueryRecord;
use Lucent\Schema\CollectionSchema;
use Lucent\Schema\FieldInterface;
use Lucent\Schema\FilesSchema;
use Mustache_Engine;
class ViewModel
{
public function __construct(
public ChannelService $channelService
)
{
}
public function getRecordName(QueryRecord $record): string
{
$schema = $this->channelService->getSchema($record->schema)->get();
if (empty($schema->cardTitle)) {
$title = match (get_class($schema)) {
CollectionSchema::class => $record->data[$schema->fields->filter(fn(FieldInterface $f) => $f->info->name === "text")->first()->name],
FilesSchema::class => $record->_file->path,
};
if (empty(trim($title))) {
return "~Untitled~";
}
return $title;
}
$m = new Mustache_Engine(array('entity_flags' => ENT_QUOTES));
return $m->render($schema->cardTitle, $record->data);
}
}