wip content index

This commit is contained in:
2024-10-01 22:31:07 +03:00
parent 39e7a3aed4
commit fa388ea302
21 changed files with 356 additions and 22 deletions
+10
View File
@@ -45,5 +45,15 @@ return [
\Lucent\Schema\Ui\Slug::class, \Lucent\Schema\Ui\Slug::class,
\Lucent\Schema\Ui\Text::class, \Lucent\Schema\Ui\Text::class,
\Lucent\Schema\Ui\Textarea::class \Lucent\Schema\Ui\Textarea::class
],
"renderers" => [
"row" => [
"file" => \Lucent\Schema\Renderer\Row\File::class,
"slug" => \Lucent\Schema\Renderer\Row\Text::class,
"text" => \Lucent\Schema\Renderer\Row\Text::class,
"checkbox" => \Lucent\Schema\Renderer\Row\Text::class,
"number" => \Lucent\Schema\Renderer\Row\Text::class,
"rich" => \Lucent\Schema\Renderer\Row\Text::class,
]
] ]
]; ];
+4
View File
@@ -6,10 +6,14 @@ import Mustache from "mustache";
import 'htmx.org'; import 'htmx.org';
import {dropdown} from "./components/dropdown.js"; import {dropdown} from "./components/dropdown.js";
import {colorPicker} from "./recordEditor/colorPicker.js"; import {colorPicker} from "./recordEditor/colorPicker.js";
import {sortReferences} from "./recordEditor/sortReferences.js";
import {recordDialog} from "./recordEditor/recordDialog.js";
addEventListener("load", (event) => { addEventListener("load", (event) => {
dropdown() dropdown()
colorPicker() colorPicker()
sortReferences()
recordDialog()
}); });
Mustache.escape = function (value) { Mustache.escape = function (value) {
+32
View File
@@ -0,0 +1,32 @@
import axios from "axios";
export function recordDialog() {
document.querySelectorAll("[data-open-modal]").forEach(el => {
const schema = el.dataset.openModal
el.addEventListener("click", e => {
load(schema)
})
})
}
function load(schema) {
axios
.get("/lucent/content/" + schema)
.then((response) => {
const dialogWrapperEl = document.createElement("div");
dialogWrapperEl.innerHTML = response.data;
document.body.appendChild(dialogWrapperEl);
const dialogEl = dialogWrapperEl.querySelector("dialog");
dialogEl.showModal();
dialogWrapperEl.querySelector(".close").addEventListener("click", e => dialogEl.close());
dialogEl.addEventListener("close", (event) => {
dialogWrapperEl.remove();
});
})
.catch((error) => console.log(error));
}
+19
View File
@@ -0,0 +1,19 @@
import Sortable from "sortablejs";
export function sortReferences() {
document.querySelectorAll(".color-picker").forEach(el => {
let options = {
animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
easing: "cubic-bezier(1, 0, 0, 1)",
direction: 'vertical',
onUpdate: function (/**Event*/ evt) {
// dispatch("update", {
// source: evt.oldIndex,
// target: evt.newIndex,
// });
}
};
Sortable.create(el, options);
})
}
+2 -1
View File
@@ -11,7 +11,8 @@
/* max-width: 128px; */ /* max-width: 128px; */
max-height: 24px; max-height: 24px;
text-overflow: ellipsis; text-overflow: ellipsis;
/* white-space: nowrap; */
overflow: hidden; overflow: hidden;
/* white-space: nowrap; */
} }
</style> </style>
+5 -1
View File
@@ -55,7 +55,11 @@
border: none; border: none;
overflow: hidden; overflow: hidden;
&.field-ui-number,&.field-ui-slug,&.field-ui-text,&.field-ui-rich,&.field-ui-url{
max-height: 24px;
text-overflow: ellipsis;
overflow: hidden;
}
//img{ //img{
// width: 48px; // width: 48px;
//} //}
+2 -2
View File
@@ -28,7 +28,7 @@
return strtoupper($segs[0][0]).strtoupper($segs[0][1]); return strtoupper($segs[0][0]).strtoupper($segs[0][1]);
}; };
$name = $user["name"]; $name = (string)data_get($user,"name");
$charIndex = ord($name[1]) + strlen($name); $charIndex = ord($name[1]) + strlen($name);
$colorIndex = $charIndex % 19; $colorIndex = $charIndex % 19;
$bgColor = $colors[$colorIndex]; $bgColor = $colors[$colorIndex];
@@ -39,5 +39,5 @@
title="{{$name}}" title="{{$name}}"
style="background-color:{{$bgColor}};height: {{$side}}px;width: {{$side}}px; font-size:{{$side / 2}}px" style="background-color:{{$bgColor}};height: {{$side}}px;width: {{$side}}px; font-size:{{$side / 2}}px"
> >
<div class="avatar__letters">{{$initials($user["name"])}}</div> <div class="avatar__letters">{{$initials($name)}}</div>
</div> </div>
@@ -0,0 +1,3 @@
<div class="checkbox-wrapper">
<input id="c1-13" type="checkbox" value="{{$value}}" {{$indeterminate ?? false ? "indeterminate" : ""}} {{$checked ?? false ? "checked" : ""}} />
</div>
@@ -0,0 +1,42 @@
<dialog id="dialog-{{$schema->name}}">
@if($schema)
<div class="dialog-header">
<button
type="button"
class="button"
disabled
>
Insert
</button>
<button
type="button"
class="button"
disabled
>
Replace
</button>
<div class="hide">
<span class="number-of-records-selected"></span> records selected
</div>
<button
type="button"
class="button close"
aria-label="Close"
>
<x-lucent::icon icon="close">
</x-lucent::icon>
</button>
</div>
<div class="dialog-body">
@include("lucent::records.index")
</div>
@endif
</dialog>
@@ -18,5 +18,6 @@
@include("lucent::records-editor.fields", ["field" => $field]) @include("lucent::records-editor.fields", ["field" => $field])
@endforeach @endforeach
</div> </div>
@endsection @endsection
@@ -1,16 +1,31 @@
@php @php
$references = $graph->edges $references = $graph->edges
->filter(fn($edge) => $edge->field === $field->name && $edge->source === $record->id) ->filter(fn($edge) => $edge->field === $field->name && $edge->source === $record->id)
->map(fn($edge) => $graph->records->firstWhere("id", $edge->target)); ->map(fn($edge) => $graph->records->firstWhere("id", $edge->target));
$collectionSchemas = $schemas->whereIn("name",$field->collections);
@endphp @endphp
@if ($references->isNotEmpty()) @if(count($field->collections) === 1)
{{--<Sortable sortableClass="mt-3" on:update={reorder}>--}} <button class="button" data-open-modal="{{$field->collections[0]}}">Browse</button>
@foreach($references as $reference) @else
<!--This div helps the sorting thing--> <x-lucent::dropdown>
<div> Browse
@include("lucent::records-editor.fields.file.preview") <x-slot:items>
</div> @foreach($collectionSchemas as $collectionSchema)
@endforeach <a class="dropdown-item" data-open-modal="{{$collectionSchema->name}}" href="/">{{$collectionSchema->label}}</a>
<!--</Sortable>--> @endforeach
</x-slot:items>
</x-lucent::dropdown>
@endif
@if ($references->isNotEmpty())
<div class="sortable-container mt-3">
@foreach($references as $reference)
<!--This div helps the sorting thing-->
<div>
@include("lucent::records-editor.fields.file.preview", ["record" => $reference])
</div>
@endforeach
</div>
@endif @endif
@@ -1,16 +1,17 @@
@php @php
$schema = $channel->schemas->firstWhere("name",$reference->schema); $reference = $record;
$schema = $channel->schemas->firstWhere("name",$record->schema);
@endphp @endphp
<div class="preview-file"> <div class="preview-file">
<div style="display: flex;align-items: center;gap: 10px;"> <div style="display: flex;align-items: center;gap: 10px;">
<div class="image"> <div class="image">
@include("lucent::records-editor.fields.file.thumb", ["size" => "small", "record" => $reference]) @include("lucent::records-editor.fields.file.thumb", ["size" => "small"])
</div> </div>
<div class="title"> <div class="title">
<div> <div>
<a class="record-title" href="{{lucent_url("records")}}/{{$record->id}}"> <a class="record-title" href="{{lucent_url("records")}}/{{$record->id}}">
{{$viewModel->getRecordName($reference)}} {{$viewModel->getRecordName($record)}}
</a> </a>
<small class="d-block"> <small class="d-block">
from {{$schema->label}} from {{$schema->label}}
+36
View File
@@ -0,0 +1,36 @@
<div class="">
<div class="{{$inModal ? 'mt-0' : 'mt-5'}}">
<h3 class="header-normal mb-5 ">
{{$schema->label}}
</h3>
{{-- {#if selected.length > 0 && !inModal && isWritable}--}}
{{-- <ActionsOnSelected {schema} {selected} {filter}/>--}}
{{-- {:else}--}}
{{-- <Tools--}}
{{-- bind:schema--}}
{{-- bind:records--}}
{{-- {systemFields}--}}
{{-- {sortParam}--}}
{{-- {sortField}--}}
{{-- {operators}--}}
{{-- {filter}--}}
{{-- {graph}--}}
{{-- {inModal}--}}
{{-- {modalUrl}--}}
{{-- {isWritable}--}}
{{-- on:refresh={refresh}--}}
{{-- />--}}
{{-- {/if}--}}
@include("lucent::records.table")
</div>
{{-- <Pagination--}}
{{-- {limit}--}}
{{-- {skip}--}}
{{-- {total}--}}
{{-- on:refresh={refresh}--}}
{{-- {inModal}--}}
{{-- {modalUrl}--}}
{{-- />--}}
</div>
+7
View File
@@ -0,0 +1,7 @@
@extends("lucent::layouts.channel")
@section("content")
@include("lucent::records.index")
@endsection
+14
View File
@@ -0,0 +1,14 @@
@foreach($schema->visible as $visibleColumn)
@php
$schemaField = $schema->fields->firstWhere("name", $visibleColumn);
@endphp
<td class="field-ui-{{$schemaField->info->name ?? $visibleColumn}} {{$visibleColumn === $sortField->name ? "is-sort" : ""}}">
@if(in_array($visibleColumn ,["_sys.createdBy","_sys.updatedBy"]))
<x-lucent::avatar side="24" :user="$users->firstWhere('id',$record->_sys->createdBy)"></x-lucent::avatar>
@elseif($visibleColumn === "_sys.status")
@include("lucent::records-editor.status",[ "status" => $record->status])
@else
{!! $viewModel->renderRow($record,$schemaField)!!}
@endif
</td>
@endforeach
+91
View File
@@ -0,0 +1,91 @@
@php
@endphp
<div class="table mt-5 ">
<table>
<thead>
<tr>
@if($isWritable)
<th>
<x-lucent::checkbox value=""></x-lucent::checkbox>
</th>
@endif
@foreach($schema->visible as $visibleColumn)
@php
$schemaField = $schema->fields->firstWhere("name", $visibleColumn);
if(empty($schemaField)){
$schemaField = collect($systemFields)->firstWhere("name", str_replace("_sys.", "",$visibleColumn) );
}
@endphp
<th
class="field-ui-{{$schemaField->info->name ?? $schemaField->ui}} {{$schemaField->name === $sortField->name ? "is-sort" : ""}}"
scope="col"
title={{$schemaField->help ?? ""}}
>{{$schemaField->label}}</th
>
@endforeach
<th></th>
</tr>
</thead>
<tbody>
@foreach($records as $record)
<tr>
<td class="title-td">
<div
class="title-td-contents"
>
@if($isWritable)
<x-lucent::checkbox :value="$record->id"></x-lucent::checkbox>
@endif
@if($record->_file?->path)
<div class="file-table-row">
@include("lucent::records-editor.fields.file.thumb", ["size" => "small"])
<div>
@if($record->status === "draft")
<span style="text-transform: uppercase;font-size:10px">{{$record->status}}</span>
@endif
<a
href="{{lucent_url("records")}}/{{$record->id}}"
target={{$inModal ? "_blank" : "_self"}}
>
{{ $viewModel->getRecordName($record)}}
</a>
<span>{{ (int)($record->_file->size / 1024) }}kB</span>
@if($record->_file->width > 0)
<span>{{$record->_file->width . "x" . $record->_file->height}}</span>
@endif
<a
href="{{lucent_file($record)}}"
target="_blank"
>
Download
</a>
</div>
</div>
@else
<a
href="{{lucent_url("records")}}/{{$record->id}}"
target={{$inModal ? "_blank" : "_self"}}
>
@if($record->status === "draft")
<span style="text-transform: uppercase;font-size:10px">{{$record->status}}</span>
@endif
{{$viewModel->getRecordName($record)}}
</a>
@endif
</div>
</td>
@include("lucent::records.row")
<td>
<x-lucent::avatar side="24"
:user="$users->firstWhere('id',$record->_sys->createdBy)"></x-lucent::avatar>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
+5 -3
View File
@@ -79,14 +79,15 @@ class RecordController extends Controller
->runWithCount(); ->runWithCount();
$records = $graph->getRootRecords()->toArray();
$data = [ $data = [
"schemas" => $this->channelService->channel->schemas, "schemas" => $this->channelService->channel->schemas,
"schema" => $schema, "schema" => $schema,
"users" => $users, "users" => $users,
"records" => $records, "records" => $graph->tree(),
"graph" => toArray($graph), "graph" => toArray($graph),
"visibleFields" => array_values(System::list()),
"systemFields" => array_values(System::list()), "systemFields" => array_values(System::list()),
"operators" => $this->operatorRegistry->all(), "operators" => $this->operatorRegistry->all(),
"sortParam" => $sort, "sortParam" => $sort,
@@ -104,9 +105,10 @@ class RecordController extends Controller
if (str_starts_with(config("lucent.url"), "https")) { if (str_starts_with(config("lucent.url"), "https")) {
$data["modalUrl"] = str_replace("http://", "https://", $request->fullUrl()); $data["modalUrl"] = str_replace("http://", "https://", $request->fullUrl());
} }
return $data; return view("lucent::records-editor.dialog", $data)->render();
} }
$data["inModal"] = false; $data["inModal"] = false;
return view("lucent::records.list", $data);
return $this->svelte->render( return $this->svelte->render(
layout: "channel", layout: "channel",
view: "contentIndex", view: "contentIndex",
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace Lucent\Schema\Renderer\Row;
use Lucent\Record\QueryRecord;
use Lucent\Schema\FieldInterface;
class File implements IRowRenderer
{
public function __invoke(QueryRecord $record, FieldInterface $field): string
{
$reference = data_get($record,"_children.".$field->name);
if(!isset($reference[0])){
return "";
}
return view("lucent::records-editor.fields.file.thumb",["size" => "tiny", "record" => $reference[0]])->render();
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace Lucent\Schema\Renderer\Row;
use Lucent\Record\QueryRecord;
use Lucent\Schema\FieldInterface;
interface IRowRenderer
{
public function __invoke(QueryRecord $record, FieldInterface $field):string;
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace Lucent\Schema\Renderer\Row;
use Lucent\Record\QueryRecord;
use Lucent\Schema\FieldInterface;
class Text implements IRowRenderer
{
public function __invoke(QueryRecord $record, FieldInterface $field): string
{
return data_get($record,"data.".$field->name,"");
}
}
+7
View File
@@ -37,4 +37,11 @@ class ViewModel
$m = new Mustache_Engine(array('entity_flags' => ENT_QUOTES)); $m = new Mustache_Engine(array('entity_flags' => ENT_QUOTES));
return $m->render($schema->cardTitle, $record->data); return $m->render($schema->cardTitle, $record->data);
} }
public function renderRow(QueryRecord $record, FieldInterface $field): string
{
$renderers = config("lucent.renderers.row");
return (new $renderers[$field->info->name])($record, $field);
}
} }