Setup Inertia (#593)

This commit is contained in:
Saeed Vaziry
2025-05-10 10:10:11 +02:00
committed by GitHub
parent 6eb88c7c6e
commit 38bafd7654
305 changed files with 13378 additions and 15435 deletions

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
<script>
(function () {
const appearance = '{{ $appearance ?? 'system' }}';
if (appearance === 'system') {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (prefersDark) {
document.documentElement.classList.add('dark');
}
}
})();
</script>
{{-- Inline style to set the HTML background color based on our theme in app.css --}}
<style>
html {
background-color: oklch(1 0 0);
}
html.dark {
background-color: oklch(0.145 0 0);
}
</style>
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="preconnect" href="https://fonts.bunny.net" />
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
@routes
@viteReactRefresh
@vite(['resources/js/app.tsx', "resources/js/pages/{$page['component']}.tsx"])
@inertiaHead
</head>
<body class="font-sans antialiased">
@inertia
</body>
</html>

View File

@ -1,5 +0,0 @@
<div class="p-6 text-xs">
<a href="https://github.com/vitodeploy/vito/releases/tag/{{ config("app.version") }}" target="_blank">
V{{ show_vito_version() }}
</a>
</div>

View File

@ -1,39 +0,0 @@
<svg class="w-[30px] rounded-md" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1024" height="1024" rx="50" fill="#312E81" />
<rect width="1024" height="1024" rx="50" fill="url(#paint0_linear_29_4)" />
<g filter="url(#filter0_d_29_4)">
<path
d="M512.206 814.3C500.806 814.3 491.506 811.6 484.306 806.2C477.106 800.8 471.406 792.7 467.206 781.9L219.706 215.8C215.506 205.6 214.306 197.2 216.106 190.6C217.906 183.4 221.806 177.7 227.806 173.5C234.406 169.3 241.906 167.2 250.306 167.2C261.706 167.2 270.106 169.9 275.506 175.3C281.506 180.1 286.306 187.3 289.906 196.9L527.506 748.6H498.706L735.406 196C739.606 187 744.706 180.1 750.706 175.3C756.706 169.9 765.106 167.2 775.906 167.2C784.306 167.2 791.206 169.3 796.606 173.5C802.606 177.7 806.206 183.4 807.406 190.6C809.206 197.8 808.006 206.2 803.806 215.8L556.306 781.9C552.106 792.7 546.406 800.8 539.206 806.2C532.606 811.6 523.606 814.3 512.206 814.3Z"
fill="white"
/>
</g>
<defs>
<filter
id="filter0_d_29_4"
x="209.406"
y="167.2"
width="604.7"
height="655.1"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_29_4" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_29_4" result="shape" />
</filter>
<linearGradient id="paint0_linear_29_4" x1="512" y1="0" x2="512" y2="1024" gradientUnits="userSpaceOnUse">
<stop stop-color="#6366F1" />
<stop offset="1" stop-color="#393B8B" />
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,5 +0,0 @@
<div
{{ $attributes->merge(["class" => "font-mono relative h-[500px] w-full overflow-auto whitespace-pre-line rounded-xl border border-gray-200 bg-black p-5 text-gray-50 dark:border-gray-800"]) }}
>
{{ $slot }}
</div>

View File

@ -1,166 +0,0 @@
<div
x-data="{
user: '{{ $server->ssh_user }}',
running: false,
dir: '{{ cache()->get("console.$server->id.dir", "~") }}',
command: '',
output: '',
serverName: '{{ $server->name }}',
shellPrefix: '',
clearAfterCommand: false,
runUrl: '{{ route("servers.console.run", ["server" => $server]) }}',
init() {
this.setShellPrefix()
$watch('user', async (value) => {
await this.getWorkingDir()
})
const consoleOutput = document.getElementById('console-output')
consoleOutput.addEventListener('mouseup', (event) => {
if (window.getSelection()?.toString()) {
return
}
this.focusCommand()
})
this.focusCommand()
document.addEventListener('keydown', (event) => {
if (event.ctrlKey && event.key === 'l') {
event.preventDefault()
if (this.running) return
this.output = ''
}
})
},
async run() {
if (! this.command) return
this.running = true
let output = this.shellPrefix + ' ' + this.command + '\n'
if (this.clearAfterCommand) {
this.output = output
} else {
this.output += output
}
setTimeout(() => {
document.getElementById('console-output').scrollTop =
document.getElementById('console-output').scrollHeight
}, 100)
const fetchOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}',
},
body: JSON.stringify({
user: this.user,
command: this.command,
}),
}
this.command = ''
const response = await fetch(this.runUrl, fetchOptions)
const reader = response.body.getReader()
const decoder = new TextDecoder('utf-8')
this.setShellPrefix()
while (true) {
if (! this.running) {
reader.cancel()
this.output += '\nStopped!'
break
}
const { value, done } = await reader.read()
if (done) break
const textChunk = decoder.decode(value, { stream: true })
this.output += textChunk
setTimeout(() => {
document.getElementById('console-output').scrollTop =
document.getElementById('console-output').scrollHeight
}, 100)
}
this.output += '\n'
await this.getWorkingDir()
this.running = false
setTimeout(() => {
document.getElementById('command').focus()
}, 100)
},
stop() {
this.running = false
},
setShellPrefix() {
this.shellPrefix = `${this.user}@${this.serverName}:${this.dir}$`
},
focusCommand() {
document.getElementById('command').focus()
},
async getWorkingDir() {
const response = await fetch(
'{{ route("servers.console.working-dir", ["server" => $server]) }}',
)
if (response.ok) {
const data = await response.json()
this.dir = data.dir
this.setShellPrefix()
}
},
}"
>
<div class="relative">
<form class="flex items-center justify-between">
<x-filament::input.wrapper>
<x-filament::input.select id="user" name="user" x-model="user" class="w-full" x-bind:disabled="running">
@foreach ($server->getSshUsers() as $user)
<option value="{{ $user }}">{{ $user }}</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
<div class="flex items-center">
<x-filament::button
color="gray"
type="button"
x-on:click="output = ''"
icon="heroicon-o-trash"
tooltip="Clear"
x-show="!running"
>
Clear
</x-filament::button>
<x-filament::button
color="gray"
type="button"
id="btn-stop"
x-on:click="stop"
x-show="running"
icon="heroicon-o-stop"
tooltip="Stop"
class="ml-2"
>
Stop
</x-filament::button>
</div>
</form>
<x-console-view id="console-output" class="mt-5">
<div class="w-full" x-text="output"></div>
</x-console-view>
<div
class="relative -mt-5 flex h-[50px] w-full items-center rounded-b-xl border-b border-l border-r border-gray-200 bg-black px-5 font-mono text-gray-50 dark:border-gray-800"
>
<form class="flex w-full items-center" x-show="!running" onsubmit="return false" id="console-form">
<div x-text="shellPrefix"></div>
<input
type="text"
class="h-5 flex-grow border-0 bg-transparent p-0 px-1 outline-none ring-0 focus:outline-none focus:ring-0"
autofocus
id="command"
name="command"
x-model="command"
autocomplete="off"
/>
<button type="submit" id="btn-run" x-on:click="run" class="hidden"></button>
</form>
</div>
</div>
</div>

