transition

This commit is contained in:
2024-08-14 22:04:34 +03:00
parent 1ab3f678b7
commit 1f3ebafe69
50 changed files with 924 additions and 172 deletions
+3
View File
@@ -5,6 +5,9 @@
*/
import axios from "axios";
import {loadHtmxFormsBehaviour} from "./htmx-form.js";
loadHtmxFormsBehaviour();
window.axios = axios;
export const axiosInstance = axios;
+24
View File
@@ -0,0 +1,24 @@
export function loadHtmxFormsBehaviour(){
document.querySelectorAll(".form").forEach(el => {
initHtmxForm(el);
})
}
function initHtmxForm(el){
el.addEventListener("htmx:responseError", (e) => {
el.querySelector(".form-errors").innerHTML = e.detail.xhr.response;
});
const formEl = el.querySelector("form");
if(!formEl.getAttribute("hx-redirect")){
return;
}
el.addEventListener("htmx:afterOnLoad", (e) => {
if(e.detail.successful){
return window.location.href = formEl.getAttribute("hx-redirect");
}
});
}
+1
View File
@@ -4,6 +4,7 @@ import Account from "./svelte/Account.svelte";
import Channel from "./svelte/Channel.svelte";
import * as bootstrap from "bootstrap";
import Mustache from "mustache";
import 'htmx.org';
Mustache.escape = function (value) {
return value;
+7 -1
View File
@@ -5,7 +5,8 @@
"packages": {
"": {
"dependencies": {
"@codemirror/lang-markdown": "^6.2.2"
"@codemirror/lang-markdown": "^6.2.2",
"htmx.org": "^2.0.1"
},
"devDependencies": {
"@codemirror/commands": "^6.1.2",
@@ -935,6 +936,11 @@
"node": ">= 0.4.0"
}
},
"node_modules/htmx.org": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.1.tgz",
"integrity": "sha512-wO/rWlveSLD2mzRS9Em0v5hlsi6r21iUvaS17GPMgehBbM7eoQmqGQCkscsM67poF24zONgq3gQv+q/cgCHn2w=="
},
"node_modules/immutable": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
+2 -1
View File
@@ -29,6 +29,7 @@
"vite": "^3.2.3"
},
"dependencies": {
"@codemirror/lang-markdown": "^6.2.2"
"@codemirror/lang-markdown": "^6.2.2",
"htmx.org": "^2.0.1"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><circle cx="4" cy="12" r="3" fill="currentColor"><animate id="svgSpinners3DotsBounce0" attributeName="cy" begin="0;svgSpinners3DotsBounce1.end+0.25s" calcMode="spline" dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12"/></circle><circle cx="12" cy="12" r="3" fill="currentColor"><animate attributeName="cy" begin="svgSpinners3DotsBounce0.begin+0.1s" calcMode="spline" dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12"/></circle><circle cx="20" cy="12" r="3" fill="currentColor"><animate id="svgSpinners3DotsBounce1" attributeName="cy" begin="svgSpinners3DotsBounce0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12"/></circle></svg>

After

Width:  |  Height:  |  Size: 803 B

+22
View File
@@ -0,0 +1,22 @@
.scope-login {
display: flex;
height: 100vh;
.bg-image {
width: 50%;
background: url("/vendor/lucent/public/art.jpg");
background-repeat: no-repeat;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
.login-form{
width: 50%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
}
+85
View File
@@ -0,0 +1,85 @@
label {
display: block;
font-weight: 700;
margin-bottom: 4px;
}
input{
width: 100%;
}
input,textarea{
background: var(--input-bg);
border: 1px solid $border-color;
border-radius: 5px;
padding: 5px 7px;
font-size: 16px;
filter: brightness(95%);
}
input:focus,textarea:focus{
filter: brightness(101%);
}
textarea{
resize: none;
}
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline;
}
.htmx-request.htmx-indicator {
display: inline;
}
.bt {
appearance: none;
background-color: #000;
background-image: none;
border: 1px solid #000;
border-radius: 4px;
box-shadow: #fff 4px 4px 0 0, #000 4px 4px 0 1px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
display: inline-block;
font-family: ITCAvantGardeStd-Bk, Arial, sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 20px;
margin: 0 5px 10px 0;
overflow: visible;
padding: 8px 40px;
text-align: center;
text-transform: none;
touch-action: manipulation;
user-select: none;
-webkit-user-select: none;
vertical-align: middle;
white-space: nowrap;
}
.bt:focus {
text-decoration: none;
}
.bt:hover {
text-decoration: none;
}
.bt:active {
box-shadow: rgba(0, 0, 0, .125) 0 3px 5px inset;
outline: 0;
}
.bt:not([disabled]):active {
box-shadow: #fff 2px 2px 0 0, #000 2px 2px 0 1px;
transform: translate(2px, 2px);
}
+49
View File
@@ -0,0 +1,49 @@
.mt-1{margin-top: 4px}
.mt-2{margin-top: 8px}
.mt-3{margin-top: 12px}
.mt-4{margin-top: 16px}
.mt-5{margin-top: 20px}
.mb-1{margin-bottom: 4px}
.mb-2{margin-bottom: 8px}
.mb-3{margin-bottom: 12px}
.mb-4{margin-bottom: 16px}
.mb-5{margin-bottom: 20px}
.pt-1{padding-top: 4px}
.pt-2{padding-top: 8px}
.pt-3{padding-top: 12px}
.pt-4{padding-top: 16px}
.pt-5{padding-top: 20px}
.pb-1{padding-bottom: 4px}
.pb-2{padding-bottom: 8px}
.pb-3{padding-bottom: 12px}
.pb-4{padding-bottom: 16px}
.pb-5{padding-bottom: 20px}
.gap-1{gap: 4px}
.gap-2{gap: 8px}
.gap-3{gap: 12px}
.gap-4{gap: 16px}
.gap-5{gap: 20px}
.hide{
display: none;
}
.d-block{
display: block;
}
.d-inline-block{
display: inline-block;
}
.is-bold{
font-weight: 700;
}
.in-place{
padding: 36px;
}
-3
View File
@@ -1,3 +0,0 @@
.in-place{
padding: 36px;
}
+14
View File
@@ -0,0 +1,14 @@
.sidebar {
}
.main-content {
width: 100%;
}
.main-wrapper {
display: flex;
gap: 40px;
padding: 20px;
}
-16
View File
@@ -1,16 +0,0 @@
.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;
margin: 0 16px;
color: $primary;
}
a{
text-decoration: none;
}
}
+32
View File
@@ -0,0 +1,32 @@
.notice {
background-color: $background;
padding: 25px 14px 14px;
margin: 2rem 0;
filter: brightness(1.03);
position: relative;
font-size: 16px;
line-height: 24px;
border: 3px solid $border-color;
}
.notice .title {
content: "NOTE";
position: absolute;
background: $background;
min-width: 90px;
border: 3px solid $border-color;
color: $text;
display: block;
text-align: center;
left: 14px;
top: -18px;
padding: 2px 10px;
font-weight: bold;
}
.notice.success{
border-color: $success;
& .title{
border-color: $success;
}
}
+46
View File
@@ -0,0 +1,46 @@
/*
1. Use a more-intuitive box-sizing model.
*/
*, *::before, *::after {
box-sizing: border-box;
}
/*
2. Remove default margin
*/
* {
margin: 0;
}
/*
Typographic tweaks!
3. Add accessible line-height
4. Improve text rendering
*/
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/*
5. Improve media defaults
*/
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
/*
6. Remove built-in form typography styles
*/
input, button, textarea, select {
font: inherit;
}
/*
7. Avoid text overflows
*/
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
/*
8. Create a root stacking context
*/
#root, #__next {
isolation: isolate;
}
+36 -76
View File
@@ -1,89 +1,49 @@
.sidebar {
background-color: $dark;
min-height: 100vh;
font-size: 15px;
line-height: 28px;
border: 1px solid $border-color;
border-radius: 12px;
min-height: 100vh;
font-size: 15px;
line-height: 28px;
min-width: 300px;
max-width: 400px;
background: $background;
filter: brightness(104%);
}
.sidebar-header {
color: $white;
position: relative;
padding: 0 10px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
&:hover .actions {
visibility: visible;
}
}
background: $background;
font-size: 16px;
padding: 12px 12px 6px;
color: $text;
filter: brightness(94%);
.sidebar .actions {
position: absolute;
top: 0px;
right: 8px;
background-color: $dark;
visibility: hidden;
}
.sidebar .sidebar-header .actions {
background-color: $dark;
}
.sidebar .sidebar-item .actions {
background-color: $white;
}
.sidebar .sidebar-item.active .actions {
background-color: $primary;
}
.sidebar .sidebar-header .actions a,
.sidebar .sidebar-header .actions span {
color: $white !important;
cursor: pointer;
}
.sidebar .sidebar-item .actions a {
color: $dark !important;
cursor: pointer;
}
.sidebar .sidebar-item.active .actions a {
color: $white !important;
cursor: pointer;
&:first-child {
border-bottom: none;
border-radius: 12px 12px 0 0;
}
}
.sidebar-item {
a {
color: $white;
text-decoration: none;
padding: 0 0px;
}
&:hover {
background-color: $light;
a {
color: $dark;
}
}
position: relative;
padding: 0 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: $white;
&:hover .actions {
visibility: visible;
}
}
color: $text;
display: block;
font-size: 14px;
padding: 6px 12px;
text-decoration: none;
border-bottom: 1px solid $border-color;
transition: 600ms;
.sidebar hr {
color: $white;
line-height: 30px;
}
&:last-child {
border-bottom: none;
border-radius: 0 0 12px 12px;
}
.sidebar .active {
background-color: $primary;
a {
color: $white;
}
&:hover {
background: $secondary;
}
&.active {
background: $secondary;
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
.lx-table {
min-width: 600px;
overflow: auto;
background-color: #f9f9f9;
table {
width: 100%;
min-width: 600px;
}
th {
-4
View File
@@ -1,4 +0,0 @@
.lx-small-text {
font-size: 12px;
line-height: 15px;
}
+56
View File
@@ -0,0 +1,56 @@
.content{
font-size: 16px;
line-height: 20px;
p{
margin-bottom: 14px;
&:last-child{
margin-bottom: 0;
}
}
ul {
padding: 0 0 0 16px;
list-style: none outside none;
li::before {
content: "";
opacity: .5;
font-size: 12px;
padding-right: 6px;
vertical-align: 10%;
}
li {
list-style: none;
padding: 0;
}
}
}
.title-separator{
font-size: 20px;
text-align: center;
padding: 30px 0 10px;
margin-bottom: 30px;
position: relative;
border-bottom: 1px solid var(--border-color);
//&:after {
// position: absolute;
// left: 0;
// right: 0;
// top: 70px;
// margin: auto;
// display: block;
// width: 270px;
// border-bottom: 1px solid var(--border-color);
// content: "";
//}
}
.lx-small-text {
font-size: 12px;
line-height: 15px;
}
+1 -1
View File
@@ -120,6 +120,6 @@
}
.header-small {
text-align: center;
text-align: left;
font-size: 26px;
}
+58 -8
View File
@@ -6,6 +6,10 @@ $green-pigment: #139a43ff;
$lincoln-green: #0b5d1eff;
$forest-green-traditional: #053b06ff;
$black: #000000ff;
$dark: #000000ff;
$white: #ffffff;
$light: #eee;
$danger: red;
/* SCSS Gradient */
$gradient-top: linear-gradient(
@@ -80,25 +84,71 @@ $gradient-radial: radial-gradient(
#000000ff
);
$primary: $lincoln-green;
$primary: #5b86be;
$secondary: #d9cca1;
$success: #80c671;
$background: #f4f6fa;
$table-striped-bg-factor: 0.03;
$dropdown-bg: rgb(206, 223, 210);
$border-color: #000;
$text: #04060b;
$accent: #80c671;
@import "../node_modules/bootstrap/scss/bootstrap";
//https://www.realtimecolors.com/?colors=04060b-f4f6fa-5b86be-d9cca1-80c671&fonts=Anek Telugu-Anek Telugu
$themes: (
light: (
text: #04060b,
background: #f4f6fa,
primary: #5b86be,
secondary: #d9cca1,
accent: #80c671,
),
dark: (
text: #f4f6fb,
background: #05070a,
primary: #416ca4,
secondary: #5e5126,
accent: #488e39,
),
);
//@import "../node_modules/bootstrap/scss/bootstrap";
@import "./reset";
@import "./helpers";
@import "./notice";
@import "./auth";
@import "./typography";
@import "./sidebar";
@import "./form";
@import "./table";
@import "./avatar";
@import "./codemirror";
@import "./layout";
@import "./wrappers";
@import "./in-place";
@import "./text";
@import "./card";
@import "./nav";
@import "./files";
@import "./revisions";
:root{
--linearPrimarySecondary: linear-gradient(#5b86be, #d9cca1);
--linearPrimaryAccent: linear-gradient(#5b86be, #80c671);
--linearSecondaryAccent: linear-gradient(#d9cca1, #80c671);
--radialPrimarySecondary: radial-gradient(#5b86be, #d9cca1);
--radialPrimaryAccent: radial-gradient(#5b86be, #80c671);
--radialSecondaryAccent: radial-gradient(#d9cca1, #80c671);
--border-color: $border-color;
--main-font: Open Sans, Arial, Helvetica, sans-serif;
--main-font-color: #444;
--input-bg: rgb(245,245,249);
}
body {
background-color: rgba(11, 93, 30, 0.04);
background-color: $background;
}
.btn-spinner .spinner-border {
@@ -119,8 +169,8 @@ body {
}
.dropdown-menu {
border: 0px;
border: 0;
border-radius: 15px;
box-shadow: 0px 0px 4px #ccc;
box-shadow: 0 0 4px #ccc;
padding: 30px 15px;
}
+9
View File
@@ -0,0 +1,9 @@
<x-lucent::notice type="success" title="Success">
<p>
If you have provided a valid email you should receive in the following seconds a login email
</p>
<p>You can safely close this tab</p>
</x-lucent::notice>
+36
View File
@@ -0,0 +1,36 @@
@extends("lucent::layouts.account")
@section("content")
<div class="scope-login">
<div class="bg-image">
</div>
<div class="login-form">
<div class="form">
<h2 class="mb-5">Enter Lucent</h2>
<form hx-post="/lucent/login" >
<p>Submit your email address and you will receive a <b>login link</b> to your email</p>
<p>Don't forget to check your spam folder</p>
<div class="mt-5 mb-3">
<label for="emailaddress" class="form-label">Email address</label>
<input
type="email"
name="email"
class="form-control"
id="emailaddress"
required
/>
</div>
<x-lucent::button-indicator>
Send email
</x-lucent::button-indicator>
</form>
</div>
</div>
</div>
@endsection
+24
View File
@@ -0,0 +1,24 @@
@extends("lucent::layouts.account")
@section("content")
<div class="scope-login">
<div class="bg-image">
</div>
<div class="login-form">
<div class="form">
<h2 class="mb-5">Welcome to Lucent</h2>
<form hx-post="/lucent/verify" hx-redirect="/lucent" hx-target-error=".form-errors" >
<input type="hidden" value="{{$email}}" name="email" />
<input type="hidden" value="{{$token}}" name="token" />
@csrf
<x-lucent::button-indicator>
Enter as {{$email}}
</x-lucent::button-indicator>
</form>
<div class="form-errors"></div>
</div>
</div>
</div>
@endsection
+43
View File
@@ -0,0 +1,43 @@
@php
$side = $side ?? 48;
$colors = [
"#00AA55",
"#009FD4",
"#B381B3",
"#939393",
"#E3BC00",
"#D47500",
"#DC2A2A",
"#3ede91",
"#377dd4",
"#0256b0",
"#053d82",
"#3d026e",
"#b378e3",
"#c4065c",
"#543208",
"#d97811",
"#0c6b40",
];
$initials = function($name){
$segs = explode(" ",$name);
if(count($segs) > 1){
return strtoupper($segs[0][0]).strtoupper($segs[1][0]);
}
return strtoupper($segs[0][0]).strtoupper($segs[0][1]);
};
$name = $user["name"];
$charIndex = ord($name[1]) + strlen($name);
$colorIndex = $charIndex % 19;
$bgColor = $colors[$colorIndex];
@endphp
<div
class="avatar"
title="{{$name}}"
style="background-color:{{$bgColor}};height: {{$side}}px;width: {{$side}}px; font-size:{{$side / 2}}px"
>
<div class="avatar__letters">{{$initials($user["name"])}}</div>
</div>
@@ -0,0 +1,4 @@
<button class="bt bt-primary">
{{$slot}}
<img alt="indicator" id="indicator" class="htmx-indicator" src="/img/spinner.svg"/>
</button>
+4
View File
@@ -0,0 +1,4 @@
<div class="notice {{$type ?? "info"}}">
<div class="title">{{$title}}</div>
<div class="content">{{ $slot }}</div>
</div>
+5
View File
@@ -0,0 +1,5 @@
Login to your Lucent account!
If you were not the one making this request, please ignore this email.
{{ $url }}/verify?email={{ $email }}&token={{ $token }}
+9
View File
@@ -0,0 +1,9 @@
@if (count($errors) > 0)
<x-lucent::notice type="error" title="🛑 Submission failed">
<ul>
@foreach ($errors as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</x-lucent::notice>
@endif
+23
View File
@@ -0,0 +1,23 @@
@extends("lucent::layouts.channel")
@section("content")
<h3 class="header-small mb-4">Latest Content changes</h3>
@if($records->isNotEmpty())
<div class="lx-card mb-4">
<div class="lx-table p-0">
<table class="">
<tbody>
@foreach($records as $record)
<tr>
@include("lucent::records.card-row")
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
@endsection
+21
View File
@@ -0,0 +1,21 @@
<div class="d-flex align-items-center ">
<a class="nav-item" href="/lucent">{{$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>
@endif
<!-- <div>-->
<!-- <form method="GET">-->
<!-- <input type="search" name="filter[search_regex]" placeholder="Search"-->
<!-- class="form-control" required/>-->
<!-- </form>-->
<!-- </div>-->
</div>
<div>
<a class="nav-item" href="/lucent/profile">
<x-lucent::avatar side="28" :user="$user"></x-lucent::avatar>
</a>
</div>
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title') - Lucent Data Platform</title>
@if(config("lucent.env") === "production")
<!-- if production -->
<link rel="stylesheet" href="/vendor/lucent/dist/{{ $manifest['main.css']["file"] }}"/>
<script type="module" src="/vendor/lucent/dist/{{ $manifest['main.js']["file"] }}"></script>
@else
<!-- if development -->
@php
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
@endphp
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
@endif
{{-- <link rel="icon" type="image/x-icon" href="/favicon.ico"/>--}}
</head>
<body>
<div>
@yield('content')
</div>
</body>
</html>
+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title') - Lucent Data Platform</title>
@if(config("lucent.env") == "production")
<!-- if production -->
<link rel="stylesheet" href="/vendor/lucent/dist/{{ $manifest['main.css']["file"] }}"/>
<script type="module" src="/vendor/lucent/dist/{{ $manifest['main.js']["file"] }}"></script>
@else
<!-- if development -->
@php
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
@endphp
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
@endif
<link rel="icon" type="image/x-icon" href="/favicon.ico">
</head>
<body>
@include("lucent::includes.header")
<div class="main-wrapper">
@include("lucent::sidebar.sidebar")
<div class="main-content">
@yield('content')
</div>
</div>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
@php
$schema = $schemas->where("name",$record->schema)->first();
@endphp
<td>
{{-- {#if schema.type === "files"}--}}
{{-- <Preview {record} size="tiny"/>--}}
{{-- {:else}--}}
<a
href="/lucent/records/{{$record->id}}"
class="text-decoration-none text-dark d-block"
>
{{$viewModel->getRecordName($record, $schemas)}}
</a>
{{$record->status->value === "draft" ? "Draft" : ""}}
{{-- {/if}--}}
</td>
<td><a
class="text-decoration-none lx-small-text"
href="/lucent/content/{{$schema->name}}">{{$schema->label}}</a
>
</td>
<td>
{{-- <div class="d-flex">--}}
{{-- <Avatar name={usernameById(users, record._sys.updatedBy)} side={24}/>--}}
{{-- <div class="ms-2">--}}
{{-- {frieldlyUpdatedAt}--}}
{{-- </div>--}}
{{-- </div>--}}
</td>
+10
View File
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{$title}}</title>
<meta http-equiv="refresh" content="0; url='{{$to}}'"/>
</head>
<body>
<p>{{$message}}</p>
</body>
</html>
@@ -0,0 +1,7 @@
@php
$currentSchema = $currentSchema ?? null;
$activeClass = $schema->name === $currentSchema?->name ? "active" : "";
@endphp
<a class="sidebar-item {{$activeClass}}" aria-current="page"
href="/lucent/content/{{$schema->name}}">{{$schema->label}}</a>
+20
View File
@@ -0,0 +1,20 @@
<div class="sidebar">
<div class="sidebar-header">
Content
</div>
@foreach($schemas->where("type.value", "collection")->where("isEntry",true) as $schema)
@include("lucent::sidebar.sidebar-item", ["schema" => $schema])
@endforeach
<div class="sidebar-header">
Files
</div>
@foreach($schemas->where("type.value", "files") as $schema)
@include("lucent::sidebar.sidebar-item", ["schema" => $schema])
@endforeach
<div class="sidebar-header">
Other
</div>
@foreach($schemas->where("type.value", "collection")->where("isEntry",false) as $schema)
@include("lucent::sidebar.sidebar-item", ["schema" => $schema])
@endforeach
</div>
+7
View File
@@ -0,0 +1,7 @@
@extends('lucent::layouts.'.$layout)
@section('title')
{{ $title }}
@endsection
@section('content')
{!! $svelte !!}
@endsection