Header layout rather than sidebar layout

This commit is contained in:
2025-04-08 19:17:12 +01:00
parent a7386814c7
commit bde11c0b8c
8 changed files with 131 additions and 39 deletions

View File

@@ -2,10 +2,20 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Organisation;
use Illuminate\Http\Request; use Illuminate\Http\Request;
class ApplicationController extends Controller class ApplicationController extends Controller
{ {
public function index(Request $request)
{
$organisation = Organisation::with('applications')->findOrFail($request->route('organisation'));
return inertia('applications/Index', [
'applications' => $organisation->applications,
]);
}
public function show(Request $request) public function show(Request $request)
{ {
$id = $request->route('application'); $id = $request->route('application');

View File

@@ -18,7 +18,7 @@ import UserMenuContent from '@/components/UserMenuContent.vue';
import { getInitials } from '@/composables/useInitials'; import { getInitials } from '@/composables/useInitials';
import type { BreadcrumbItem, NavItem } from '@/types'; import type { BreadcrumbItem, NavItem } from '@/types';
import { Link, usePage } from '@inertiajs/vue3'; import { Link, usePage } from '@inertiajs/vue3';
import { BookOpen, Folder, LayoutGrid, Menu, Search } from 'lucide-vue-next'; import { AppWindowIcon, BookOpen, Folder, LayoutGrid, Menu, Search, ServerIcon } from 'lucide-vue-next';
import { computed } from 'vue'; import { computed } from 'vue';
interface Props { interface Props {
@@ -39,24 +39,41 @@ const activeItemStyles = computed(
); );
const mainNavItems: NavItem[] = [ const mainNavItems: NavItem[] = [
{ // {
title: 'Dashboard', // title: 'Dashboard',
href: '/dashboard', // href: new URL(route('dashboard')).pathname,
icon: LayoutGrid, // icon: LayoutGrid,
}, // },
]; ];
if (page.props.organisation) {
mainNavItems.push({
title: 'Applications',
href: new URL(route('applications.index', {
organisation: page.props?.organisation?.id
})).pathname,
icon: AppWindowIcon,
});
mainNavItems.push({
title: 'Servers',
href: new URL(route('servers.index', {
organisation: page.props?.organisation?.id
})).pathname,
icon: ServerIcon,
})
}
const rightNavItems: NavItem[] = [ const rightNavItems: NavItem[] = [
{ // {
title: 'Repository', // title: 'Repository',
href: 'https://github.com/laravel/vue-starter-kit', // href: 'https://github.com/laravel/vue-starter-kit',
icon: Folder, // icon: Folder,
}, // },
{ // {
title: 'Documentation', // title: 'Documentation',
href: 'https://laravel.com/docs/starter-kits', // href: 'https://laravel.com/docs/starter-kits',
icon: BookOpen, // icon: BookOpen,
}, // },
]; ];
</script> </script>

View File

@@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { WavesIcon } from 'lucide-vue-next';
import type { HTMLAttributes } from 'vue'; import type { HTMLAttributes } from 'vue';
defineOptions({ defineOptions({
@@ -13,12 +14,5 @@ defineProps<Props>();
</script> </script>
<template> <template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 42" :class="className" v-bind="$attrs"> <WavesIcon v-bind="$attrs" :class="className" />
<path
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.2 5.633 8.6.855 0 5.633v26.51l16.2 9 16.2-9v-8.442l7.6-4.223V9.856l-8.6-4.777-8.6 4.777V18.3l-5.6 3.111V5.633ZM38 18.301l-5.6 3.11v-6.157l5.6-3.11V18.3Zm-1.06-7.856-5.54 3.078-5.54-3.079 5.54-3.078 5.54 3.079ZM24.8 18.3v-6.157l5.6 3.111v6.158L24.8 18.3Zm-1 1.732 5.54 3.078-13.14 7.302-5.54-3.078 13.14-7.3v-.002Zm-16.2 7.89 7.6 4.222V38.3L2 30.966V7.92l5.6 3.111v16.892ZM8.6 9.3 3.06 6.222 8.6 3.143l5.54 3.08L8.6 9.3Zm21.8 15.51-13.2 7.334V38.3l13.2-7.334v-6.156ZM9.6 11.034l5.6-3.11v14.6l-5.6 3.11v-14.6Z"
/>
</svg>
</template> </template>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import AppLayout from '@/layouts/app/AppSidebarLayout.vue'; import AppLayout from '@/layouts/app/AppHeaderLayout.vue';
import type { BreadcrumbItemType } from '@/types'; import type { BreadcrumbItemType } from '@/types';
interface Props { interface Props {

View File

@@ -0,0 +1,54 @@
<script setup>
import { Badge } from '@/components/ui/badge';
import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import AppLayout from '@/layouts/AppLayout.vue';
import { Head, Link } from '@inertiajs/vue3';
const props = defineProps({
applications: {
type: [Object, null],
required: true,
},
});
</script>
<template>
<Head title="Dashboard" />
<AppLayout
:breadcrumbs="[
{
title: 'Applications',
href: route('applications.index', {
organisation: $page.props.organisation.id,
}),
},
]"
>
<div class="flex justify-between items-center gap-3 p-4">
<h2 class="text-3xl font-bold tracking-tight">Applications</h2>
<div>
<!-- <Button :as="Link" :href="route('applications.create', {
organisation: $page.props.organisation.id,
})">Create</Button> -->
</div>
</div>
<div class="grid gap-4 rounded-xl p-4 md:grid-cols-2 lg:grid-cols-3">
<Card v-for="application in applications.data" :key="`application{$applications.id}`" class="relative w-full">
<CardHeader>
<CardTitle>{{ application.name }}</CardTitle>
</CardHeader>
<Link
:href="
route('applications.show', {
organisation: $page.props.organisation.id,
application: application.id,
})
"
class="absolute inset-0"
></Link>
</Card>
</div>
</AppLayout>
</template>

View File

@@ -1,8 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import AppLayout from '@/layouts/AppLayout.vue'; import AppLayout from '@/layouts/AppLayout.vue';
import { type BreadcrumbItem } from '@/types'; import { type BreadcrumbItem } from '@/types';
import { Head } from '@inertiajs/vue3'; import { Head, Link } from '@inertiajs/vue3';
import PlaceholderPattern from '../components/PlaceholderPattern.vue'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { ChevronRightIcon } from 'lucide-vue-next';
defineProps({
organisations: {
type: Array,
required: true,
},
});
const breadcrumbs: BreadcrumbItem[] = [ const breadcrumbs: BreadcrumbItem[] = [
{ {
@@ -16,16 +24,21 @@ const breadcrumbs: BreadcrumbItem[] = [
<Head title="Dashboard" /> <Head title="Dashboard" />
<AppLayout :breadcrumbs="breadcrumbs"> <AppLayout :breadcrumbs="breadcrumbs">
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4"> <div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4 items-center">
<div>The plan:</div> <Card class="w-80">
<div>Organisations have applications</div> <CardHeader class="border-b border-b-muted-background">
<div>Applications have environments</div> <CardTitle>Your Organisation</CardTitle>
<div>Servers have services</div> <CardDescription>
<div>Services have slices, this could be a database table or a client in a websocket server</div> Select an organisation to view its details.
<div>Environments have SLICES</div> </CardDescription>
<div>Also servers need to be provisioned</div> </CardHeader>
<div>Users have SSH keys</div> <CardContent class="divide-y divide-y-muted-foreground p-0">
<div>Keystone has its own SSH keys</div> <Link v-for="organisation in organisations" :href="route('organisations.show', { organisation: organisation.id })" class="py-3 px-6 hover:bg-muted flex justify-between items-center">
<div>{{ organisation.name }}</div>
<ChevronRightIcon class="size-4 text-muted-foreground" />
</Link>
</CardContent>
</Card>
</div> </div>
</AppLayout> </AppLayout>
</template> </template>

View File

@@ -82,7 +82,7 @@ defineProps({
<template #fallback> Loading... </template> <template #fallback> Loading... </template>
<h3 class="mt-4 text-2xl font-bold tracking-tight">Server Providers</h3> <h3 class="mt-4 text-2xl font-bold tracking-tight">Server Providers</h3>
<p class="mb-4 text-sm text-muted-foreground">Manage your server providers.</p> <p class="mb-4 text-sm text-muted-foreground">Manage your server providers.</p>
<div class="border-muted-background divide-y-muted-background divide-y rounded-md border"> <div class="border-muted-background divide-y-muted-background divide-y rounded-md border max-w-80">
<div v-for="provider in providers" class="flex items-center gap-2 px-2 py-1"> <div v-for="provider in providers" class="flex items-center gap-2 px-2 py-1">
{{ provider.name }} {{ provider.name }}
<span class="ml-auto text-xs uppercase text-muted-foreground">{{ provider.type }}</span> <span class="ml-auto text-xs uppercase text-muted-foreground">{{ provider.type }}</span>

View File

@@ -12,7 +12,11 @@ use Illuminate\Support\Facades\Route;
Route::inertia('/', 'Welcome')->name('home'); Route::inertia('/', 'Welcome')->name('home');
Route::middleware(['auth', 'verified'])->group(function () { Route::middleware(['auth', 'verified'])->group(function () {
Route::inertia('dashboard', 'Dashboard')->name('dashboard'); Route::get('/dashboard', function () {
return inertia('Dashboard', [
'organisations' => auth()->user()->organisations,
]);
})->name('dashboard');
Route::prefix('organisations/{organisation}')->group(function () { Route::prefix('organisations/{organisation}')->group(function () {
Route::get('/', [OrganisationController::class, 'show'])->name('organisations.show'); Route::get('/', [OrganisationController::class, 'show'])->name('organisations.show');