View File

@ -1,7 +0,0 @@
<div
@if (isset($getExtraAttributeBag))
{{ $getExtraAttributeBag() }}
@endif
>
{!! $content !!}
</div>

View File

@ -1 +0,0 @@
@livewire($widget, $params ?? [], key($widget))

View File

@ -1,6 +0,0 @@
<div>
<form>
{{ $this->form }}
</form>
<x-filament-actions::modals />
</div>

View File

@ -1,4 +0,0 @@
<div>
{{ $this->infolist }}
<x-filament-actions::modals />
</div>

View File

@ -1 +0,0 @@
<a href="{{ $href }}" @if($external) target="_blank" @endif>{{ $text }}</a>

View File

@ -1,11 +0,0 @@
<div {{ $this->getExtraAttributesBag() }}>
<x-filament-panels::page>
@if (method_exists($this, "getSecondSubNavigation") && count($this->getSecondSubNavigation()) > 0)
<x-filament-panels::page.sub-navigation.tabs class="!flex" :navigation="$this->getSecondSubNavigation()" />
@endif
@foreach ($this->getWidgets() as $key => $widget)
@livewire($widget[0], $widget[1] ?? [], key(class_basename($widget[0]) . "-" . $key))
@endforeach
</x-filament-panels::page>
</div>

View File

@ -1,13 +0,0 @@
@props(["value" => 0])
<div class="bg-primary-200 dark:bg-primary-500 relative flex h-6 overflow-hidden rounded text-xs dark:bg-opacity-10">
<div
style="width: {{ $value }}%"
class="bg-primary-500 flex flex-col justify-center whitespace-nowrap text-center text-white shadow-none transition-all duration-500 ease-out"
></div>
<span
class="{{ $value >= 40 ? "text-white" : "text-black dark:text-white" }} absolute left-0 right-0 top-1 text-center font-semibold"
>
{{ $value }}%
</span>
</div>

View File

