mirror of
https://github.com/bdnugget/speedtest-tracker.git
synced 2026-11-07 08:37:27 +00:00
[Feature] Public dashboard and Getting Started pages (#822)
This commit is contained in:
1 parent
27964058c9
commit
3532c89b9c
12 files changed
+344
-5
No files matched your search
@@ -50,7 +50,7 @@ class RecentSpeedChartWidget extends ChartWidget
|
||||
return [
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => 'Download (Mbps)',
|
||||
'label' => 'Download',
|
||||
'data' => $results->map(fn ($item) => ! blank($item->download) ? toBits(convertSize($item->download), 2) : 0),
|
||||
'borderColor' => '#0ea5e9',
|
||||
'backgroundColor' => '#0ea5e9',
|
||||
@@ -59,7 +59,7 @@ class RecentSpeedChartWidget extends ChartWidget
|
||||
'tension' => 0.4,
|
||||
],
|
||||
[
|
||||
'label' => 'Upload (Mbps)',
|
||||
'label' => 'Upload',
|
||||
'data' => $results->map(fn ($item) => ! blank($item->upload) ? toBits(convertSize($item->upload), 2) : 0),
|
||||
'borderColor' => '#8b5cf6',
|
||||
'backgroundColor' => '#8b5cf6',
|
||||
@@ -72,6 +72,27 @@ class RecentSpeedChartWidget extends ChartWidget
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'scales' => [
|
||||
'x' => [
|
||||
'display' => true,
|
||||
'title' => [
|
||||
'display' => true,
|
||||
],
|
||||
],
|
||||
'y' => [
|
||||
'display' => true,
|
||||
'title' => [
|
||||
'display' => true,
|
||||
'text' => 'Mbps',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getType(): string
|
||||
{
|
||||
return 'line';
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Result;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$hasResults = Result::count() > 0;
|
||||
|
||||
return view($hasResults ? 'dashboard' : 'get-started');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class AppLayout extends Component
|
||||
{
|
||||
public $title = 'Page Title';
|
||||
|
||||
public function __construct($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('layouts.app');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:rgba(var(--gray-200),1)}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:rgba(var(--gray-400),1)}input::placeholder,textarea::placeholder{opacity:1;color:rgba(var(--gray-400),1)}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='rgba(var(--gray-500)%2c var(--tw-stroke-opacity%2c 1))' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity, 1));border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(Line truncated
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"resources/css/app.css": {
|
||||
"file": "assets/app-d8cd240f.css",
|
||||
"isEntry": true,
|
||||
"src": "resources/css/app.css"
|
||||
},
|
||||
"resources/css/filament/admin/theme.css": {
|
||||
"file": "assets/theme-182befaf.css",
|
||||
"isEntry": true,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<x-app-layout title="Dashboard">
|
||||
<div class="grid gap-4 sm:grid-cols-6 sm:gap-8">
|
||||
<div class="col-span-full">
|
||||
@livewire(\App\Filament\Widgets\StatsOverviewWidget::class)
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
@livewire(\App\Filament\Widgets\RecentSpeedChartWidget::class)
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
@livewire(\App\Filament\Widgets\RecentPingChartWidget::class)
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
@livewire(\App\Filament\Widgets\RecentJitterChartWidget::class)
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="h-full">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Getting Started - {{ config('app.name') }}</title>
|
||||
|
||||
{{-- Fonts --}}
|
||||
<link href="{{ asset('fonts/inter/inter.css') }}" rel="stylesheet" />
|
||||
|
||||
{{-- Styles --}}
|
||||
@filamentStyles
|
||||
@vite('resources/css/app.css')
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') ?? 'system'
|
||||
|
||||
if (
|
||||
theme === 'dark' ||
|
||||
(theme === 'system' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="h-full antialiased bg-gray-50 dark:bg-gray-950 text-gray-950 dark:text-white">
|
||||
<main class="flex flex-col justify-center min-h-full p-4 space-y-4 sm:mx-auto sm:p-6 lg:p-8 sm:max-w-3xl sm:space-y-8">
|
||||
<header>
|
||||
<h1 class="text-2xl font-bold tracking-tight text-gray-950 dark:text-white sm:text-3xl">{{ __("Getting Started") }} - {{ config('app.name') }}</h1>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<ul role="list" class="divide dark:divide-white/5 divide-white/80">
|
||||
<li class="relative flex items-center py-4 space-x-4">
|
||||
<div class="flex-auto min-w-0">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="flex-none p-1 rounded-full text-amber-400 bg-gray-100/10">
|
||||
<div class="w-2 h-2 bg-current rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<h2 class="min-w-0 text-sm font-semibold leading-6 text-white">
|
||||
<a href="{{ url('/admin/login') }}" class="flex gap-x-2">
|
||||
<span class="truncate">Sign In</span>
|
||||
<span class="text-amber-400">/</span>
|
||||
<span class="whitespace-nowrap">Admin Panel</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex items-center gap-x-2.5 text-sm leading-5 dark:text-gray-400 text-gray-950">
|
||||
<p class="truncate">
|
||||
Sign in to the admin panel to run your first speedtest or to setup scheduled tests.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg class="flex-none w-5 h-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</li>
|
||||
|
||||
<li class="relative flex items-center py-4 space-x-4">
|
||||
<div class="flex-auto min-w-0">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="flex-none p-1 rounded-full text-amber-400 bg-gray-100/10">
|
||||
<div class="w-2 h-2 bg-current rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<h2 class="min-w-0 text-sm font-semibold leading-6 text-white">
|
||||
<a href="https://docs.speedtest-tracker.dev/" target="_blank" rel="nofollow" class="flex gap-x-2">
|
||||
<span class="truncate">Getting Started</span>
|
||||
<span class="text-amber-400">/</span>
|
||||
<span class="whitespace-nowrap">Docs</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex items-center gap-x-2.5 text-sm leading-5 dark:text-gray-400 text-gray-950">
|
||||
<p class="truncate">
|
||||
Need help getting started with Speedtest Tracker? Check out the docs.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg class="flex-none w-5 h-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</li>
|
||||
|
||||
<li class="relative flex items-center py-4 space-x-4">
|
||||
<div class="flex-auto min-w-0">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="flex-none p-1 rounded-full text-amber-400 bg-gray-100/10">
|
||||
<div class="w-2 h-2 bg-current rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<h2 class="min-w-0 text-sm font-semibold leading-6 text-white">
|
||||
<a href="https://github.com/alexjustesen/speedtest-tracker" target="_blank" rel="nofollow" class="flex gap-x-2">
|
||||
<span class="truncate">GitHub</span>
|
||||
<span class="text-amber-400">/</span>
|
||||
<span class="whitespace-nowrap">Repo</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg class="flex-none w-5 h-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</li>
|
||||
|
||||
<li class="relative flex items-center py-4 space-x-4">
|
||||
<div class="flex-auto min-w-0">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="flex-none p-1 rounded-full text-amber-400 bg-gray-100/10">
|
||||
<div class="w-2 h-2 bg-current rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<h2 class="min-w-0 text-sm font-semibold leading-6 text-white">
|
||||
<a href="https://github.com/alexjustesen/speedtest-tracker/discussions" target="_blank" rel="nofollow" class="flex gap-x-2">
|
||||
<span class="truncate">Discussions</span>
|
||||
<span class="text-amber-400">/</span>
|
||||
<span class="whitespace-nowrap">Community</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg class="flex-none w-5 h-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</li>
|
||||
|
||||
<!-- More items... -->
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{-- Scripts --}}
|
||||
@filamentScripts
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>{{ $title }} - {{ config('app.name') }}</title>
|
||||
|
||||
{{-- Fonts --}}
|
||||
<link href="{{ asset('fonts/inter/inter.css') }}" rel="stylesheet" />
|
||||
|
||||
{{-- Styles --}}
|
||||
@filamentStyles
|
||||
@vite('resources/css/app.css')
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') ?? 'system'
|
||||
|
||||
if (
|
||||
theme === 'dark' ||
|
||||
(theme === 'system' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.matches)
|
||||
) {
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="min-h-screen antialiased bg-gray-50 dark:bg-gray-950 text-gray-950 dark:text-white">
|
||||
<main class="p-4 sm:p-6 lg:p-8 mx-auto max-w-{{ config('speedtest.content_width') }} space-y-4 sm:space-y-8">
|
||||
<header class="flex flex-col gap-4 sm:flex-row sm:justify-between sm:items-center">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold tracking-tight text-gray-950 dark:text-white sm:text-3xl">{{ $title ?? 'Page Title' }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex-shrink-0">
|
||||
<x-filament::button
|
||||
href="{{ url('/admin') }}"
|
||||
tag="a"
|
||||
>
|
||||
Admin Panel
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{ $slot }}
|
||||
</main>
|
||||
|
||||
{{-- Scripts --}}
|
||||
@filamentScripts
|
||||
</body>
|
||||
</html>
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\HomeController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
@@ -13,7 +14,7 @@ use Illuminate\Support\Facades\Route;
|
||||
|
|
||||
*/
|
||||
|
||||
Route::redirect('/', '/admin');
|
||||
Route::get('/', HomeController::class);
|
||||
|
||||
Route::get('/login', function () {
|
||||
return redirect('/admin/login');
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import defaultTheme from 'tailwindcss/defaultTheme';
|
||||
import forms from '@tailwindcss/forms';
|
||||
import presets from './vendor/filament/support/tailwind.config.preset';
|
||||
import typography from '@tailwindcss/typography';
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
presets: [presets],
|
||||
|
||||
content: [
|
||||
'./resources/views/**/*.blade.php',
|
||||
'./storage/framework/views/*.php',
|
||||
],
|
||||
|
||||
darkMode: 'class',
|
||||
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [
|
||||
forms,
|
||||
typography,
|
||||
],
|
||||
}
|
||||
+11
-2
@@ -1,13 +1,22 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
import laravel, { refreshPaths } from 'laravel-vite-plugin';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
laravel({
|
||||
input: [
|
||||
'resources/css/app.css',
|
||||
'resources/css/filament/admin/theme.css',
|
||||
],
|
||||
refresh: true,
|
||||
refresh: [
|
||||
...refreshPaths,
|
||||
'app/Livewire/**',
|
||||
],
|
||||
}),
|
||||
],
|
||||
server: {
|
||||
hmr: {
|
||||
host: 'localhost',
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user