sidebar
This commit is contained in:
+2
-1
@@ -15,7 +15,8 @@
|
||||
"spatie/image-optimizer": "^1.6",
|
||||
"staudenmeir/laravel-cte": "^1.0",
|
||||
"ext-pdo": "*",
|
||||
"opis/json-schema": "^2.3"
|
||||
"opis/json-schema": "^2.3",
|
||||
"symfony/yaml": "^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.8"
|
||||
|
||||
Generated
+151
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "63bda0f783c53f088a85b8b35874ff00",
|
||||
"content-hash": "8a508d36870e3e47f5b756acc01e1458",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@@ -1906,6 +1906,85 @@
|
||||
],
|
||||
"time": "2023-05-23T14:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.28.0",
|
||||
@@ -2306,6 +2385,77 @@
|
||||
],
|
||||
"time": "2023-05-30T17:17:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v7.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "2d4fca631c00700597e9442a0b2451ce234513d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/2d4fca631c00700597e9442a0b2451ce234513d3",
|
||||
"reference": "2d4fca631c00700597e9442a0b2451ce234513d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<6.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^6.4|^7.0"
|
||||
},
|
||||
"bin": [
|
||||
"Resources/bin/yaml-lint"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Loads and dumps YAML files",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/yaml/tree/v7.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-23T15:02:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "voku/portable-ascii",
|
||||
"version": "2.0.1",
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
export let data;
|
||||
// export let layout;
|
||||
export let channel;
|
||||
|
||||
export let sidebar;
|
||||
export let axios;
|
||||
export let readableSchemas;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
</script>
|
||||
|
||||
<Navbar schema={data.schema}/>
|
||||
<Navbar {sidebar}/>
|
||||
|
||||
<svelte:component this={components[view]} {title} {...data}/>
|
||||
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
<script>
|
||||
import Avatar from "./account/Avatar.svelte";
|
||||
import NavbarMenu from "./NavbarMenu.svelte";
|
||||
import {getContext} from "svelte";
|
||||
|
||||
export let schema;
|
||||
export let sidebar;
|
||||
const channel = getContext("channel");
|
||||
const readableSchemas = getContext("readableSchemas");
|
||||
const user = getContext("user");
|
||||
|
||||
let contentIsOpen = false;
|
||||
const fileSchemas = readableSchemas.filter((sc) => sc.type === "files");
|
||||
const otherSchemas = readableSchemas.filter((sc) => !sc.isEntry && sc.type === "collection");
|
||||
|
||||
let filesIsActive = false;
|
||||
let otherIsActive = false;
|
||||
if(schema){
|
||||
filesIsActive = fileSchemas.filter(s => s.name === schema.name).length > 0;
|
||||
otherIsActive = otherSchemas.filter(s => s.name === schema.name).length > 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<nav class="lx-nav">
|
||||
@@ -29,12 +14,7 @@
|
||||
<button on:click={(e) => contentIsOpen = true} class="btn btn-primary btn-sm d-xxl-none">« Content</button>
|
||||
</div>
|
||||
<div class="d-flex align-items-center ">
|
||||
<a class="nav-item" href="{channel.lucentUrl}">{channel.name}</a>
|
||||
<a class="nav-item" href="{channel.lucentUrl}/members">Members</a>
|
||||
|
||||
{#if channel.generateCommand}
|
||||
<a href="{channel.lucentUrl}/build-report" class="btn btn-outline-primary btn-sm d-">Build website</a>
|
||||
{/if}
|
||||
<!-- <div>-->
|
||||
<!-- <form method="GET">-->
|
||||
<!-- <input type="search" name="filter[search_regex]" placeholder="Search"-->
|
||||
@@ -42,7 +22,12 @@
|
||||
<!-- </form>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-items-center ">
|
||||
<a class="nav-item" href="{channel.lucentUrl}/members">Members</a>
|
||||
|
||||
{#if channel.generateCommand}
|
||||
<a href="{channel.lucentUrl}/build-report" class="btn btn-outline-primary btn-sm d-">Build website</a>
|
||||
{/if}
|
||||
<a class="nav-item" href="{channel.lucentUrl}/profile">
|
||||
<Avatar side="28" name={user.name}/>
|
||||
</a>
|
||||
@@ -51,76 +36,12 @@
|
||||
|
||||
</nav>
|
||||
|
||||
<div class="offcanvas offcanvas-start d-xxl-block show border-0 bg-light-subtle" class:d-none={!contentIsOpen}
|
||||
style="padding-top:36px " data-bs-scroll="true"
|
||||
<div class="offcanvas offcanvas-start d-xxl-block show border-0 bg-primary-subtle " class:d-none={!contentIsOpen}
|
||||
data-bs-scroll="true"
|
||||
data-bs-backdrop="false"
|
||||
tabindex="-1" aria-labelledby="offcanvasScrollingLabel">
|
||||
<!-- <div class="offcanvas-header">-->
|
||||
<!-- <h5 class="offcanvas-title" id="offcanvasScrollingLabel">Content</h5>-->
|
||||
<!-- </div>-->
|
||||
<div class="offcanvas-body">
|
||||
<button on:click={(e) => contentIsOpen = false} class="btn btn-primary btn-sm d-xxl-none mb-4">« close</button>
|
||||
<div class="accordion">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="panelsStayOpen-headingMain">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseMain" aria-expanded="true"
|
||||
aria-controls="panelsStayOpen-collapseMain">
|
||||
Main
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panelsStayOpen-collapseMain" class="accordion-collapse collapse show"
|
||||
aria-labelledby="panelsStayOpen-headingMain">
|
||||
<div class="accordion-body">
|
||||
<NavbarMenu
|
||||
schemas={ readableSchemas.filter((sc) => sc.isEntry)}
|
||||
schema={schema}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if otherSchemas.length > 0}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="panelsStayOpen-headingOther">
|
||||
<button class="accordion-button" class:collapsed={!otherIsActive} type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseOther" aria-expanded={otherIsActive}
|
||||
aria-controls="panelsStayOpen-collapseOther">
|
||||
Other
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panelsStayOpen-collapseOther" class="accordion-collapse collapse"
|
||||
class:show={otherIsActive}
|
||||
aria-labelledby="panelsStayOpen-headingOther">
|
||||
<div class="accordion-body">
|
||||
<NavbarMenu
|
||||
schemas={ otherSchemas}
|
||||
schema={schema}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if fileSchemas.length > 0}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="panelsStayOpen-headingFS">
|
||||
<button class="accordion-button " class:collapsed={!filesIsActive} type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseFS" aria-expanded={filesIsActive}
|
||||
aria-controls="panelsStayOpen-collapseFS">
|
||||
Filesystem
|
||||
</button>
|
||||
</h2>
|
||||
<div id="panelsStayOpen-collapseFS" class="accordion-collapse collapse" class:show={filesIsActive}
|
||||
aria-labelledby="panelsStayOpen-headingFS">
|
||||
<div class="accordion-body">
|
||||
<NavbarMenu
|
||||
schemas={ fileSchemas}
|
||||
schema={schema}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
{@html sidebar}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +0,0 @@
|
||||
<script>
|
||||
import {getContext} from "svelte";
|
||||
|
||||
const channel = getContext("channel");
|
||||
export let schemas;
|
||||
export let schema;
|
||||
</script>
|
||||
|
||||
<div class="list-group list-group-flush">
|
||||
|
||||
{#each schemas as aschema}
|
||||
<a class="list-group-item list-group-item-action" class:active={aschema.name === schema?.name}
|
||||
aria-current="page"
|
||||
href="{channel.lucentUrl}/content/{aschema.name}">{aschema.label}</a>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@
|
||||
</script>
|
||||
|
||||
<div class="wrapper-large transparent ">
|
||||
<div class="lx-card mb-4 {inModal ? 'mt-0' : 'mt-5'}">
|
||||
<div class="lx-card mb-4 mt-0">
|
||||
<h3 class="header-normal mb-5 ">
|
||||
{schema.label}
|
||||
</h3>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<div class="wrapper-normal transparent">
|
||||
|
||||
<h3 class="header-small mb-4 mt-5">Latest Content changes</h3>
|
||||
<h3 class="header-small mb-4 ">Latest Content changes</h3>
|
||||
{#if records.length > 0}
|
||||
<div class="lx-card mb-4">
|
||||
<div class="lx-table p-0">
|
||||
|
||||
+64
-6
@@ -1,16 +1,74 @@
|
||||
.lx-nav{
|
||||
.lx-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: rgba(255,255,255,1);
|
||||
margin-bottom:0px ;
|
||||
.nav-item{
|
||||
padding:16px 0;
|
||||
//background-color: rgba(255,255,255,1);
|
||||
margin-bottom: 0px;
|
||||
|
||||
.nav-item {
|
||||
padding: 16px 0;
|
||||
margin: 0 16px;
|
||||
color: $primary;
|
||||
|
||||
}
|
||||
a{
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
.accordion {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.accordion-button:not(.collapsed) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
.offcanvas-body {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.accordion-button:not(.collapsed) {
|
||||
background: rgba(11, 93, 30, 0.2) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.accordion .list-group-item {
|
||||
margin-left: 20px;
|
||||
border-left: 2px solid rgba(11, 93, 30, 0.2);
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.accordion .list-group-item:hover {
|
||||
background: rgba(11, 93, 30, 0.1) !important;
|
||||
}
|
||||
|
||||
.accordion .list-group-item.active {
|
||||
border-left: 2px solid rgba(11, 93, 30, 0.8);
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
background: rgba(11, 93, 30, 0.1) !important;
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
|
||||
.sidebar-logo{
|
||||
padding: 5px 20px;
|
||||
border-bottom: 1px solid rgba(11, 93, 30, 0.2);
|
||||
}
|
||||
.sidebar-logo a{
|
||||
text-decoration: none;
|
||||
font-size: 25px;
|
||||
color: var(--bs-primary);
|
||||
}
|
||||
+3
-2
@@ -3,8 +3,9 @@
|
||||
return [
|
||||
"env" => env("LUCENT_ENV", "production"),
|
||||
"schemas_path" => env("LUCENT_SCHEMAS_PATH", "app/Lucent"),
|
||||
"json_schemas_path" => env("LUCENT_JSON_SCHEMA_PATH", "json_schemas"),
|
||||
"database" => env('LUCENT_DB_CONNECTION', env('DB_CONNECTION',"sqlite")),
|
||||
"json_schemas_path" => env("LUCENT_JSON_SCHEMA_PATH", "json_schema"),
|
||||
"sidebar_path" => env("LUCENT_SIDEBAR_PATH", "app/Lucent"),
|
||||
"database" => env('LUCENT_DB_CONNECTION', env('DB_CONNECTION', "sqlite")),
|
||||
"name" => env("LUCENT_NAME", "Lucent"),
|
||||
"url" => env("LUCENT_URL", env('APP_URL')),
|
||||
"previewTarget" => env("LUCENT_PREVIEW_TARGET", "previewTarget"),
|
||||
|
||||
@@ -37,7 +37,6 @@ class SchemaController extends Controller
|
||||
name: $request->input("name"),
|
||||
label: $request->input("label"),
|
||||
type: $request->input("type"),
|
||||
isEntry: $request->input("isEntry"),
|
||||
revisionRetentionDays: $request->input("revisionRetentionDays"),
|
||||
revisionRetentionNumber: $request->input("revisionRetentionNumber"),
|
||||
trashedRetentionDays: $request->input("trashedRetentionDays"),
|
||||
|
||||
@@ -34,7 +34,7 @@ class GenerateJsonSchema extends Command
|
||||
|
||||
$definitions = $this->channelService->channel->schemas->whereIn("type", [Type::COLLECTION, Type::FILES])->values()->map(fn(Schema $schema) => $this->fromSchema($schema));
|
||||
$definitions->map(function (Definition $definition) use ($definitions) {
|
||||
$this->writeToFile($definition,$definitions);
|
||||
$this->writeToFile($definition, $definitions);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,17 +58,17 @@ class GenerateJsonSchema extends Command
|
||||
mkdir($json_schema_dir);
|
||||
}
|
||||
$nameAr = explode("/", $definition->_id);
|
||||
$name = end($nameAr);
|
||||
$nameEtx = end($nameAr);
|
||||
$name = str_replace(".schema.json", "", $nameEtx);
|
||||
|
||||
$defArray = $definition->toArray();
|
||||
$defArray['$defs'] = $definitions->map(fn($def) => $def->toArray())->keyBy(function ($def){
|
||||
$defArray['$defs'] = $definitions->map(fn($def) => $def->toArray())->keyBy(function ($def) {
|
||||
$nameAr = explode("/", $def['$id']);
|
||||
return str_replace(".json","",end($nameAr));
|
||||
return str_replace(".schema.json", "", end($nameAr));
|
||||
});
|
||||
|
||||
unset($defArray['$defs'][str_replace(".json","",$name)]);
|
||||
|
||||
file_put_contents($json_schema_dir . "/" . $name,json_encode($defArray,JSON_UNESCAPED_SLASHES));
|
||||
unset($defArray['$defs'][$name]);
|
||||
file_put_contents($json_schema_dir . "/" . $nameEtx, json_encode($defArray, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class Definition
|
||||
|
||||
private static function getBasePath(string $schemaName): string
|
||||
{
|
||||
return config("lucent.url") . "/" . config("lucent.json_schemas_path") . "/" . $schemaName . ".json";
|
||||
return config("lucent.url") . "/" . config("lucent.json_schemas_path") . "/" . $schemaName . ".schema.json";
|
||||
}
|
||||
|
||||
private static function getRefPath(string $schemaName): string
|
||||
@@ -81,22 +81,22 @@ class Definition
|
||||
if ($property->maxItems->getOrElse(null) === 1) {
|
||||
$newProperty["type"] = "object";
|
||||
if ($property->_ref->count() == 1) {
|
||||
$newProperty['$ref'] = $property->_ref->map(fn($ref)=>self::getRefPath($ref))->first();
|
||||
$newProperty['$ref'] = $property->_ref->map(fn($ref)=>self::getBasePath($ref))->first();
|
||||
} else {
|
||||
$newProperty["oneOf"] = $property->_ref->map(function (string $ref) {
|
||||
return [
|
||||
'$ref' => self::getRefPath($ref)
|
||||
'$ref' => self::getBasePath($ref)
|
||||
];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$newProperty["type"] = "array";
|
||||
if ($property->_ref->count() == 1) {
|
||||
$newProperty["items"]['$ref'] = $property->_ref->map(fn($ref)=>self::getRefPath($ref))->first();
|
||||
$newProperty["items"]['$ref'] = $property->_ref->map(fn($ref)=>self::getBasePath($ref))->first();
|
||||
} else {
|
||||
$newProperty["items"]["anyOf"] = $property->_ref->map(function (string $ref) {
|
||||
return [
|
||||
'$ref' => self::getRefPath($ref)
|
||||
'$ref' => self::getBasePath($ref)
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Intervention\Image\ImageManager;
|
||||
use Lucent\Channel\ChannelService;
|
||||
use Lucent\Commands\CompileSchemas;
|
||||
use Lucent\Commands\LiveLink;
|
||||
use Lucent\Commands\RebuildThumbnails;
|
||||
use Lucent\Commands\RemoveOrphanEdges;
|
||||
@@ -17,6 +16,7 @@ use Lucent\JsonSchema\Command\GenerateJsonSchema;
|
||||
use Lucent\Query\DatabaseGraph\DatabaseGraph;
|
||||
use Lucent\Query\DatabaseGraph\PgsqlDatabaseGraph;
|
||||
use Lucent\Query\DatabaseGraph\SqliteDatabaseGraph;
|
||||
use Lucent\Schema\Commands\CompileSchemas;
|
||||
|
||||
class LucentServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
namespace Lucent\Schema\BlockUi;
|
||||
|
||||
use Lucent\JsonSchema\Property\Property;
|
||||
use Lucent\JsonSchema\Property\RefProperty;
|
||||
use Lucent\JsonSchema\Property\TypeProperty;
|
||||
use Lucent\Primitive\Collection;
|
||||
use Lucent\Schema\FieldInfo;
|
||||
use Lucent\Schema\FieldInterface;
|
||||
use Lucent\Schema\FieldType;
|
||||
use Lucent\Schema\Type;
|
||||
use Lucent\Schema\Validator\MinMaxInterface;
|
||||
use PhpOption\Option;
|
||||
|
||||
class File implements FieldInterface, MinMaxInterface
|
||||
{
|
||||
@@ -19,9 +25,11 @@ class File implements FieldInterface, MinMaxInterface
|
||||
public string $name,
|
||||
public string $label,
|
||||
public string $mime = "",
|
||||
public string $help = "",
|
||||
public ?int $min = null,
|
||||
public ?int $max = null,
|
||||
public array $collections = [],
|
||||
public string $group = "",
|
||||
)
|
||||
{
|
||||
$this->info = new FieldInfo("file", "File", FieldType::FILE);
|
||||
@@ -50,20 +58,20 @@ class File implements FieldInterface, MinMaxInterface
|
||||
return count($value) < $this->min;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function toJsonSchema(): Property
|
||||
{
|
||||
return new TypeProperty(
|
||||
type: PropertyType::STRING,
|
||||
return new RefProperty(
|
||||
id: $this->name,
|
||||
title: Option::fromValue($this->label),
|
||||
description: Option::fromValue($this->help, ""),
|
||||
default: Option::fromValue($this->default, ""),
|
||||
minLength: Option::fromValue($this->min),
|
||||
maxLength: Option::fromValue($this->max),
|
||||
readOnly: Option::fromValue($this->readonly, false),
|
||||
enum: Option::fromValue($this->selectOptions),
|
||||
_ref: new Collection($this->collections),
|
||||
minItems: Option::fromValue($this->min),
|
||||
maxItems: Option::fromValue($this->max),
|
||||
comment: Option::fromValue($this->group, ""),
|
||||
format: none(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,5 +29,9 @@ class Heading implements FieldInterface
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ class Markdown implements FieldInterface
|
||||
$output[$this->name] = $input[$this->name] ?? "";
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ class Reference implements FieldInterface, MinMaxInterface
|
||||
|
||||
return count($value) < $this->min;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ class Rich implements FieldInterface
|
||||
$output[$this->name] = $input[$this->name] ?? "";
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ class Textarea implements FieldInterface
|
||||
$output[$this->name] = $input[$this->name] ?? "";
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ class CollectionSchema implements Schema
|
||||
public array $visible,
|
||||
public array $groups,
|
||||
public Collection $fields,
|
||||
public bool $isEntry = false,
|
||||
public string $color = "",
|
||||
public string $sortBy = "-_sys.updatedAt",
|
||||
public string $titleTemplate = "",
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Commands;
|
||||
namespace Lucent\Schema\Commands;
|
||||
|
||||
use DirectoryIterator;
|
||||
use Illuminate\Console\Command;
|
||||
use Lucent\Schema\Schema;
|
||||
use Lucent\Schema\SchemaService;
|
||||
use Lucent\Schema\Type;
|
||||
use function Lucent\Commands\base_path;
|
||||
|
||||
class CompileSchemas extends Command
|
||||
{
|
||||
@@ -11,5 +11,4 @@ enum FieldType: string
|
||||
case FILE = 'file';
|
||||
case JSON = 'json';
|
||||
case REFERENCE = 'reference';
|
||||
case TAB = 'tab';
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ class FilesSchema implements Schema
|
||||
public Collection $fields,
|
||||
public string $path,
|
||||
public array $groups,
|
||||
public bool $isEntry = false,
|
||||
public string $sortBy = "-_sys.updatedAt",
|
||||
public string $color = "",
|
||||
public string $titleTemplate = "",
|
||||
|
||||
@@ -22,7 +22,6 @@ class SchemaService
|
||||
visible: $schemaArr["visible"] ?? [],
|
||||
groups: $schemaArr["groups"] ?? [],
|
||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
||||
isEntry: $schemaArr["isEntry"] ?? false,
|
||||
color: $schemaArr["color"] ?? "",
|
||||
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
||||
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||
@@ -36,7 +35,6 @@ class SchemaService
|
||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
||||
path: $schemaArr["path"] ?? $schemaArr["name"],
|
||||
groups: $schemaArr["groups"] ?? [],
|
||||
isEntry: $schemaArr["isEntry"] ?? false,
|
||||
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
||||
color: $schemaArr["color"] ?? "",
|
||||
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar\Item;
|
||||
|
||||
|
||||
abstract class Item
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar\Item;
|
||||
|
||||
class LinkItem extends Item
|
||||
{
|
||||
public function __construct(
|
||||
public string $label,
|
||||
public string $href,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
label: $data["label"],
|
||||
href: $data["href"],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar\Item;
|
||||
|
||||
class SchemaItem extends Item
|
||||
{
|
||||
public function __construct(
|
||||
public string $label,
|
||||
public string $schema,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
label: $data["label"],
|
||||
schema: $data["schema"],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar;
|
||||
|
||||
use Lucent\Primitive\Collection;
|
||||
use Lucent\Schema\Sidebar\Item\Item;
|
||||
use Lucent\Schema\Sidebar\Item\LinkItem;
|
||||
use Lucent\Schema\Sidebar\Item\SchemaItem;
|
||||
|
||||
class Section
|
||||
{
|
||||
/**
|
||||
* @param Collection<Item> $items
|
||||
*/
|
||||
public function __construct(
|
||||
public string $label,
|
||||
public Collection $items
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
label: $data["label"],
|
||||
items: (new Collection($data["items"]))->map(fn($itemData) => isset($itemData["schema"]) ? SchemaItem::fromArray($itemData) : LinkItem::fromArray($itemData))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar;
|
||||
|
||||
use Lucent\Primitive\Collection;
|
||||
|
||||
class Sidebar
|
||||
{
|
||||
/**
|
||||
* @param Collection<Section> $sections
|
||||
*/
|
||||
public function __construct(
|
||||
public Collection $sections
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self((new Collection($data))->map(fn($sectionData) => Section::fromArray($sectionData)));
|
||||
}
|
||||
|
||||
public function getUsedSchemas(): array
|
||||
{
|
||||
return $this->sections->reduce(function (array $carry, Section $section) {
|
||||
return array_merge($carry, $section->items->pluck("schema")->toArray());
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Schema\Sidebar;
|
||||
|
||||
|
||||
use Lucent\Channel\Channel;
|
||||
use PhpOption\Option;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class SidebarService
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Channel $channel
|
||||
* @param array<string> $readableSchemas
|
||||
* @param string $currentSchema
|
||||
* @return string
|
||||
*/
|
||||
public function render(Channel $channel, array $readableSchemas, string $currentSchema): string
|
||||
{
|
||||
$schemas = $channel->schemas->whereIn("name", $readableSchemas);
|
||||
|
||||
|
||||
return view('lucent::sidebar.sidebar', [
|
||||
'sidebar' => $this->fromConfig(),
|
||||
'schemas' => $schemas,
|
||||
'channel' => $channel,
|
||||
'currentSchema' => $currentSchema,
|
||||
'lucentUrl' => $channel->lucentUrl,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Option<Sidebar>
|
||||
*/
|
||||
private function fromConfig(): Option
|
||||
{
|
||||
$configPath = base_path(config("lucent.sidebar_path")) . "/sidebar.yaml";
|
||||
|
||||
if (!file_exists($configPath)) {
|
||||
return none();
|
||||
}
|
||||
|
||||
$yaml = Yaml::parse(file_get_contents($configPath));
|
||||
|
||||
if (empty($yaml)) {
|
||||
return none();
|
||||
}
|
||||
|
||||
$sidebar = Sidebar::fromArray($yaml);
|
||||
return some($sidebar);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ class Reference implements FieldInterface, MinMaxInterface
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $label,
|
||||
public string $mime = "",
|
||||
public string $help = "",
|
||||
public ?int $min = null,
|
||||
public ?int $max = null,
|
||||
|
||||
@@ -6,27 +6,30 @@ use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Lucent\Account\AccountService;
|
||||
use Lucent\Channel\ChannelService;
|
||||
use Lucent\Schema\Sidebar\SidebarService;
|
||||
|
||||
class Svelte
|
||||
{
|
||||
public function __construct(
|
||||
public ChannelService $channelService,
|
||||
public AccountService $accountService
|
||||
public AccountService $accountService,
|
||||
public SidebarService $sidebarService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
function render(string $layout, string $view, string $title = "", mixed $data = []): View|Factory
|
||||
{
|
||||
|
||||
$readableSchemas = $this->accountService->currentReadableSchemas();
|
||||
$context = [];
|
||||
$context["user"] = session('user');
|
||||
$context["view"] = $view;
|
||||
$context["layout"] = $layout;
|
||||
$context["sidebar"] = $this->sidebarService->render($this->channelService->channel,$readableSchemas, $data["schema"]?->name ?? "");
|
||||
$context["title"] = $title;
|
||||
$context["data"] = $data;
|
||||
$context["channel"] = $this->channelService->channel;
|
||||
$context["readableSchemas"] = $this->accountService->currentReadableSchemas();
|
||||
$context["readableSchemas"] = $readableSchemas;
|
||||
$json = json_encode($context);
|
||||
|
||||
$divTag = sprintf('<div class="lucent-component" data-layout="%s"></div>', $layout);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<div class="accordion-item">
|
||||
@php
|
||||
$show = $schemas->where("name", $currentSchema)->isNotEmpty() || $main;
|
||||
@endphp
|
||||
|
||||
<h2 class="accordion-header" id="panelsStayOpen-headingMain">
|
||||
<button class="accordion-button bg-primary-subtle {{$show ? "" : "collapsed"}}" type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapseMain" aria-expanded="{{$show}}"
|
||||
aria-controls="panelsStayOpen-collapseMain">
|
||||
@if($main)
|
||||
Content
|
||||
@else
|
||||
Other
|
||||
@endif
|
||||
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<div id="panelsStayOpen-collapseMain" class="accordion-collapse collapse {{$show ? "show" : ""}}"
|
||||
aria-labelledby="panelsStayOpen-headingMain"
|
||||
data-bs-parent="#main-sidebar">
|
||||
<div class="list-group list-group-flush">
|
||||
@foreach($schemas as $schema)
|
||||
|
||||
<a class="list-group-item list-group-item-action bg-primary-subtle {{ $schema->name == $currentSchema ? "active" : ""}}"
|
||||
aria-current="page"
|
||||
href="{{$lucentUrl}}/content/{{$schema->name}}">{{$schema->label}}</a>
|
||||
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,52 @@
|
||||
<div class="sidebar-logo">
|
||||
<a href="{{$channel->lucentUrl}}">{{$channel->name}}</a>
|
||||
</div>
|
||||
<div class="accordion" id="main-sidebar">
|
||||
@if($sidebar->isEmpty())
|
||||
@include("lucent::sidebar.accordion-item", ["schemas" => $schemas, "currentSchema" => $currentSchema, "lucentUrl" => $lucentUrl, "main" => true])
|
||||
@else
|
||||
@foreach($sidebar->get()->sections as $index => $section)
|
||||
@php
|
||||
$show = $section->items->where("schema", $currentSchema)->isNotEmpty();
|
||||
@endphp
|
||||
<div class="accordion-item ">
|
||||
<h2 class="accordion-header" id="panelsStayOpen-heading-{{$index}}">
|
||||
<button class="accordion-button rounded-0 bg-primary-subtle {{$show ? "" : "collapsed"}}"
|
||||
type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#panelsStayOpen-collapse-{{$index}}" aria-expanded="{{$show}}"
|
||||
aria-controls="panelsStayOpen-collapse-{{$index}}">
|
||||
{{$section->label}}
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<div id="panelsStayOpen-collapse-{{$index}}"
|
||||
class="accordion-collapse collapse {{$show ? "show" : ""}}"
|
||||
aria-labelledby="panelsStayOpen-heading-{{$index}}"
|
||||
data-bs-parent="#main-sidebar">
|
||||
<div class="list-group list-group-flush bg-primary-subtle">
|
||||
@foreach($section->items as $item)
|
||||
@if(isset($item->href))
|
||||
<a class="list-group-item list-group-item-action bg-primary-subtle"
|
||||
aria-current="page"
|
||||
href="{{$item->href}}"
|
||||
target="_blank"
|
||||
>{{$item->label}}</a>
|
||||
@else
|
||||
@php
|
||||
$schema = $schemas->where("name",$item->schema)->first();
|
||||
|
||||
@endphp
|
||||
|
||||
<a class="list-group-item list-group-item-action bg-primary-subtle {{ $schema->name == $currentSchema ? "active" : ""}}"
|
||||
aria-current="page"
|
||||
href="{{$lucentUrl}}/content/{{$schema->name}}">{{$item->label}}</a>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@include("lucent::sidebar.accordion-item", ["schemas" => $schemas->whereNotIn("name",$sidebar->get()->getUsedSchemas()), "currentSchema" => $currentSchema, "lucentUrl" => $lucentUrl, "main" => false])
|
||||
@endif
|
||||
</div>
|
||||
Reference in New Issue
Block a user