@ -1,9 +0,0 @@
<div>
<div>
<div
class="border-{{ $getColor() }}-500 bg-{{ $getColor() }}-100 text-{{ $getColor() }}-700 dark:bg-{{ $getColor() }}-500 dark:text-{{ $getColor() }}-500 rounded-lg border border-l-4 px-4 py-3 dark:bg-opacity-10"
>
{!! $getMessage() !!}
</div>
</div>
</div>

View File

@ -1,18 +0,0 @@
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field" :label-sr-only="$isLabelHidden()">
<div
wire:ignore
x-data="codeEditorFormComponent({
state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }},
options: @js($getOptions()),
})"
>
<div>
<div
id="{{ $getId() }}"
{{ $attributes->merge(["class" => "mt-1 min-h-[400px] w-full border border-gray-100 dark:border-gray-700"]) }}
class="ace-vito ace_dark"
></div>
<textarea id="textarea-{{ $getId() }}" style="display: none" x-model="state"></textarea>
</div>
</div>
</x-dynamic-component>

View File

@ -1,19 +0,0 @@
<x-filament-forms::field-wrapper.label>
{{ $getLabel() }}
</x-filament-forms::field-wrapper.label>
<div x-data="{ state: $wire.$entangle('{{ $getStatePath() }}') }" class="mt-1 grid grid-cols-6 gap-2">
@foreach (config("core.server_providers") as $p)
<div
class="flex w-full cursor-pointer items-center justify-center rounded-md border-2 bg-transparent px-3 pb-2 pt-3"
@click="state = '{{ $p }}'; $wire.set('{{ $getStatePath() }}', state)"
:class="{ 'border-primary-600': state === '{{ $p }}', 'border-primary-200 dark:border-primary-600 dark:border-opacity-20': state !== '{{ $p }}' }"
>
<div class="flex w-full flex-col items-center justify-center text-center">
<x-icon :name="$p" class="h-7" />
<span class="md:text-normal mt-2 hidden text-sm md:block">
{{ $p }}
</span>
</div>
</div>
@endforeach
</div>

View File

@ -1,27 +0,0 @@
@props([
"heading" => null,
"logo" => true,
"subheading" => null,
])
<header class="fi-simple-header flex h-8 items-center justify-between">
<div class="flex items-center gap-1">
@if ($logo)
<x-filament-panels::logo />
@endif
@if (filled($heading))
<h1
class="fi-simple-header-heading text-center text-2xl font-bold tracking-tight text-gray-950 dark:text-white"
>
{{ $heading }}
</h1>
@endif
</div>
@if (filled($subheading))
<p class="fi-simple-header-subheading text-center text-sm text-gray-500 dark:text-gray-400">
{{ $subheading }}
</p>
@endif
</header>

View File

@ -1,53 +0,0 @@
<x-filament::dropdown placement="bottom-start" :size="true" :teleport="true" class="pointer-choices -mx-2">
<x-slot name="trigger">
<button
@if (filament()->isSidebarCollapsibleOnDesktop())
x-data="{ tooltip: false }"
x-effect="
tooltip = $store.sidebar.isOpen
? false
: {
content: @js($currentProject->name),
placement: document.dir === 'rtl' ? 'left' : 'right',
theme: $store.theme,
}
"
x-tooltip.html="tooltip"
@endif
type="button"
class="fi-tenant-menu-trigger group flex w-full items-center justify-center gap-x-3 rounded-lg p-2 text-sm font-medium outline-none transition duration-75 hover:bg-gray-100 focus-visible:bg-gray-100 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
>
<div
class="bg-primary-700-gradient text-md flex h-8 w-8 items-center justify-center rounded-lg capitalize text-white"
>
{{ $currentProject->name[0] }}
</div>
<span
@if (filament()->isSidebarCollapsibleOnDesktop())
x-show="$store.sidebar.isOpen"
@endif
class="grid justify-items-start text-start"
>
<span class="text-gray-950 dark:text-white">
{{ $currentProject->name }}
</span>
</span>
<x-filament::icon
icon="heroicon-m-chevron-down"
icon-alias="panels::tenant-menu.toggle-button"
:x-show="filament()->isSidebarCollapsibleOnDesktop() ? '$store.sidebar.isOpen' : null"
class="ms-auto h-5 w-5 shrink-0 text-gray-400 transition duration-75 group-hover:text-gray-500 group-focus-visible:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-400 dark:group-focus-visible:text-gray-400"
/>
</button>
</x-slot>
<x-filament::dropdown.list>
@foreach ($projects as $project)
<x-filament::dropdown.list.item wire:click="updateProject({{ $project }})" class="cursor-pointer" tag="a">
{{ $project->name }}
</x-filament::dropdown.list.item>
@endforeach
</x-filament::dropdown.list>
</x-filament::dropdown>