removed blade and htmx

This commit is contained in:
2026-05-06 23:16:09 +03:00
parent dff3748623
commit 98efb76f7b
31 changed files with 235 additions and 465 deletions
-51
View File
@@ -1,51 +0,0 @@
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
import axios from "axios";
import {loadHtmxFormsBehaviour} from "./htmx-form.js";
loadHtmxFormsBehaviour();
window.axios = axios;
export const axiosInstance = axios;
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
window.axios.interceptors.request.use(
function (config) {
let list;
list = document.querySelectorAll(".btn-spinner");
for (let i = 0; i < list.length; ++i) {
list[i].classList.add("spinner-on");
list[i].disabled = true;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
window.axios.interceptors.response.use(
function (response) {
let list;
list = document.querySelectorAll(".btn-spinner");
for (let i = 0; i < list.length; ++i) {
list[i].classList.remove("spinner-on");
list[i].disabled = false;
}
return response;
},
function (error) {
let list;
list = document.querySelectorAll(".btn-spinner");
for (let i = 0; i < list.length; ++i) {
list[i].classList.remove("spinner-on");
list[i].disabled = false;
}
return Promise.reject(error);
}
);
+60 -29
View File
@@ -1,52 +1,83 @@
import {formatDistanceToNow, parseJSON, format, parse} from "date-fns"; import { formatDistanceToNow, parseJSON, format, parse } from "date-fns";
export function friendlyDate(date) { export function friendlyDate(date) {
return formatDistanceToNow(parseJSON(date), {addSuffix: true}); return formatDistanceToNow(parseJSON(date), { addSuffix: true });
} }
export function readableDate(date) { export function readableDate(date) {
if(!date){ if (!date) {
return ""; return "";
} }
return format(parseJSON(date), "dd MMM yyyy"); return format(parseJSON(date), "dd MMM yyyy");
} }
export function readableDatetime(date) { export function readableDatetime(date) {
if(!date){ if (!date) {
return ""; return "";
} }
return format(parseJSON(date), "dd MMM yyyy HH:mm"); return format(parseJSON(date), "dd MMM yyyy HH:mm");
} }
export function stripHtml(html = "") { export function stripHtml(html = "") {
let tmp = document.createElement("div"); let tmp = document.createElement("div");
tmp.innerHTML = html; tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || ""; return tmp.textContent || tmp.innerText || "";
} }
export function randomId(length = 10) { export function randomId(length = 10) {
return Math.random().toString(36).substring(2, length + 2); return Math.random()
.toString(36)
.substring(2, length + 2);
} }
export function clickOutside(node) { export function clickOutside(node) {
const handleClick = (event) => {
const handleClick = event => { if (node && !node.contains(event.target) && !event.defaultPrevented) {
if (node && !node.contains(event.target) && !event.defaultPrevented) { node.dispatchEvent(new CustomEvent("click_outside", node));
node.dispatchEvent(
new CustomEvent('click_outside', node)
)
}
} }
};
document.addEventListener('click', handleClick, true); document.addEventListener("click", handleClick, true);
return { return {
destroy() { destroy() {
document.removeEventListener('click', handleClick, true); document.removeEventListener("click", handleClick, true);
} },
} };
} }
export function apiFetch(url, options = {}) {
return fetch(url, {
...options,
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').content,
...options.headers,
},
});
}
export function apiPost(url, body, options = {}) {
return fetch(url, {
...options,
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').content,
...options.headers,
},
});
}
export function apiGet(url, options = {}) {
return fetch(url, {
...options,
method: "GET",
headers: {
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').content,
...options.headers,
},
}).then((r) => r.json());
}
+28 -34
View File
@@ -1,53 +1,47 @@
import {axiosInstance} from "./bootstrap";
import "../sass/app.scss"; import "../sass/app.scss";
import Account from "./svelte/Account.svelte"; import Account from "./svelte/Account.svelte";
import Channel from "./svelte/Channel.svelte"; import Channel from "./svelte/Channel.svelte";
import Mustache from "mustache"; // import Mustache from "mustache";
import 'htmx.org';
Mustache.escape = function (value) {
return value;
};
// Mustache.escape = function (value) {
// return value;
// };
// Define all components // Define all components
const entryComponents = { const entryComponents = {
account: Account, account: Account,
channel: Channel, channel: Channel,
}; };
let loadedComponents = []; let loadedComponents = [];
let loadSvelte = function () { let loadSvelte = function () {
loadedComponents.map((comp) => comp.$destroy()); loadedComponents.map((comp) => comp.$destroy());
loadedComponents = []; loadedComponents = [];
const elements = document.body.querySelectorAll(".lucent-component"); const elements = document.body.querySelectorAll(".lucent-component");
if (elements.length === 0) { if (elements.length === 0) {
return; return;
}
const loadElement = function (element) {
const componentId = element.attributes["data-layout"].value;
const [_, component] = Object.entries(entryComponents).find(
([key, _]) => componentId === key,
);
if (!component) {
return [];
} }
const loadElement = function (element) {
const componentId = element.attributes["data-layout"].value;
const [_, component] = Object.entries(entryComponents).find(
([key, _]) => componentId === key
);
if (!component) {
return [];
}
const jsonData = document.getElementById( const jsonData = document.getElementById("json-" + componentId).innerHTML;
"json-" + componentId const props = JSON.parse(jsonData);
).innerHTML; const compOptions = {
const props = JSON.parse(jsonData); target: element,
props.axios = axiosInstance; props: props,
const compOptions = {
target: element,
props: props,
};
loadedComponents = [...loadedComponents, new component(compOptions)];
}; };
Array.from(elements).map(loadElement);
loadedComponents = [...loadedComponents, new component(compOptions)];
};
Array.from(elements).map(loadElement);
}; };
// document.addEventListener("turbo:load", loadSvelte); // document.addEventListener("turbo:load", loadSvelte);
+4 -7
View File
@@ -4,7 +4,7 @@
import Verify from "./account/Verify.svelte"; import Verify from "./account/Verify.svelte";
import Profile from "./account/Profile.svelte"; import Profile from "./account/Profile.svelte";
import SetupIndex from "./setup/Index.svelte"; import SetupIndex from "./setup/Index.svelte";
import {setContext} from "svelte"; import { setContext } from "svelte";
const components = { const components = {
register: Register, register: Register,
@@ -23,10 +23,7 @@
setContext("channel", channel); setContext("channel", channel);
setContext("user", user); setContext("user", user);
</script> </script>
<div style="text-align: center;background: var(--p20);padding: 20px;color: var(--p90)">
<h1><a class="text-decoration-none" href="{channel.lucentUrl}">{channel.name ?? "Lucent Setup"}</a></h1>
</div>
<div>
<svelte:component this={components[view]} {title} {...data}/>
</div>
<div>
<svelte:component this={components[view]} {channel} {title} {...data} />
</div>
+51 -37
View File
@@ -1,54 +1,68 @@
<script> <script>
import {getContext} from "svelte"; import { getContext } from "svelte";
import SpinnerButton from "../common/SpinnerButton.svelte"; import { apiPost } from "../../helpers";
const channel = getContext("channel"); const channel = getContext("channel");
let email = ""; let email = "";
let message = ""; let submitted = false;
function login(e) { function login(e) {
e.preventDefault(); e.preventDefault();
axios apiPost(channel.lucentUrl + "/login", { email: email })
.post(channel.lucentUrl + "/login", { .then(() => {
email: email, submitted = true;
}) })
.then((response) => { .catch(() => {});
console.log(response)
message = "You will receive an email with a login link"
})
.catch((error) => {
});
} }
</script> </script>
<div class="wrapper-tiny"> <div class="scope-login">
{#if message} <div class="bg-image"></div>
<div class="alert alert-info" role="alert"> <div class="login-form">
{message} {#if submitted}
</div> <div class="alert alert-info" role="alert">
<p>
{:else} You will receive an email with a login link at <b>{email}</b
>.
<form on:submit={login}> </p>
<div class="mb-3"> <p>Check your spam folder</p>
<label for="emailaddress" class="form-label">Email address</label>
<input
type="email"
bind:value={email}
class="form-control"
id="emailaddress"
required
/>
</div> </div>
{:else}
<div class="form">
<h2 class="mb-5">Enter Lucent</h2>
<form on:submit={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"
bind:value={email}
class="form-control"
id="emailaddress"
required
/>
</div>
<div class="text-center mt-5 d-block"> <button class="bt bt-primary">
<SpinnerButton label="Login"/> Send email
<img
alt="indicator"
id="indicator"
class="htmx-indicator"
src="/img/spinner.svg"
/>
</button>
</form>
</div> </div>
{/if}
</div>
</form>
{/if}
</div> </div>
+25 -26
View File
@@ -1,43 +1,42 @@
<script> <script>
import {getContext} from "svelte"; import { getContext } from "svelte";
import SpinnerButton from "../common/SpinnerButton.svelte"; import { apiPost } from "../../helpers";
import SuccessAlert from "../common/SuccessAlert.svelte";
const channel = getContext("channel"); const channel = getContext("channel");
export let email; export let email;
export let token; export let token;
let successAlert;
function login(e) { function login(e) {
e.preventDefault(); e.preventDefault();
axios apiPost(channel.lucentUrl + "/verify", {
.post(channel.lucentUrl + "/verify", { email: email,
email: email, token: token,
token: token, })
})
.then((response) => { .then((response) => {
window.location = channel.lucentUrl; window.location = channel.lucentUrl;
}) })
.catch((error) => { .catch((error) => {});
});
} }
</script> </script>
<SuccessAlert bind:this={successAlert}/> <div class="scope-login">
<div class="wrapper-tiny"> <div class="bg-image"></div>
<div class="login-form">
<form on:submit={login}> <div class="form">
<div class="mb-3 text-center"> <h2 class="mb-5">Welcome to Lucent</h2>
<h3>Login as {email}</h3> <form on:submit={login}>
<button class="bt bt-primary">
Enter as {email}
<img
alt="indicator"
id="indicator"
class="htmx-indicator"
src="/img/spinner.svg"
/>
</button>
</form>
<div class="form-errors"></div>
</div> </div>
</div>
<div class="text-center mt-5 d-block">
<SpinnerButton label="Enter"/>
</div>
</form>
</div> </div>
+8 -8
View File
@@ -3,11 +3,11 @@
export let disabled = false; export let disabled = false;
</script> </script>
<button type="submit" class="button secondary btn-spinner" {disabled}> <button type="submit" class="button secondary btn-spinner" {disabled}>
<span <span
class="spinner-border spinner-border-sm" class="spinner-border spinner-border-sm"
role="status" role="status"
aria-hidden="true" aria-hidden="true"
/> />
{label} {label}
</button> </button>
+6 -7
View File
@@ -1,18 +1,17 @@
<script> <script>
import { getContext, onMount } from "svelte"; import { getContext, onMount } from "svelte";
import RecordRow from "./RecordRow.svelte"; import RecordRow from "./RecordRow.svelte";
import { apiGet } from "../../helpers";
const channel = getContext("channel"); const channel = getContext("channel");
let records = []; let records = [];
let graph = null; let graph = null;
let users = []; let users = [];
onMount(() => { onMount(() => {
axios apiGet(channel.lucentUrl + "/home/records")
.get(channel.lucentUrl + "/home/records") .then((data) => {
.then((response) => { records = data.records;
records = response.data.records; users = data.users;
graph = response.data.graph;
users = response.data.users;
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
@@ -27,7 +26,7 @@
<tbody> <tbody>
{#each records as record (record.id)} {#each records as record (record.id)}
<tr> <tr>
<RecordRow {graph} {record} {users} /> <RecordRow {record} {users} />
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
-1
View File
@@ -7,7 +7,6 @@
const channel = getContext("channel"); const channel = getContext("channel");
export let users; export let users;
export let graph;
export let record; export let record;
let schema = channel.schemas.find((s) => s.name === record.schema); let schema = channel.schemas.find((s) => s.name === record.schema);
let frieldlyUpdatedAt = formatDistanceToNow(parseJSON(record.updatedAt), { let frieldlyUpdatedAt = formatDistanceToNow(parseJSON(record.updatedAt), {
+16 -8
View File
@@ -1,20 +1,28 @@
<script> <script>
import Step from "./Step.svelte" import Step from "./Step.svelte";
export let channel;
export let steps; export let steps;
export let allSuccess = false; export let allSuccess = false;
console.log(steps);
</script> </script>
<div class="wrapper-tiny">
<div
style="text-align: center;background: var(--p20);padding: 20px;color: var(--p90)"
>
<h1>
<a class="text-decoration-none" href={channel.lucentUrl}
>{channel.name ?? "Lucent Setup"}</a
>
</h1>
</div>
<div class="wrapper-tiny">
{#each steps as step} {#each steps as step}
<Step {step}></Step> <Step {step}></Step>
{/each} {/each}
<div style="text-align: center;margin-top: 30px;"> <div style="text-align: center;margin-top: 30px;">
{#if allSuccess} {#if allSuccess}
<a href="/lucent/register" class="bt">Create the first user</a> <a href="/lucent/register" class="bt">Create the first user</a>
{/if} {/if}
</div> </div>
</div> </div>
-9
View File
@@ -1,9 +0,0 @@
<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>
-37
View File
@@ -1,37 +0,0 @@
@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="{{config("lucent.url")}}/lucent/login" >
@csrf
<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
@@ -1,24 +0,0 @@
@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="{{config("lucent.url")}}/lucent/verify" hx-redirect="{{config("lucent.url")}}/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
@@ -1,43 +0,0 @@
@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>
@@ -1,4 +0,0 @@
<button class="bt bt-primary">
{{$slot}}
<img alt="indicator" id="indicator" class="htmx-indicator" src="/img/spinner.svg"/>
</button>
-4
View File
@@ -1,4 +0,0 @@
<div class="notice {{$type ?? "info"}}">
<div class="title">{{$title}}</div>
<div class="content">{{ $slot }}</div>
</div>
-9
View File
@@ -1,9 +0,0 @@
@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
@@ -1,23 +0,0 @@
@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
@@ -1,21 +0,0 @@
<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>
@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>
-1
View File
@@ -6,7 +6,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield('title') - Lucent Data Platform</title> <title>@yield('title') - Lucent Data Platform</title>
<meta name="htmx-config" content='{"selfRequestsOnly": false}' />
@if(config("lucent.env") === "production") @if(config("lucent.env") === "production")
<!-- if production --> <!-- if production -->
<link rel="stylesheet" href="{{url('vendor/lucent/dist/'.$manifest['main.js']["css"][0])}}"/> <link rel="stylesheet" href="{{url('vendor/lucent/dist/'.$manifest['main.js']["css"][0])}}"/>
-33
View File
@@ -1,33 +0,0 @@
@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" : ""}}
@endif
</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>
@@ -1,7 +0,0 @@
@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>
-22
View File
@@ -1,22 +0,0 @@
<a class="nav-item" href="/lucent">{{$channel->name}}</a>
<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>
+6 -7
View File
@@ -9,7 +9,6 @@ use Illuminate\Support\Str;
use Lucent\Channel\ChannelService; use Lucent\Channel\ChannelService;
use Lucent\LucentException; use Lucent\LucentException;
use Lucent\Mail\LoginMail; use Lucent\Mail\LoginMail;
use Filament\Facades\Filament;
readonly class AuthServiceLucent implements AuthService readonly class AuthServiceLucent implements AuthService
{ {
@@ -41,8 +40,8 @@ readonly class AuthServiceLucent implements AuthService
name: new Name($this->session->get("user.name")), name: new Name($this->session->get("user.name")),
email: new Email($this->session->get("user.email")), email: new Email($this->session->get("user.email")),
roles: $this->session->get("user.roles"), roles: $this->session->get("user.roles"),
createdAt: $this->session->get("user.createdAt"), createdAt: Carbon::parse($this->session->get("user.createdAt")),
updatedAt: $this->session->get("user.updatedAt"), updatedAt: Carbon::parse($this->session->get("user.updatedAt")),
loggedInAt: null, loggedInAt: null,
mailToken: null, mailToken: null,
); );
@@ -81,7 +80,7 @@ readonly class AuthServiceLucent implements AuthService
} }
$newUser = $user->get(); $newUser = $user->get();
$newUser->updatedAt = Carbon::now()->toJson(); $newUser->updatedAt = Carbon::now();
$newUser->mailToken = null; $newUser->mailToken = null;
$this->userRepo->update($newUser); $this->userRepo->update($newUser);
$this->session->put(["user" => $user->get()->safe()]); $this->session->put(["user" => $user->get()->safe()]);
@@ -110,9 +109,9 @@ readonly class AuthServiceLucent implements AuthService
name: new Name($name), name: new Name($name),
email: new Email($email), email: new Email($email),
roles: $this->validateRoles($roles), roles: $this->validateRoles($roles),
createdAt: Carbon::now()->toJson(), createdAt: Carbon::now(),
updatedAt: Carbon::now()->toJson(), updatedAt: Carbon::now(),
loggedInAt: Carbon::now()->toJson(), loggedInAt: Carbon::now(),
mailToken: Token::new(32), mailToken: Token::new(32),
); );
+1 -1
View File
@@ -14,7 +14,7 @@ interface UserRepo
*/ */
public function all(): Collection; public function all(): Collection;
public static function insert(User $user): void; public function insert(User $user): void;
public function update(User $user): void; public function update(User $user): void;
+1 -1
View File
@@ -30,7 +30,7 @@ class UserRepoLucent implements UserRepo
return new Collection($users); return new Collection($users);
} }
public static function insert(User $user): void public function insert(User $user): void
{ {
$userData = toArray($user); $userData = toArray($user);
$userData["roles"] = json_encode($userData["roles"]); $userData["roles"] = json_encode($userData["roles"]);
+1 -1
View File
@@ -30,7 +30,7 @@ class UserRepoLunar implements UserRepo
return new Collection($users); return new Collection($users);
} }
public static function insert(User $user): void public function insert(User $user): void
{ {
$userData = toArray($user); $userData = toArray($user);
$userData["roles"] = json_encode($userData["roles"]); $userData["roles"] = json_encode($userData["roles"]);
+20 -7
View File
@@ -67,22 +67,35 @@ class AuthController
); );
} }
return view("lucent::auth.login"); return $this->svelte->render(
layout: "account",
view: "login",
title: "Login",
);
} }
public function postLogin(Request $request) public function postLogin(Request $request)
{ {
$this->authService->sendLoginEmail($request->input("email")); $this->authService->sendLoginEmail($request->input("email"));
return [];
return view("lucent::auth.login-success");
} }
public function verify(Request $request): View public function verify(Request $request): View
{ {
return view("lucent::auth.verify", [ // return view("lucent::auth.verify", [
"email" => $request->input("email"), // "email" => $request->input("email"),
"token" => $request->input("token"), // "token" => $request->input("token"),
]); // ]);
return $this->svelte->render(
layout: "account",
view: "verify",
title: "Enter",
data: [
"email" => $request->input("email"),
"token" => $request->input("token"),
],
);
} }
public function postVerify(Request $request) public function postVerify(Request $request)
-1
View File
@@ -56,7 +56,6 @@ class HomeController extends Controller
return ok([ return ok([
"users" => $users, "users" => $users,
"records" => $graph->getRootRecords()->toArray(), "records" => $graph->getRootRecords()->toArray(),
"graph" => toArray($graph),
"modalUrl" => $request->fullUrl(), "modalUrl" => $request->fullUrl(),
]); ]);
} }
+5 -1
View File
@@ -9,6 +9,7 @@ use Illuminate\Support\ServiceProvider;
use Intervention\Image\ImageManager; use Intervention\Image\ImageManager;
use Lucent\Account\AuthService; use Lucent\Account\AuthService;
use Lucent\Account\AuthServiceLunar; use Lucent\Account\AuthServiceLunar;
use Lucent\Account\AuthServiceLucent;
use Lucent\Account\UserRepo; use Lucent\Account\UserRepo;
use Lucent\Account\UserRepoLucent; use Lucent\Account\UserRepoLucent;
use Lucent\Account\UserRepoLunar; use Lucent\Account\UserRepoLunar;
@@ -51,7 +52,10 @@ class LucentServiceProvider extends ServiceProvider
}); });
$this->app->bind(AuthService::class, function ($app) { $this->app->bind(AuthService::class, function ($app) {
return $app->make(AuthServiceLunar::class); return match ($app->make(ChannelService::class)->channel->auth) {
ChannelAuth::LUNAR => $app->make(AuthServiceLunar::class),
ChannelAuth::LUCENT => $app->make(AuthServiceLucent::class),
};
}); });
} }
+3 -1
View File
@@ -23,7 +23,9 @@ class Svelte
mixed $data = [], mixed $data = [],
): View|Factory { ): View|Factory {
$context = []; $context = [];
$context["user"] = toArray($this->authService->getCurrentUser()); $context["user"] = $this->authService->isLoggedIn()
? $this->authService->getCurrentUser()
: null;
$context["view"] = $view; $context["view"] = $view;
$context["layout"] = $layout; $context["layout"] = $layout;
$context["title"] = $title; $context["title"] = $title;