Just commit it all

This commit is contained in:
Frankie B 2024-04-01 14:21:45 +01:00
parent a64bcc2c46
commit 36f9b56049
No known key found for this signature in database
83 changed files with 1949 additions and 1658 deletions
app
auth0composer.jsoncomposer.lock
config
database
public
resources
routes

View file

@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers;
use App\Models\BookmarkCategory;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class AdminBookmarksController extends Controller
{
public function show() : View {
$categories = BookmarkCategory::with('sites')->get();
return view('admin.bookmarks', compact('categories'));
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Http\Controllers;
use App\Models\GuestbookEntry;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
use UAParser\Parser;
class AdminGuestbookController extends Controller
{
function getGuestbookUniqueAddr(): int {
$uniqueIpsCount = DB::table('guestbook__entries')->distinct()->count('ip');
return $uniqueIpsCount;
}
function getGuestbookEntriesCount(): int {
$entryCount = DB::table('guestbook__entries')->count();
return $entryCount;
}
public function show() : View {
$guestbook_unique_addr = $this->getGuestbookUniqueAddr();
$guestbook_entry_count = $this->getGuestbookEntriesCount();
$entries = GuestbookEntry::selectEntries();
$parser = Parser::create();
return view('admin.guestbook', [
'guestbook_unique_addr' => $guestbook_unique_addr,
'guestbook_entry_count' => $guestbook_entry_count,
'entries' => $entries,
'parser' => $parser,
]);
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use App\Models\BookmarkCategory;
use App\Models\BookmarkSite;
use App\Models\GuestbookEntry;
use Exception;
use Illuminate\Http\Request;
use Illuminate\View\View;
class AdminImportController extends Controller
{
public function show() : View {
return view('admin.import');
}
public function submit(Request $request)
{
$request->validate([
'jsonFile' => 'required|mimes:json',
]);
$file = $request->file('jsonFile');
$jsonContent = file_get_contents($file->getRealPath());
$data = json_decode($jsonContent, true);
$tables = [];
foreach($data as $item) {
if ($item['type'] !== "table") continue;
$tables[$item['name']] = [
'data' => $item['data'],
'count' => count($item['data'])
];
if ($item['name'] === "guestbook__entries") {
GuestbookEntry::importGuestbookEntry($item['data']);
}
$this->import($item['data'], $item['name']);
}
return view('admin.import-success', ['tables' => $tables]);
}
/**
* Imports the given data to the specified table
*
* @param array $data The data to import
* @param string $table_name The name of the table to import to
* @return void
* @throws Exception Invalid table specified, to be replaced with custom exception
*/
public function import(array $data, string $table_name): void {
switch ($table_name) {
case 'guestbook__entries':
GuestbookEntry::importGuestbookEntry($data);
break;
case 'bookmark__categories' :
BookmarkCategory::importBookmarkCategory($data);
break;
case 'bookmark__sites':
BookmarkSite::importBookmark($data);
break;
case 'guestbook__bans':
break;
default:
// TODO: Replace with custom exception
throw new Exception("Invalid table specified ($table_name)");
}
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers;
use App\Models\BookmarkSite;
use App\Models\BookmarkCategory;
use Illuminate\View\View;
class BookmarksController extends Controller
{
public function show() : View {
$categories = BookmarkCategory::with('sites')->get();
return view('bookmarks', compact('categories'));
}
}

View file

@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\View\View;
class CalculatorsController extends Controller
{
public function show() : View {
return view('calculators');
}
}

View file

@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\View\View;
class ComputersController extends Controller
{
public function show() : View {
return view('computers');
}
}

View file

@ -2,37 +2,46 @@
namespace App\Http\Controllers;
use App\Models\GuestbookEntry;
use Illuminate\Http\Request;
use DB;
use Illuminate\Http\RedirectResponse;
use Illuminate\Contracts\View\View;
use Illuminate\Validation\ValidationException;
use UAParser\Parser;
class GuestbookController extends Controller {
public function guestbook() {
return view('pages.guestbook');
public function show(): View {
$entries = GuestbookEntry::selectEntries();
$parser = Parser::create();
return view('guestbook')
->with('entries', $entries)
->with('parser', $parser);
}
public function guestbookPost(Request $request) {
/**
* Creates a new guestbook entry
*
* @param Request $request
* @return RedirectResponse
* @throws ValidationException
*/
public function addEntry(Request $request): RedirectResponse {
$this->validate($request, [
'name' => 'required',
'message' => 'required'
]);
$matching_bans = DB::select('SELECT reason FROM guestbook__bans WHERE ip_address = ?', array($request->ip()));
if (!empty($matching_bans)) {
return view('errors.guestbook-ipban')->with('reason', $matching_bans[0]->reason);
}
DB::insert(
'INSERT INTO guestbook__entries (name, timestamp, ip_address, agent, message) values (?, ?, ?, ?, ?)',
[
htmlspecialchars($request->get('name')),
time(),
$request->ip(),
$request->userAgent(),
htmlspecialchars($request->get('message'))
]
);
GuestbookEntry::insertGuestbookEntry($request);
return back()->with('success', 'Entry submitted successfully!');
}
public function banIP(string $addr) {
// TODO: Add banning system
// $matching_bans = DB::select('SELECT reason FROM guestbook__bans WHERE ip_address = ?', array($request->ip()));
// if (!empty($matching_bans)) {
// return view('errors.guestbook-ipban')->with('reason', $matching_bans[0]->reason);
// }
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
use DateTime;
class HomeController extends Controller
{
/**
* Returns age based on birthday date and current date (GMT)
* @return int
*/
function returnAge(): int
{
date_default_timezone_set('Europe/London');
$birthday = new DateTime("2005-06-07");
$currentDate = DateTime::createFromFormat("Y-m-d", date("Y-m-d"));
$age = $birthday->diff($currentDate);
return $age->y;
}
/**
* Shows home page
* @return View
*/
public function show() : View {
return view('home', [
'age' => $this->returnAge()
]);
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace App\Http\Controllers;
use App\Models\Track;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\View\View;
class MusicController extends Controller
{
public function getCurrentTrack() {
if (Cache::has('current_track')) {
return Cache::get('current_track');
}
$response = Http::get('https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user='.env('LASTFM_USER').'&nowplaying=true&format=json&api_key='.env('LASTFM_KEY'));
$data = $response->json();
$track_data = $data["recenttracks"]["track"][0];
$current_track = [
'title' => $track_data["name"],
'artist' => $track_data["artist"]["#text"],
'url' => $track_data["url"],
];
Cache::put('current_track', $current_track, now()->addSeconds(15));
return $current_track;
}
public function getTopTracks() {
if (Cache::has('top_tracks')) {
return Cache::get('top_tracks');
}
$response = Http::get('https://ws.audioscrobbler.com/2.0/?method=user.gettoptracks&user='.env('LASTFM_USER').'&format=json&period=1month&limit=10&api_key='.env('LASTFM_KEY'));
$data = $response->json();
$topTracks = [];
foreach ($data["toptracks"]["track"] as $track) {
$topTracks[] = [
'title' => $track["name"],
'artist' => $track["artist"]["name"],
'url' => $track["url"],
'plays' => $track["playcount"],
];
}
Cache::put('top_tracks', $topTracks, now()->addSeconds(15));
return $topTracks;
}
public function show() : View {
return view('music')
->with('current_track', $this->getCurrentTrack())
->with('top_tracks', $this->getTopTracks());
}
}

View file

@ -16,6 +16,9 @@ class RateLimiter
*/
public function handle(Request $request, Closure $next): Response
{
if (auth()->check()) {
return $next($request);
}
$ipAddress = $request->ip();
$cacheKey = 'rate_limit_'.$ipAddress;

View file

@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BookmarkCategory extends Model
{
use HasFactory;
protected $table = "bookmark__categories";
protected $fillable = ['name'];
public function sites() {
return $this->hasMany(BookmarkSite::class, 'category');
}
public static function insertBookmarkCategory(string $name) {
$newBookmarkCategory = new BookmarkCategory;
$newBookmarkCategory->name = $name;
$newBookmarkCategory->save();
}
public static function selectBookmarks(int $id) {
$bookmarks = BookmarkSite::where('category', '=', $id)->firstOrFail();
return $bookmarks;
}
public static function importBookmarkCategory(array $data) {
foreach ($data as $category) {
$newBookmarkCategory = new BookmarkCategory;
$newBookmarkCategory->name = $category['name'];
$newBookmarkCategory->priority = intval($category['priority']);
$newBookmarkCategory->save();
}
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BookmarkSite extends Model {
use HasFactory;
protected $table = "bookmark__sites";
protected $fillable = ['name', 'description', 'url', 'category'];
public function category() {
return $this->belongsTo(BookmarkCategory::class, 'category');
}
public static function insertBookmark(string $name, string $url, int $category) {
$category = BookmarkCategory::where('id', $category)->firstOrFail();
$newBookmark = new BookmarkSite;
$newBookmark->name = $name;
$newBookmark->url = $url;
$newBookmark->category = $category->id;
$newBookmark->save();
}
public static function importBookmark(array $data) {
foreach ($data as $site) {
$newBookmark = new BookmarkSite;
$newBookmark->name = $site['name'];
$newBookmark->description = $site['description'];
$newBookmark->url = $site['url'];
$newBookmark->category = $site['category_id'];
$newBookmark->save();
}
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace App\Models;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class GuestbookEntry extends Model
{
use HasFactory;
protected $table = "guestbook__entries";
protected $fillable = ['name', 'message'];
/**
* Creates a new guestbook entry.
*
* @param Request $request The HTTP POST request
* @return void
*/
public static function insertGuestbookEntry(Request $request) {
$newEntry = new GuestbookEntry;
$newEntry->name = htmlspecialchars($request->get('name'));
$newEntry->message = htmlspecialchars($request->get('message'));
$newEntry->ip = $request->ip();
$newEntry->agent = $request->userAgent();
$newEntry->admin = auth()->check();
$newEntry->save();
}
public static function selectEntries() {
$entries = GuestbookEntry::orderBy('created_at', 'desc')->get();
return $entries;
}
public static function importGuestbookEntry(array $data) {
foreach ($data as $entry) {
$dt = new \DateTime('@' . $entry['timestamp']);
$newEntry = new GuestbookEntry;
$newEntry->name = $entry['name'];
$newEntry->ip = $entry['ip_address'];
$newEntry->agent = $entry['agent'];
$newEntry->admin = $entry['site_owner'];
$newEntry->message = $entry['message'];
$newEntry->created_at = $dt;
$newEntry->updated_at = $dt;
$newEntry->save();
}
}
}

View file

@ -1,45 +0,0 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class CurrentTrack extends Component
{
public $track;
/**
* Create a new component instance.
*/
public function __construct($track)
{
$this->track = $track;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.current-track');
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Layout extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.layout');
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Navbar extends Component
{
public $title;
/**
* Create a new component instance.
*/
public function __construct($title)
{
$this->title = $title;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.navbar');
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class TopTracks extends Component
{
public $tracks;
/**
* Create a new component instance.
*/
public function __construct($tracks)
{
$this->tracks = $tracks;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.top-tracks');
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Track extends Component
{
public $track;
public $count;
/**
* Create a new component instance.
*/
public function __construct($track, $count)
{
$this->track = $track;
$this->count = $count;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.track');
}
}

BIN
auth0 Executable file

Binary file not shown.

View file

@ -13,6 +13,7 @@
"scrivo/highlight.php": "v9.18.1.10",
"sentry/sentry-laravel": "^4.1",
"spatie/laravel-honeypot": "^4.3",
"spatie/laravel-html": "^3.4",
"ua-parser/uap-php": "^3.9.14"
},
"require-dev": {

757
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,8 @@
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY),
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM),
Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST),
Configuration::CONFIG_BACKCHANNEL_LOGOUT_CACHE => Configuration::get(Configuration::CONFIG_BACKCHANNEL_LOGOUT_CACHE),
Configuration::CONFIG_BACKCHANNEL_LOGOUT_EXPIRES => Configuration::get(Configuration::CONFIG_BACKCHANNEL_LOGOUT_EXPIRES),
],
'api' => [
@ -53,4 +55,13 @@
Configuration::CONFIG_TRANSIENT_STORAGE_ID => Configuration::get(Configuration::CONFIG_TRANSIENT_STORAGE_ID),
],
],
'routes' => [
Configuration::CONFIG_ROUTE_INDEX => Configuration::get(Configuration::CONFIG_ROUTE_INDEX, '/'),
Configuration::CONFIG_ROUTE_CALLBACK => Configuration::get(Configuration::CONFIG_ROUTE_CALLBACK, '/callback'),
Configuration::CONFIG_ROUTE_LOGIN => Configuration::get(Configuration::CONFIG_ROUTE_LOGIN, '/login'),
Configuration::CONFIG_ROUTE_AFTER_LOGIN => Configuration::get(Configuration::CONFIG_ROUTE_AFTER_LOGIN, '/'),
Configuration::CONFIG_ROUTE_LOGOUT => Configuration::get(Configuration::CONFIG_ROUTE_LOGOUT, '/logout'),
Configuration::CONFIG_ROUTE_AFTER_LOGOUT => Configuration::get(Configuration::CONFIG_ROUTE_AFTER_LOGOUT, '/'),
],
];

View file

@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BookmarkCategory>
*/
class BookmarkCategoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->word,
];
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\BookmarkCategory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BookmarkSite>
*/
class BookmarkSiteFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->name,
'description' => $this->faker->sentence,
'url' => $this->faker->url,
'category' => BookmarkCategory::factory(),
];
}
}

View file

@ -1,29 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('guestbook__bans', function (Blueprint $table) {
$table->increments('id');
$table->string('ip_address', 40);
$table->string('reason', 50);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('guestbook__bans');
}
};

View file

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// Check if table exists and is empty
if (Schema::hasTable('bookmark__categories') && DB::table('bookmark__categories')->count() == 0) {
// Insert placeholder categories
DB::table('bookmark__categories')->insert([
['name' => 'Friends\' Websites', 'priority' => 1],
['name' => 'Cool Projects', 'priority' => 2],
['name' => 'Other Cool Sites', 'priority' => 3],
['name' => 'Miscellaneous Resources', 'priority' => 4]
]);
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View file

@ -12,9 +12,9 @@
public function up(): void
{
Schema::create('bookmark__categories', function (Blueprint $table) {
$table->increments('id');
$table->id();
$table->string('name');
$table->float('priority');
$table->unsignedBigInteger('priority')->nullable();
$table->timestamps();
});
}

View file

@ -12,13 +12,15 @@
public function up(): void
{
Schema::create('bookmark__sites', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50);
$table->string('description', 150);
$table->string('url', 100);
$table->float('priority');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('bookmark__categories');
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->string('url');
$table->unsignedBigInteger('category');
$table->foreign('category')
->references('id')
->on('bookmark__categories')
->onDelete('cascade');
$table->timestamps();
});
}
@ -28,6 +30,6 @@ public function up(): void
*/
public function down(): void
{
Schema::dropIfExists('bookmark__sites');
Schema::dropIfExists('bookmarks');
}
};

View file

@ -12,13 +12,12 @@
public function up(): void
{
Schema::create('guestbook__entries', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 255);
$table->bigInteger('timestamp');
$table->string('ip_address', 40);
$table->string('agent', 2048)->default('Agent unavailable');
$table->boolean('site_owner')->default(0);
$table->string('message', 512);
$table->id();
$table->string('name');
$table->string('ip');
$table->string('agent');
$table->longText('message');
$table->boolean('admin');
$table->timestamps();
});
}

View file

@ -0,0 +1,30 @@
<?php
namespace Database\Seeders;
use App\Models\BookmarkCategory;
use App\Models\BookmarkSite;
use Illuminate\Database\Seeder;
class BookmarkCategoriesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void {
// BookmarkCategory::factory()->count(5)->create()->each(function ($category) {
// $category->sites()->saveMany(BookmarkSite::factory()->count(3)->make());
// });
$category = new BookmarkCategory([
'name' => 'cool people',
]);
$category->save();
$site = new BookmarkSite([
'name' => 'campos',
'description' => 'Cool brazilian dude, does programming and stuff',
'url' => 'https://campos02.me/',
'category' => 1,
]);
$site->save();
}
}

View file

@ -1,22 +0,0 @@
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// \App\Models\User::factory(10)->create();
// \App\Models\User::factory()->create([
// 'name' => 'Test User',
// 'email' => 'test@example.com',
// ]);
}
}

View file

@ -111,6 +111,10 @@ .nav-wrapper {
grid-row-gap: 0;
}
.nav-wrapper div:nth-child(2) {
text-align: right;
}
.theme-selector label {
font-weight: bold;
}
@ -226,7 +230,7 @@ table.computers td ul {
padding-left: 20px;
}
table.computers section-title {
table.computers .section-title {
text-decoration: underline;
font-style: italic;
font-weight: bold;
@ -272,34 +276,46 @@ a {
text-decoration: underline dotted;
}
table.gb-entry-form tr td {
table.form tr td {
border: none;
}
table.gb-entry-form tr td label {
table.form tr td label {
padding-right: 5px;
}
table.gb-entry-form tr td span.text-danger {
table.form tr td span.text-danger {
padding-left: 5px;
color: var(--warning);
}
table.gb-entry-form tr td textarea,
table.gb-entry-form tr td input,
table.gb-entry-form tr td button{
margin-bottom: 5px;
margin-left: 10px;
input.file {
border: 0 !important;
}
table.form tr td textarea,
table.form tr td input,
table.form tr td button,
form.import input::file-selector-button,
form.import button {
background-color: var(--background);
border: var(--foreground) solid 1px;
}
table.gb-entry-form tr td button {
table.form label {
margin: 5px 0;
}
form.import button,
form.import input::file-selector-button,
table.form tr td button {
color: var(--foreground);
background-color: var(--background-secondary);
}
table.gb-entry-form tr td button:hover {
form.import button:hover,
form.import input::file-selector-button:hover,
table.form tr td button:hover {
color: var(--background);
background-color: var(--foreground);
}
@ -318,7 +334,7 @@ table.gb-entry-form-container tr td ul {
margin: 0;
}
table.gb-entry-form tbody tr td textarea {
table.form tbody tr td textarea {
width: 210px;
}
@ -490,20 +506,151 @@ #scheme-selector {
}
.music-top10 td {
.music-top10 td,
.music-top10 th {
border: none;
border-left: 1px dotted var(--foreground);
padding: 2px 5px
}
.music-top10 tr:nth-child(2) td {
.music-top10 tr:nth-child(1) th {
border-bottom: 1px dotted var(--foreground);
}
.music-top10 tr:nth-child(3) td {
.music-top10 tr:nth-child(2) td {
padding-top: 5px;
}
.music-top10 td:first-child {
.music-top10 td:first-child,
.music-top10 th:first-child {
border: none;
}
.music-top10 tr th:first-child {
text-align: right;
}
.music-top10 td {
white-space: nowrap; text-overflow:ellipsis; overflow: hidden;
}
.music-top10 tr td:first-child {
text-align: right;
}
.music-top10 tr td:nth-child(2),
.music-top10 tr td:nth-child(3) {
width: 50%;
}
.current-track {
width: 100%;
}
.current-track h2 {
margin: 0;
}
.info-section ul {
list-style-position: inside;
list-style-type: none;
padding-left: 0;
margin: 0;
}
.info-section ul li:before {
content: "◆ ";
}
.info-section h2 {
margin: 0;
}
.info-section p {
margin-top: 10px;
}
.contact-section {
display: grid;
grid-template-rows: 1fr 1fr;
}
.banner {
padding: 5px;
margin-top: 10px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: 1fr;
grid-column-gap: 0;
grid-row-gap: 0;
}
.banner div:nth-child(1) {
text-align: left;
}
.banner div:nth-child(2) {
text-align: right;
}
.red-banner {
border: 3px solid var(--foreground);
background-color: var(--background-secondary);
}
.info-admin td,
.info-admin th {
border: 1px solid var(--foreground);
padding: 5px;
}
.info-admin th {
background-color: var(--background-secondary);
}
.info-admin th.blank {
border: none;
background-color: var(--background);
}
.info-admin button {
border: 1px solid var(--foreground);
background-color: var(--background);
color: var(--foreground);
}
.info-admin button:hover {
background-color: var(--foreground);
color: var(--background);
}
.info-admin button:active {
background-color: var(--background-secondary);
color: var(--foreground);
}
.info-admin-section h2 {
margin-bottom: 5px;
}
.fullwidth {
width: 100%;
}
.fullwidth td:last-child {
width: 0;
}
.guestbook-message {
text-wrap: wrap;
width: 100%;
}
td.diagonal-line {
background: linear-gradient(to right bottom, var(--background) 0%,var(--background) 49.9%,var(--foreground) 50%,var(--foreground) 51%,var(--background) 51.1%,var(--background) 100%);
}
form.import h2 {
margin: 10px 0 5px 0;
}

Binary file not shown.

After

(image error) Size: 780 B

Binary file not shown.

After

(image error) Size: 705 B

Binary file not shown.

After

(image error) Size: 1.1 KiB

View file

@ -1,31 +1,31 @@
// Define an array of strings
const neverSaid = [
"<td style=\"width: 105px\"><strong>ASM:</strong></td> <td>The Director liked all the props we got today.</td>",
"<td style=\"width: 105px\"><strong>PM:</strong></td> <td>Ah ha, a revolve. Terrific.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I don't know, let's look at the ground plan.</td>",
"<td style=\"width: 105px\"><strong>Set Designer:</strong></td> <td>Well, let's just have whatever is cheaper.</td>",
"<td style=\"width: 105px\"><strong>Sound:</strong></td> <td>Better turn that down a bit. We don't want to deafen them.</td>",
"<td style=\"width: 105px\"><strong>Director:</strong></td> <td>Sorry, my mistake.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>This equipment is more complicated than we need.</td>",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>I really think my big scene should be cut.</td>",
"<td style=\"width: 105px\"><strong>SM:</strong></td> <td>Can we doo that scene change again please?",
"<td style=\"width: 105px\"><strong>LX designer:</strong></td> <td>Bit more light from those big chaps at the side. Yes that's right, the ones on stalks whatever they are called.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>All the equipment works perfectly.</td>",
"<td style=\"width: 105px\"><strong>Musicians:</strong></td> <td>So what if that's the end of a call. Let's just finish this bit off.</td>",
"<td style=\"width: 105px\"><strong>Wardrobe:</strong></td> <td>Now, when exactly is the first dress rehearsal?",
"<td style=\"width: 105px\"><strong>Workshop:</strong></td> <td>I don't want anyone to know, but if you insist then yes, I admit it, I have just done an all-nighter.</td>",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>This costume is so comfortable.</td>",
"<td style=\"width: 105px\"><strong>Admin:</strong></td> <td>The level of overtime payments here are simply unacceptable. Our backstage staff deserve better.</td>",
"<td style=\"width: 105px\"><strong>Box Office:</strong></td> <td>Comps? No problem.</td>",
"<td style=\"width: 105px\"><strong>Set Designer:</strong></td> <td>You're right, it looks dreadful.</td>",
"<td style=\"width: 105px\"><strong>Flyman:</strong></td> <td>No, my lips are sealed. What I may or may not have seen remains a secret.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>That had nothing to do with the computer, it was my fault.</td>",
"<td style=\"width: 105px\"><strong>Crew:</strong></td> <td>No, no, I'm sure that's our job.</td>",
"<td style=\"width: 105px\"><strong>SMgt:</strong></td> <td>Thanks, but I don't drink",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>Let me stand down here with my back to the audience.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I can't really manage those big fast power tools myself.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I prefer to use these little hand drills.</td>",
"<td style=\"width: 105px\"><strong>All:</strong></td> <td>Let's go and ask the Production Manager. He'll know.</td>"
"<strong>ASM:</strong> The Director liked all the props we got today.",
"<strong>PM:</strong> Ah ha, a revolve. Terrific.",
"<strong>Chippie:</strong> I don't know, let's look at the ground plan.",
"<strong>Set Designer:</strong> Well, let's just have whatever is cheaper.",
"<strong>Sound:</strong> Better turn that down a bit. We don't want to deafen them.",
"<strong>Director:</strong> Sorry, my mistake.",
"<strong>Electrics:</strong> This equipment is more complicated than we need.",
"<strong>Performer:</strong> I really think my big scene should be cut.",
"<strong>SM:</strong> Can we do that scene change again please?",
"<strong>LX designer:</strong> Bit more light from those big chaps at the side. Yes that's right, the ones on stalks whatever they are called.",
"<strong>Electrics:</strong> All the equipment works perfectly.",
"<strong>Musicians:</strong> So what if that's the end of a call. Let's just finish this bit off.",
"<strong>Wardrobe:</strong> Now, when exactly is the first dress rehearsal?",
"<strong>Workshop:</strong> I don't want anyone to know, but if you insist then yes, I admit it, I have just done an all-nighter.",
"<strong>Performer:</strong> This costume is so comfortable.",
"<strong>Admin:</strong> The level of overtime payments here are simply unacceptable. Our backstage staff deserve better.",
"<strong>Box Office:</strong> Comps? No problem.",
"<strong>Set Designer:</strong> You're right, it looks dreadful.",
"<strong>Flyman:</strong> No, my lips are sealed. What I may or may not have seen remains a secret.",
"<strong>Electrics:</strong> That had nothing to do with the computer, it was my fault.",
"<strong>Crew:</strong> No, no, I'm sure that's our job.",
"<strong>SMgt:</strong> Thanks, but I don't drink",
"<strong>Performer:</strong> Let me stand down here with my back to the audience.",
"<strong>Chippie:</strong> I can't really manage those big fast power tools myself.",
"<strong>Chippie:</strong> I prefer to use these little hand drills.",
"<strong>All:</strong> Let's go and ask the Production Manager. He'll know."
]
// Generate a random index into the array

35
resources/js/neverSaid.js Normal file
View file

@ -0,0 +1,35 @@
// Define an array of strings
const neverSaid = [
"<td style=\"width: 105px\"><strong>ASM:</strong></td> <td>The Director liked all the props we got today.</td>",
"<td style=\"width: 105px\"><strong>PM:</strong></td> <td>Ah ha, a revolve. Terrific.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I don't know, let's look at the ground plan.</td>",
"<td style=\"width: 105px\"><strong>Set Designer:</strong></td> <td>Well, let's just have whatever is cheaper.</td>",
"<td style=\"width: 105px\"><strong>Sound:</strong></td> <td>Better turn that down a bit. We don't want to deafen them.</td>",
"<td style=\"width: 105px\"><strong>Director:</strong></td> <td>Sorry, my mistake.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>This equipment is more complicated than we need.</td>",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>I really think my big scene should be cut.</td>",
"<td style=\"width: 105px\"><strong>SM:</strong></td> <td>Can we doo that scene change again please?",
"<td style=\"width: 105px\"><strong>LX designer:</strong></td> <td>Bit more light from those big chaps at the side. Yes that's right, the ones on stalks whatever they are called.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>All the equipment works perfectly.</td>",
"<td style=\"width: 105px\"><strong>Musicians:</strong></td> <td>So what if that's the end of a call. Let's just finish this bit off.</td>",
"<td style=\"width: 105px\"><strong>Wardrobe:</strong></td> <td>Now, when exactly is the first dress rehearsal?",
"<td style=\"width: 105px\"><strong>Workshop:</strong></td> <td>I don't want anyone to know, but if you insist then yes, I admit it, I have just done an all-nighter.</td>",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>This costume is so comfortable.</td>",
"<td style=\"width: 105px\"><strong>Admin:</strong></td> <td>The level of overtime payments here are simply unacceptable. Our backstage staff deserve better.</td>",
"<td style=\"width: 105px\"><strong>Box Office:</strong></td> <td>Comps? No problem.</td>",
"<td style=\"width: 105px\"><strong>Set Designer:</strong></td> <td>You're right, it looks dreadful.</td>",
"<td style=\"width: 105px\"><strong>Flyman:</strong></td> <td>No, my lips are sealed. What I may or may not have seen remains a secret.</td>",
"<td style=\"width: 105px\"><strong>Electrics:</strong></td> <td>That had nothing to do with the computer, it was my fault.</td>",
"<td style=\"width: 105px\"><strong>Crew:</strong></td> <td>No, no, I'm sure that's our job.</td>",
"<td style=\"width: 105px\"><strong>SMgt:</strong></td> <td>Thanks, but I don't drink",
"<td style=\"width: 105px\"><strong>Performer:</strong></td> <td>Let me stand down here with my back to the audience.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I can't really manage those big fast power tools myself.</td>",
"<td style=\"width: 105px\"><strong>Chippie:</strong></td> <td>I prefer to use these little hand drills.</td>",
"<td style=\"width: 105px\"><strong>All:</strong></td> <td>Let's go and ask the Production Manager. He'll know.</td>"
]
// Generate a random index into the array
const randomIndex = Math.floor(Math.random() * neverSaid.length);
// Use document.write to output the random string
document.write(neverSaid[randomIndex]);

View file

@ -0,0 +1,70 @@
/**
* Retrieves a cookies value
* @param {string} cname Cookie name
* @returns {string} Cookie value
*/
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
/**
* Sets/creates a cookie
* @param {string} cname Cookie name
* @param {string} cvalue Cookie value
* @param {number} exdays Cookie lifespan (days)
*/
function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
let expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;SameSite=Strict;Domain=.diskfloppy.me";
}
/**
* Checks if a cookie exists
* @param {string} cname Cookie name
* @returns {boolean} If cookie exists or not
*/
function cookieExists(cname) {
const cvalue = getCookie(cname);
return cvalue !== "";
}
/**
* Swaps the colorscheme
* @param {string} scheme Color scheme ID
*/
function swapScheme(scheme) {
setCookie("colorscheme", scheme, 90);
document.getElementById("css-colorscheme").href = `/css/colorschemes/${scheme}.css`;
console.log(`Set colorscheme to ${getCookie("colorscheme")}`)
}
function setSchemeSelector() {
if (!cookieExists("colorscheme")) {
setCookie("colorscheme", "catppuccin-macchiato", 90);
} else {
const scheme = getCookie("colorscheme");
const scheme_selector = document.getElementById("scheme-selector");
if (scheme && scheme_selector) {
for (let option of scheme_selector.options) {
if (option.value === scheme) {
option.selected = true;
break;
}
}
}
}
}

View file

@ -0,0 +1,28 @@
<x-layout>
<x-slot:title>Admin | Bookmarks</x-slot:title>
@foreach($categories as $category)
<div class="info-section info-admin-section">
<h2>{{ $category->name }}</h2>
<table class="info-admin">
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>URL</th>
<th>Priority</th>
<th class="blank"></th>
</tr>
@foreach($category->sites as $site)
<tr>
<td>{{ $site->id }}</td>
<td>{{ $site->name }}</td>
<td>{{ $site->description }}</td>
<td>{{ $site->url }}</td>
<td>{{ $site->priority }}</td>
<td><a href="?action=delete&id={{ $site->id }}"><button>Delete</button></a></td>
</tr>
@endforeach
</table>
</div>
@endforeach
</x-layout>

View file

@ -0,0 +1,32 @@
<x-layout>
<x-slot:title>Admin | Guestbook</x-slot:title>
<div class="info-section">
<h2>Statistics</h2>
<hr>
<strong>Unique IP addresses:</strong> {{ $guestbook_unique_addr }}<br>
<strong>Entries:</strong> {{ $guestbook_entry_count }}
</div>
<br>
<div class="info-section">
<h2>Entries</h2>
<hr>
<table class="info-admin fullwidth">
<tr>
<th>ID</th>
<th>Name</th>
<th>IP Address</th>
<th>Message</th>
<th class="blank"></th>
</tr>
@foreach ($entries as $entry)
<tr>
<td>{{ $entry->id }}</td>
<td>{{ $entry->name }}</td>
<td>{{ $entry->ip }}</td>
<td>{{ $entry->message }}</td>
<td><a href="?action=delete&id={{ $entry->id }}"><button>Delete</button></a></td>
</tr>
@endforeach
</table>
</div>
</x-layout>

View file

@ -0,0 +1,12 @@
<x-layout>
<x-slot:title>Admin | Import</x-slot:title>
<div class="info-section">
<h2>Imported data</h2>
<hr>
<ul>
@foreach($tables as $name => $data)
<li><strong>{{ ucwords(str_replace('__', ' ', $name)) }}:</strong> {{ $data['count'] }} record(s)</li>
@endforeach
</ul>
</div>
</x-layout>

View file

@ -0,0 +1,18 @@
<x-layout>
<x-slot:title>Admin | Import</x-slot:title>
<form class="import" action="{{ route('admin.import.submit') }}" method="post" enctype="multipart/form-data">
@csrf
<label for="data_file"><strong>File:</strong></label>
<input class="file" type="file" name="data_file" accept=".json"><br>
<h2>What to import:</h2>
<input type="checkbox" name="guestbook__entries" checked>
<label for="guestbook__entries">Guestbook Entries</label><br>
<input type="checkbox" name="guestbook__bans" checked>
<label for="guestbook__bans">Guestbook Bans</label><br>
<input type="checkbox" name="guestbook__entries" checked>
<label for="bookmark__categories">Bookmark Categories</label><br>
<input type="checkbox" name="guestbook__entries" checked>
<label for="bookmark_sites">Bookmark Sites</label><br>
<button type="submit">Import</button>
</form>
</x-layout>

View file

@ -0,0 +1,18 @@
<x-layout>
<x-slot:title>Bookmarks</x-slot:title>
@foreach($categories as $category)
<table class="info-table" role="presentation">
<caption>
<h2>{{ $category->name }}</h2>
<hr>
</caption>
<tbody>
@foreach($category->sites as $site)
<tr>
<td><a href="{{ $site->url }}">{{ $site->name }}</a> - {{ $site->description }}</td>
</tr>
@endforeach
</tbody>
</table>
@endforeach
</x-layout>

View file

@ -0,0 +1,4 @@
<div class="info-table current-track">
<h2>Last/Current Track:</h2>
<a href="{{ $track["url"] }}">{{ $track["title"] }} {{ $track["artist"] }}</a><br>
</div>

View file

@ -0,0 +1,116 @@
@php // Get colorscheme from cookie and apply immediately
$colorscheme = request()->cookie('colorscheme', 'catppuccin-macchiato');
@endphp
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Global -->
<meta charset="utf-8">
<meta property="og:type" content="website">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#333333">
<link rel="stylesheet" href="{{ asset("/css/colorschemes/$colorscheme.css") }}" id="css-colorscheme"/>
<link rel="stylesheet" href="{{ asset('/css/master.css') }}"/>
<link rel="icon" type="image/png" href="{{ asset('/favicon-32x32.png') }}" sizes="32x32"/>
<link rel="icon" type="image/png" href="{{ asset('/favicon-16x16.png') }}" sizes="16x16"/>
<script src="{{ asset('/js/schemeSwap.js') }}"></script>
{!! (intval(date('n')) == 12) ? '<script src="/js/christmas/snow.js"></script>' : '' !!}
<!-- Page-specific -->
<title>{{ $title ?? 'Unknown' }} - diskfloppy.me</title>
<meta property="og:title" content="diskfloppy.me | @yield('title')">
<meta property="og:description" content="@yield('description')">
<meta property="og:image" content="/favicon-128x128.png">
<meta name="description" content="@yield('description')">
</head>
<body onload="setSchemeSelector()">
<div class="page">
<div id="header" class="header">
{{-- @if (auth()->check())--}}
@if (true)
<div class="banner red-banner">
<div>
<a href="/admin/guestbook">Guestbook</a>&nbsp;|
<a href="/admin/bookmarks">Bookmarks</a> |
<a href="/admin/import">Import</a>
</div>
<div><strong>Logged in as:</strong> {{-- auth()->user()->name --}}N/A (<a href="/logout">logout</a>)</div>
</div>
@endif
<x-navbar title="{{ $title }}"/>
<hr>
</div> <!-- header -->
<div id="content" class="content" role="main">
{{ $slot }}
</div> <!-- content -->
<div id="footer" class="footer">
<hr>
<div class="footer" role="contentinfo">
<a href="https://dimden.dev/" class="button">
<img src="https://dimden.dev/services/images/88x31.gif" width="88" height="31"
class="pixel" alt="dimden.dev">
</a>&nbsp;
<a href="https://www.linux.org/" class="button">
<img src="{{ URL::asset('images/buttons/linuxnow.gif') }}" width="88"
class="pixel" height="31" alt="Linux NOW!">
</a>&nbsp;
<a href="https://www.vim.org/" class="button">
<img src="{{ URL::asset('images/buttons/vim.gif') }}" width="88" height="31"
class="pixel" alt="vim">
</a>&nbsp;
<a href="https://wave.webaim.org/" class="button">
<img src="{{ URL::asset('images/buttons/evaluatedWAVE.png') }}" width="88" height="31"
class="pixel" alt="Evaluated to be accessible!">
</a>&nbsp;
<a href="https://jigsaw.w3.org/css-validator/check/referer" class="button">
<img src="{{ URL::asset('images/buttons/vcss-blue.gif') }}" width="88" height="31"
class="pixel" alt="Valid CSS!">
</a>&nbsp;
<a href="https://wiby.me/" class="button">
<img src="{{ URL::asset('images/buttons/wiby.gif') }}" width="88" height="31"
class="pixel" alt="Wiby - Search Engine for the Classic Web">
</a><br>
This site is best viewed at 1024x768 with 16-bit color or better<br>
&copy; floppydisk 2021-{{ date('Y') }}, v{{ config('app.version') }}@if(env('DEVEL'))-dev, @else, @endif<a
href="https://github.com/floppydisk05/diskfloppy.me">Source</a>,
Served by {{ gethostname() }}<br>
<label for="scheme-selector">Color Scheme:</label>
<select onchange="swapScheme(this.value)" id="scheme-selector">
<optgroup label="Misc">
<option value="c64">C64</option>
</optgroup>
<optgroup label="Light">
<option value="catppuccin-latte">Catppuccin Latte</option>
<option value="gruvbox">Gruvbox</option>
<option value="man-page">Man Page</option>
<option value="papercolor-light">Papercolor Light</option>
<option value="rose-pine-dawn">Rosé Pine Dawn</option>
<option value="solarized-light">Solarized Light</option>
<option value="terminal-basic">Terminal Basic</option>
</optgroup>
<optgroup label="Dark">
<option value="catppuccin-frappe">Catppuccin Frappé</option>
<option value="catppuccin-macchiato" selected="selected">Catppuccin Macchiato</option>
<option value="catppuccin-mocha">Catppuccin Mocha</option>
<option value="gruvbox-dark">Gruvbox Dark</option>
<option value="gruvbox-material">Gruvbox Material</option>
<option value="maia">Maia</option>
<option value="mono-amber">Mono Amber</option>
<option value="mono-cyan">Mono Cyan</option>
<option value="mono-green">Mono Green</option>
<option value="mono-red">Mono Red</option>
<option value="mono-white">Mono White</option>
<option value="mono-yellow">Mono Yellow</option>
<option value="papercolor-dark">Papercolor Dark</option>
<option value="rose-pine">Rosé Pine</option>
<option value="rose-pine-moon">Rose Pine Moon</option>
<option value="shel">Shel</option>
<option value="slate">Slate</option>
<option value="solarized-dark">Solarized Dark</option>
</optgroup>
</select><br>
</div>
</div> <!-- footer -->
</div> <!-- page -->
</body>
</html>

View file

@ -0,0 +1,28 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<title>{{ $title ?? '' }}</title>
<link rel="stylesheet" href="{{ URL::asset ('css/minimal.css') }}"/>
</head>
<body>
<h1>Error {{ $code }} | <strong>{{ $message }}</strong></h1>
<hr align="left">
<p>Here, have a cat...</p>
<img src="https://http.cat/{{ $code }}" width="500"><br><br>
<p>If you believe this is a server error, contact the <a href="mailto:webmaster@diskfloppy.me">webmaster</a></p>
<br>
<h4>Diagnostic Info</h4>
<table><tr><td>
<code>
Server: &nbsp;{{ gethostname() }}<br>
Your IP: {{ Request::ip() }}<br>
Root: &nbsp;&nbsp;&nbsp;{!! url('') !!}<br>
Path: &nbsp;&nbsp;&nbsp;@if(Request::path() == "/")/@else/{{ Request::path() }}/@endif<br>
Epoch: &nbsp;&nbsp;{{ now()->timestamp }}<br>
Agent: &nbsp;&nbsp;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0 </code>
</td></tr></table>
<hr align="left">
<p>&copy; floppydisk 2021-2024</p>
</body>
</html>

View file

@ -0,0 +1,18 @@
<nav>
<h1>diskfloppy.me | <strong>{{ $title }}</strong></h1>
<div class="nav-wrapper">
<div>
<a href="/" title="Home"><img class="pixel" src="/images/icons/nav/home2.png" alt="Home" width="32" height="32"></a>
<a href="//git.diskfloppy.me/" title="cgit"><img class="pixel" src="/images/icons/nav/repo.png" alt="cgit" width="32" height="32"></a>
<a href="/pub/" title="Public Files"><img class="pixel" src="/images/icons/nav/pubfiles.png" alt="Public Files" width="32" height="32"></a>
<a href="/computers/" title="Computers"><img class="pixel" src="/images/icons/nav/computers.png" alt="Computers" width="32" height="32"></a>
<a href="/bookmarks/" title="Bookmarks"><img class="pixel" src="/images/icons/nav/bookmarks.png" alt="Bookmarks" width="32" height="32"></a>
<a href="/guestbook/" title="Guestbook"><img class="pixel" src="/images/icons/nav/guestbook.png" alt="Guestbook" width="32" height="32"></a>
<a href="//weather.diskfloppy.me/" title="Weather"><img class="pixel" src="/images/icons/nav/weather.png" alt="Weather" width="32" height="32"></a>
<a href="/music/" title="Music"><img class="pixel" src="/images/icons/nav/music.png" alt="Music" width="32" height="32"></a>&nbsp;&nbsp;
</div>
<div>
<a href="/login/" title="Admin Login"><img class="pixel" src="/images/icons/nav/admin.png" alt="Admin Login" width="32" height="32"></a>&nbsp;&nbsp;
</div>
</div>
</nav>

View file

@ -0,0 +1,16 @@
<table class="music-top10">
<caption>
<h2 style="margin-bottom: 5px">Top 10 Tracks (Last 30 days):</h2>
</caption>
<tr>
<th><b>#</b></th>
<th><b>Track</b></th>
<th><b>Artist</b></th>
<th><b>Plays</b></th>
</tr>
@php($count = 0)
@foreach ($tracks as $track)
@php($count++)
<x-track :track="$track" :count="$count"/>
@endforeach
</table>

View file

@ -0,0 +1,6 @@
<tr>
<td>{{ $count }}</td>
<td><a href="{{ $track["url"] }}">{{ $track["title"] }}</a></td>
<td>{{ $track["artist"] }}</td>
<td>{{ $track["plays"] }}</td>
</tr>

View file

@ -0,0 +1,187 @@
@extends('layouts.default')
@section('title', 'Computers')
@section('description', 'Computers I own or have owned.')
@php
// TODO: AMD whitebox, 745, D531, 1525, server, vaio, qosmio, packard bell
@endphp
@section('content')
<table class="computers">
<tr>
<th>PICTURES</th>
<th>SPECS &amp; DESCRIPTION</th>
</tr>
<tr>
<td>Random Whitebox</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>486DX2 (50MHz)</li>
<li>16MB RAM</li>
<li>280MB HDD</li>
<li>Windows NT 3.51</li>
</ul>
<p class="description">
Had been monitoring the ventilation system in a school since the late 1990s,
only stopped because the power supply internally exploded. Replaced the PSU with
a standard ATX PSU and an ATX to AT adaptor and it sprung back to life.
Motherboard is a Gigabyte GA486IM with 4 PCI slots, 4 ISA slots and 2 VLB slots.
Has two identical ISA serial/parallel/game-port cards with one acting as the
HDD/FDD controller. Also has a Realtek NIC with both RJ45 and BNC. GPU is a
Cirrus Logic card and is astoundingly shit.
</p>
</td>
</tr>
<tr>
<td>2023 MacBook Pro 14"</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Apple M3 Pro</li>
<li>18GB RAM</li>
<li>500GB SSD</li>
<li>macOS Sonoma</li>
</ul>
</td>
</tr>
<tr>
<td>2018 MacBook Pro 13"</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel i5-8259U @ 2.3GHz</li>
<li>Intel Iris Plus Graphics 655</li>
<li>8GB RAM</li>
<li>250GB SSD</li>
<li>macOS Sonoma</li>
</ul>
<p class="description">
Old main computer. Really like the touch bar, absolutely hate the butterfly
keyboard.
</p>
</td>
</tr>
<tr>
<td>2012 Lenovo ThinkPad T430</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Core i7</li>
<li>16GB RAM</li>
<li>Windows 7 Professional / NixOS</li>
</ul>
<p class="description">
One of my main computers. Has been modified to use a classic keyboard instead of
the stock Lenovo keyboard.
</p>
</td>
</tr>
<tr>
<td>2005 IBM ThinkPad X41T</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Pentium M @ 1.6GHz</li>
<li>Mobile Intel Express Chipset Family (128MB)</li>
<li>1.5GB RAM</li>
<li>40GB HDD</li>
<li>Windows XP Tablet PC Edition</li>
</ul>
</td>
</tr>
<tr>
<td>1999 Dell OptiPlex GX1</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Pentium II (Deschutes) @ 400MHz</li>
<li>ATI 3D Rage Pro (4MB)</li>
<li>639MB</li>
<li>40GB HDD</li>
<li>MS-DOS 6.22 &amp; WFW 3.10</li>
</ul>
<p class="description">
Cool computer that uses Slot 1 CPUs. After a lot of trial and error I managed to
max out the memory. Has a riser that sports 2 PCI and 2 ISA slots (one PCI and
ISA share the same slot).
</p>
</td>
</tr>
<tr>
<td>2003 IBM ThinkPad T40</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Pentium M @ 1.3GHz</li>
<li>ATI Mobility Radeon 7500 (32MB)</li>
<li>1GB RAM</li>
<li>30GB HDD</li>
<li>Windows 2000 Professional</li>
</ul>
<p class="description">
Useful laptop thanks to its parallel port. Has the ubiquitous GPU solder issues
which I &quot;&quot;&quot;&quot;fixed&quot;&quot;&quot;&quot; by jamming a CF card
between the GPU chip and the keyboard.
</p>
</td>
</tr>
<tr>
<td>2010 HP Compaq Elite 8100</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Core i7</li>
<li>16GB RAM</li>
<li>some SSD and an HDD</li>
<li>Windows Vista Ultimate (64-bit)</li>
</ul>
</td>
</tr>
<tr>
<td>2014 Mac mini</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Core i5-4278U @ 2.6GHz</li>
<li>Intel Iris Graphics</li>
<li>8GB RAM</li>
<li>1TB HDD</li>
<li>VMware ESXi 6.7.0u3</li>
</ul>
<p class="description">
Was used as my VM host for a few years. Has now been superseded by an
actual 1U rack-mount server.
</p>
</td>
</tr>
<tr>
<td>1996 Fujitsu Milan</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Pentium</li>
<li>32MB RAM</li>
<li>1215MB HDD</li>
<li>Windows 98 SE</li>
</ul>
<p class="description">
Was originally a family members' laptop. Unfortunately the HDD side of the
HDD/FDD cable ripped while I was removing the drive to clean the computer.
Still scouring eBay for a replacement cable (or more likely, an entire
parts machine).
</p>
</td>
</tr>
<tr>
<td>1999 Compaq Armada M300</td>
<td>
<span class="section-title">Quick Specs</span>
<ul>
<li>Intel Pentium III</li>
</ul>
<p class="description">
Nice little laptop. Mysteriously dead.
</p>
</td>
</tr>
</table>
@stop

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Unauthorized'))
@section('code', '401')
@section('message', __('Unauthorized'))
<x-minimal-error>
<x-slot:code>401</x-slot:code>
<x-slot:message>Unauthorized</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Payment Required'))
@section('code', '402')
@section('message', __('Payment Required'))
<x-minimal-error>
<x-slot:code>402</x-slot:code>
<x-slot:message>Payment Required</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Forbidden'))
@section('code', '403')
@section('message', __($exception->getMessage() ?: 'Forbidden'))
<x-minimal-error>
<x-slot:code>403</x-slot:code>
<x-slot:message>{{__($exception->getMessage() ?: 'Forbidden')}}</x-slot:message>
</x-minimal-error>

View file

@ -1,27 +1,4 @@
@extends('errors::minimal')
@section('content')
<h1>Error 404 | <strong>Page not found!</strong></h1>
<hr align="left">
<h2>The page <code class="addr">/{{ Request::path() }}/</code> doesn't exist! Did you mean...</h2>
<ul>
<li><a href="//www.diskfloppy.me/">diskfloppy.me</a></li>
<li><a href="//git.diskfloppy.me/">git.diskfloppy.me</a></li>
<li><a href="//weather.diskfloppy.me">weather.diskfloppy.me</a></li>
<li><a href="//dl.diskfloppy.me/">dl.diskfloppy.me</a></li>
<li><a href="https://status.diskfloppy.me">status.diskfloppy.me</a> (HTTPS Only)</li>
<li><a href="gopher://diskfloppy.me">gopher://diskfloppy.me</a></li>
</ul>
<p>Still haven't found what you were looking for or believe this is a server error? Contact the <a href="mailto:webmaster@diskfloppy.me">webmaster</a>!</p>
<br>
<h4>Diagnostic Info</h4>
<table><tr><td>
<code>
Server: &nbsp;{{ gethostname() }}<br>
Your IP: {{ Request::ip() }}<br>
Epoch: &nbsp;&nbsp;{{ now()->timestamp }}<br>
Agent: &nbsp;&nbsp;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0 </code>
</td></tr></table>
<hr align="left">
<p>&copy; floppydisk 2021-2024</p>
@endsection
<x-minimal-error>
<x-slot:code>404</x-slot:code>
<x-slot:message>Page not found!</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('I\'m a teapot'))
@section('code', '418')
@section('message', __('I\'m a teapot'))
<x-minimal-error>
<x-slot:code>418</x-slot:code>
<x-slot:message>I'm a teapot</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Page Expired'))
@section('code', '419')
@section('message', __('Page Expired'))
<x-minimal-error>
<x-slot:code>419</x-slot:code>
<x-slot:message>Page Expired</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Too Many Requests'))
@section('code', '429')
@section('message', __('Too Many Requests'))
<x-minimal-error>
<x-slot:code>429</x-slot:code>
<x-slot:message>Too Many Requests</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Server Error'))
@section('code', '500')
@section('message', __('Server Error'))
<x-minimal-error>
<x-slot:code>500</x-slot:code>
<x-slot:message>Server Error</x-slot:message>
</x-minimal-error>

View file

@ -1,5 +1,4 @@
@extends('errors::minimal')
@section('title', __('Service Unavailable'))
@section('code', '503')
@section('message', __('Service Unavailable'))
<x-minimal-error>
<x-slot:code>503</x-slot:code>
<x-slot:message>Service Unavailable</x-slot:message>
</x-minimal-error>

View file

@ -1,9 +1,8 @@
@extends('layouts.minimal')
@section('title', 'Error 401: Unauthorized User!')
@section('content')
<x-minimal>
<x-slot:title>Error 401: Unauthorized User!</x-slot:title>
<h1>{{ $error }}</h1>
<hr>
@if(isset($description))
<p>{{ $description }}</p>
@endif
@stop
</x-minimal>

View file

@ -1,6 +1,5 @@
@extends('layouts.minimal')
@section('title', 'Error 403: IP Blocked!')
@section('content')
<x-minimal>
<x-slot:title>Error 403: IP Blocked!</x-slot:title>
<h1>Error 403: IP Blocked!</h1>
<hr>
<p>Your IP has been banned from submitting to the guestbook.</p>
@ -9,4 +8,4 @@
@endif
<br>
Click <a href="/guestbook">here</a> to go back to the guestbook.
@stop
</x-minimal>

View file

@ -1,10 +1,9 @@
@extends('layouts.minimal')
@section('title', 'Error 429: Overclocking Detected!')
@section('content')
<x-minimal>
<x-slot:title>Error 429: Overclocking Detected!</x-slot:title>
<h1>Error 429: Overclocking Detected!</h1>
<hr>
<p>Whoa there! Your submissions are going at warp speed.</p>
<p>Remember you can only submit an entry <u>once every hour</u>!</p>
<br>
Click <a href="/guestbook">here</a> to go back to the guestbook.
@stop
</x-minimal>

View file

@ -1,53 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title')</title>
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 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-weight: 100;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.content {
text-align: center;
}
.title {
font-size: 36px;
padding: 20px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
<div class="content">
<div class="title">
@yield('message')
</div>
</div>
</div>
</body>
</html>

View file

@ -1,21 +1,3 @@
@extends('layouts.minimal')
@section('content')
<h1>Error @yield('code') | <strong>@yield('message')</strong></h1>
<hr align="left">
<p>Here, have a cat...</p>
<img src="https://http.cat/@yield('code')" width="500"><br><br>
<p>If you believe this is a server error, contact the <a href="mailto:webmaster@diskfloppy.me">webmaster</a></p>
<br>
<h4>Diagnostic Info</h4>
<table><tr><td>
<code>
Server: &nbsp;{{ gethostname() }}<br>
Your IP: {{ Request::ip() }}<br>
Root: &nbsp;&nbsp;&nbsp;{!! url('') !!}<br>
Path: &nbsp;&nbsp;&nbsp;/{{ Request::path() }}/<br>
Epoch: &nbsp;&nbsp;{{ now()->timestamp }}<br>
Agent: &nbsp;&nbsp;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0 </code>
</td></tr></table>
<hr align="left">
<p>&copy; floppydisk 2021-2024</p>
@endsection
<x-minimal>
</x-minimal>

View file

@ -1,27 +1,12 @@
@extends('layouts.default')
@section('title', 'Guestbook')
@section('content')
@php
use UAParser\Parser;
$parser = Parser::create();
$db_alive = true;
try {
DB::connection()->getPdo();
} catch (Exception $e) {
$db_alive = false;
}
@endphp
@if (!$db_alive)
@include('components.errors.db-error')
@else
<br>
<x-layout>
<x-slot:title>Guestbook</x-slot:title>
<table class="gb-entry-form-container" role="presentation">
<tr>
<td>
<form method="POST" action="/guestbook">
@csrf
<x-honeypot/>
<table class="gb-entry-form" role="presentation">
<table class="form" role="presentation">
<tr>
<td>
<label for="name"><strong>Name:</strong></label>
@ -66,13 +51,6 @@
<hr>
@php
$entries = DB::select('
SELECT name, timestamp, message, agent
FROM guestbook__entries
ORDER BY id DESC
');
@endphp
<h2>Entries <small>({{ count($entries) }} total)</small></h2>
@foreach ($entries as $entry)
@php
@ -82,10 +60,10 @@
<tr>
<td>
Submitted by <strong>{{ $entry->name }}</strong>
on <strong>{{ gmdate('Y-m-d', $entry->timestamp) }}</strong>
at <strong>{{ gmdate('h:i:s A (e)', $entry->timestamp) }}</strong>
on <strong>{{ $entry->created_at->format('Y-m-d') }}</strong>
at <strong>{{ $entry->created_at->format('h:i:s A (e)') }}</strong>
<hr>
{{ $entry->message }}
<span class="guestbook-message">{{ $entry->message }}</span>
<hr>
@if($entry->agent === "Agent Unavailable")
<address>Agent unavailable</address>
@ -98,5 +76,4 @@
</table>
<br>
@endforeach
@endif
@stop
</x-layout>

View file

@ -0,0 +1,44 @@
<x-layout>
<x-slot:title>Home</x-slot:title>
<p>Hi! This is my personal homepage on the <strong>W</strong>orld <strong>W</strong>ide <strong>W</strong>eb.</p>
<div class="info-section">
<h2>QuickFacts&trade;</h2>
<hr>
<ul>
<li>18 y/o, he/him, British</li>
<li>Theatre Technician, &quot;Web Developer&quot; and NixOS User</li>
<li>Loves ETC desks, prefers Generics to LEDs for some reason</li>
<li>Spends way too much time on his computer</li>
<li>Favorite games: <a href="https://steamcommunity.com/id/floppydisk05/recommended/420530/">OneShot</a>, Minecraft, Stardew Valley, N++ and Starbound</li>
<li><a href="http://wxqa.com/">CWOP</a> member</li>
</ul>
</div>
<div class="info-section">
<h2>Interests</h2>
<hr>
<ul>
<li><strong>Tech Theatre</strong> - Lighting, Stage Management, etc. (<a href="https://www.controlbooth.com/members/floppydisk.28673/">ControlBooth</a>)</li>
<li><strong>Programming</strong> - HTML, CSS, JavaScript, C#, Java, PHP, Ruby, Python (<a href="https://github.com/floppydisk05">GitHub</a>)</li>
<li><strong>Photography</strong> - <a href="https://www.flickr.com/photos/floppydisk/">Flickr</a></li>
<li><strong>Gaming</strong> - <a href="https://steamcommunity.com/id/floppydisk05/">Steam Profile</a></li>
</ul>
</div>
<div class="info-section">
<h2>Things they never said</h2>
<hr>
<p>
<script type="text/javascript" src="{{ asset("/js/neverSaid.js") }}"></script>
<noscript>Oops! You need JavaScript enabled to view this content.</noscript>
</p>
</div>
<div class="info-section">
<h2>Contact &amp; social</h2>
<hr>
<p>
<strong>E-mail:</strong> <a href="mailto:contact@diskfloppy.me">contact@diskfloppy.me</a><br>
<strong>Mastodon:</strong> <a rel="me" href="https://c.im/@floppydisk">@floppydisk@c.im</a><br>
<strong>Matrix:</strong> <a href="https://matrix.to/#/@floppydisk:arcticfoxes.net">@floppydisk:arcticfoxes.net</a>
</p>
</div>
</x-layout>

View file

@ -1,12 +0,0 @@
<nav>
<div>
<a href="/">public home</a> |
<a href="/admin">admin home</a> |
<a href="/admin/guestbook">guestbook</a>
@if (auth()->check())
| ({{ auth()->user()->name }}) <a href="/logout">logout</a>
@else
| <a href="/login">login</a>
@endif
</div>
</nav>

View file

@ -25,7 +25,7 @@ class="pixel" alt="Valid CSS!">
class="pixel" alt="Wiby - Search Engine for the Classic Web">
</a><br>
This site is best viewed at 1024x768 with 16-bit color or better<br>
&copy; floppydisk 2021-{{ date('Y') }}, v{{ config('app.version') }}, <a
&copy; floppydisk 2021-{{ date('Y') }}, v{{ config('app.version') }}@if(env('DEVEL'))-dev, @else, @endif<a
href="https://github.com/floppydisk05/diskfloppy.me">Source</a>,
Served by {{ gethostname() }}<br>
<label for="scheme-selector">Color Scheme:</label>

View file

@ -0,0 +1,6 @@
<x-layout>
<x-slot:title>Music</x-slot:title>
<x-current-track :track="$current_track"/>
<hr>
<x-top-tracks :tracks="$top_tracks"/>
</x-layout>

View file

@ -1,33 +0,0 @@
@extends('layouts.minimal')
@section('title', 'Delete confirm')
@section('content')
<h1>Delete Confirmation</h1>
<hr>
<p>Are you sure you want to delete this entry?</p>
<h3>Entry Details:</h3>
<table class="gb-entry-details">
<tr>
<td><b>ID:</b></td>
<td>{{ $entry->id }}</td>
</tr>
<tr>
<td><b>Name:</b></td>
<td>{{ $entry->name }}</td>
</tr>
<tr>
<td><b>Date:</b></td>
<td>{{ gmdate("H:i:s - Y-m-d", $entry->timestamp) }}</td>
</tr>
<tr>
<td><b>Message:</b></td>
<td>{{ $entry->message }}</td>
</tr>
</table>
<form action="/admin/guestbook/delete" method="POST">
@csrf
<input type="hidden" name="id" value="{{ $entry->id }}">
<button type="submit">Confirm Delete</button>
</form>
@stop

View file

@ -1,32 +0,0 @@
@extends('layouts.default-admin')
@section('title', 'Guestbook')
@section('content')
@php
$entries = DB::select('
SELECT id, name, timestamp, message, ip_address
FROM guestbook__entries
ORDER BY id DESC
');
@endphp
<h1>Entries <small>({{ count($entries) }} total)</small></h1>
@foreach ($entries as $entry)
<table class="gb-admin">
<tr>
<td>
Name:&nbsp;{{ $entry->name }}<br>
IP:&nbsp;&nbsp;&nbsp;{{ $entry->ip_address }}<br>
Date:&nbsp;{{ gmdate("H:i:s - Y-m-d", $entry->timestamp) }}
</td>
<td class="gb-del">
<a href="/admin/guestbook/delete?id={{ $entry->id }}">del</a>
</td>
</tr>
<tr>
<td class="gb-message">
<br>
{{ htmlspecialchars($entry->message) }}
</td>
</tr></table>
@endforeach
@stop

View file

@ -1,9 +0,0 @@
@extends('layouts.default-admin')
@section('title', 'Page Title')
@section('description', 'Page description goes here')
@php
$user = auth()->user();
@endphp
@section('content')
<p>You are logged in as {{ $user->name }} ({{ $user->email }})</p>
@stop

View file

@ -1,52 +0,0 @@
@extends('layouts.default')
@section('title', 'Bookmarks')
@section('description', 'This is the personal homepage of floppydisk.')
@section('content')
@php
$db_alive = true;
try {
DB::connection()->getPdo();
} catch (Exception $e) {
$db_alive = false;
}
@endphp
@if (!$db_alive)
@include('components.errors.db-error')
@else
@php
$categories = DB::select('
SELECT id, name
FROM bookmark__categories
ORDER BY priority ASC
');
@endphp
@foreach ($categories as $category)
<table class="info-table" role="presentation">
<caption>
<h2>{{ $category->name }}</h2>
<hr>
</caption>
@php
$sites = DB::select(
'
SELECT name, url, description
FROM bookmark__sites
WHERE category_id = ? ORDER BY priority ASC
',
[$category->id],
);
@endphp
@foreach ($sites as $site)
<tr>
<td><a href="{{ $site->url }}">{{ $site->name }}</a>
- {{ $site->description }}</td>
</tr>
@endforeach
</table>
<br>
@endforeach
@endif
@stop

View file

@ -1,7 +0,0 @@
@extends('layouts.default')
@section('title', 'Discord Bot')
@section('description', '')
@section('content')
<p>The diskfloppy.me Discord bot blah blah blah blah blah</p>
<p>Maybe I'll finish this page later idk</p>
@stop

View file

@ -1,442 +0,0 @@
@extends('layouts.default')
@section('title', 'Computers')
@section('description', 'Computers I own or have owned.')
@section('content')
<table class="computers">
<tr>
<th>PICTURES</th>
<th>SPECS &amp; DESCRIPTION</th>
</tr>
<tr>
<td>2023 MacBook Pro 14"</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Apple M3 Pro</li>
<li>18GB RAM</li>
<li>500GB SSD</li>
<li>macOS Sonoma</li>
</ul>
<p class="description">WHAT</p>
</td>
</tr>
<tr>
<td>2018 MacBook Pro 13"</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel i5-8259U @ 2.3GHz</li>
<li>Intel Iris Plus Graphics 655</li>
<li>8GB RAM</li>
<li>250GB SSD</li>
<li>macOS Sonoma</li>
</ul>
</td>
</tr>
<tr>
<td>2012 Lenovo ThinkPad T430</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Core i7</li>
<li>16GB RAM</li>
<li>Windows 7 Professional</li>
</ul>
</td>
</tr>
<tr>
<td>2005 IBM ThinkPad X41T</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Pentium M @ 1.6GHz</li>
<li>Mobile Intel Express Chipset Family (128MB)</li>
<li>1.5GB RAM</li>
<li>40GB HDD</li>
<li>Windows XP Tablet PC Edition</li>
</ul>
</td>
</tr>
<tr>
<td>1999 Dell OptiPlex GX1</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Pentium II (Deschutes) @ 400MHz</li>
<li>ATI 3D Rage Pro (4MB)</li>
<li>639MB</li>
<li>40GB HDD</li>
<li>MS-DOS 6.22 &amp; WFW 3.10</li>
</ul>
</td>
</tr>
<tr>
<td>2003 IBM ThinkPad T40</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Pentium M @ 1.3GHz</li>
<li>ATI Mobility Radeon 7500 (32MB)</li>
<li>1GB RAM</li>
<li>30GB HDD</li>
<li>Windows 2000 Professional</li>
</ul>
</td>
</tr>
<tr>
<td>2010 HP Compaq Elite 8100</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Core i7</li>
<li>16GB RAM</li>
<li>some SSD and an HDD</li>
<li>Windows Vista Ultimate (64-bit)</li>
</ul>
</td>
</tr>
<tr>
<td>2014 Mac mini</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Core i5-4278U @ 2.6GHz</li>
<li>Intel Iris Graphics</li>
<li>8GB RAM</li>
<li>1TB HDD</li>
<li>VMware ESXi 6.7.0u3</li>
</ul>
</td>
</tr>
<tr>
<td>1996 Fujitsu Milan</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Pentium</li>
<li>32MB RAM</li>
<li>1215MB HDD</li>
<li>Windows 98 SE</li>
</ul>
</td>
</tr>
<tr>
<td>1999 Compaq Armada M300</td>
<td>
<section-title>Quick Specs</section-title>
<ul>
<li>Intel Pentium III</li>
</ul>
</td>
</tr>
</table>
<!--<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Custom Build</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">NixOS 22.11 / Windows 10 Pro</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel i7-6700K (8-core) @ 4.0GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">NVidia GTX 1060 (3GB)</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">64GB</td>
</tr>
<tr>
<td class="spec-title">DISK0:</td>
<td class="spec">SanDisk SSD Plus (120GB, Win10)</td>
</tr>
<tr>
<td class="spec-title">DISK1:</td>
<td class="spec">Crucial CT500MX500SSD1 (500GB, NixOS)</td>
</tr>
<tr>
<td class="spec-title">DISK2:</td>
<td class="spec">WDC WD20EZEAZ-00GGJB0 (2TB, Data)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>MacBook Pro (2018)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">macOS 12.5.1</td>
</tr>
<tr>
<td class="spec-title">Display:</td>
<td class="spec">2560x1600 (Retina)</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel i5-8259U (8-core) @ 2.3GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">Intel Iris Plus Graphics 655</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">8GB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">Apple SSD AP0256M (250GB)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Lenovo ThinkPad T430 (2012)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">NixOS 22.11 / Windows 7 Ultimate</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel i7-3520M (4-core) @ 3.6GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">Intel 3rd Gen Core processor Graphics Controllertd>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">16GB</td>
</tr>
<tr>
<td class="spec-title">DISK0:</td>
<td class="spec">Crucial CT500MX500SSD1 (500GB, NixOS)</td>
</tr>
<tr>
<td class="spec-title">DISK1:</td>
<td class="spec">Crucial CT250MX500SSD1 (250GB, Win7)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>IBM ThinkPad X41 (2005)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">Windows XP Tablet PC Edition (2005, SP3)</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel Pentium M (single-core) @ 1.6GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">Mobile Intel 915GM/GMS 910GML Express Chipset Family (128MB)</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">1.5GB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">Hitachi HTC426040G9AT00 (40GB)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Dell OptiPlex GX1 (400L+, 1999)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">Windows 3.10 for Workgroups (DOS 6.22)</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel Pentium II (Deschutes) @ 400MHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">ATI 3D Rage Pro (4MB)</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">639MB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">Unknown</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>IBM ThinkPad T40 (2003)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">Windows XP Pro</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel Pentium M (single-core) @ 1.3GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">ATI Mobility Radeon 7500 (32MB)</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">1GB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">Fujitsu MHS2030AT (30GB)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>HP Compaq Elite 8100 CMT</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">Windows Vista 64-bit</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel Core i7</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec"></td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">16GB</td>
</tr>
<tr>
<td class="spec-title">DISK0:</td>
<td class="spec">SanDisk SSD Plus (120GB, Win10)</td>
</tr>
<tr>
<td class="spec-title">DISK1:</td>
<td class="spec">Crucial CT500MX500SSD1 (500GB, NixOS)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Mac mini (2014)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">VMware ESXi 6.7.0u3</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel i5-4278U (4-core) @ 2.6GHz</td>
</tr>
<tr>
<td class="spec-title">GPU:</td>
<td class="spec">Intel Iris Graphics</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">8GB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">Apple HDD HTS541 (1TB)</td>
</tr>
</table>
</td>
</tr>
</table>
<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Fujitsu Milan (1996)</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec-title">OS:</td>
<td class="spec">Windows 98 SE</td>
</tr>
<tr>
<td class="spec-title">CPU:</td>
<td class="spec">Intel Pentium</td>
</tr>
<tr>
<td class="spec-title">Memory:</td>
<td class="spec">32MB</td>
</tr>
<tr>
<td class="spec-title">DISK:</td>
<td class="spec">IBM DPRA-21215 (1215MB)</td>
</tr>
</table>
</td>
</tr>
</table>-->
<!--<table class="computer" role="presentation">
<tr>
<td colspan="2"><h2>Compaq Armada M300</h2><hr></td>
</tr>
<tr>
<td>
<table class="computer-specs">
<tr>
<td class="spec">TBD</td>
</tr>
</table>
</td>
</tr>
</table>-->
@stop

View file

@ -1,88 +0,0 @@
@extends('layouts.default')
@section('title', 'Home')
@section('description', 'This is the personal homepage of floppydisk.')
@section('content')
<p>Hi! This is my personal homepage on the <strong>W</strong>orld <strong>W</strong>ide <strong>W</strong>eb.</p>
<table class="info-table" role="presentation">
<caption>
<h2>QuickFacts&trade;</h2>
<hr>
</caption>
<tr>
<td>&#9670; 18 y/o, he/him, British</td>
</tr>
<tr>
<td>&#9670; Theatre Technician, &quot;Web Developer&quot; and NixOS User</td>
</tr>
<tr>
<td>&#9670; Loves ETC desks, prefers Generics to LEDs for some reason</td>
</tr>
<tr>
<td>&#9670; Spends way too much time on his computer</td>
</tr>
<tr>
<td>&#9670; Favorite games: <a href="https://steamcommunity.com/id/floppydisk05/recommended/420530/">OneShot</a>, Minecraft, Stardew Valley, N++ and Starbound</td>
</tr>
<tr>
<td>&#9670; <a href="http://wxqa.com/">CWOP</a> member</td>
</tr>
</table>
<br>
<table class="info-table" role="presentation">
<caption>
<h2>Interests</h2>
<hr>
</caption>
<tr>
<td>&#9670; <b>Tech Theatre</b></td>
<td>- Lighting, Stage Management, etc. (<a href="https://www.controlbooth.com/members/floppydisk.28673/">ControlBooth</a>)</td>
</tr>
<tr>
<td>&#9670; <b>Programming</b></td>
<td>- HTML, CSS, JavaScript, C#, Java, PHP, Ruby, Python (<a href="https://github.com/floppydisk05">GitHub</a>)</td>
</tr>
<tr>
<td>&#9670; <b>Photography</b></td>
<td>- <a href="https://www.flickr.com/photos/floppydisk/">Flickr</a></td>
</tr>
<tr>
<td>&#9670; <b>Gaming</b></td>
<td>- <a href="https://steamcommunity.com/id/floppydisk05/">Steam Profile</a></td>
</tr>
</table>
<br>
<table class="info-table never-said" role="presentation">
<caption>
<h2>Things they never said</h2>
<hr>
</caption>
<tr>
<script type="text/javascript" src="/js/neverSaid.js"></script>
<noscript><td>Oops! You need JavaScript enabled to view this content.</td></noscript>
</tr>
</table>
<br>
<table class="info-table" role="presentation">
<caption>
<h2>Contact &amp; social</h2>
<hr>
</caption>
<tr>
<td><strong>E-mail:</strong></td>
<td><a href="mailto:contact@diskfloppy.me">contact@diskfloppy.me</a></td>
</tr>
<tr>
<td><strong>Mastodon:</strong></td>
<td><a rel="me" href="https://c.im/@floppydisk">@floppydisk@c.im</a></td>
</tr>
<tr>
<td><strong>Matrix:</strong></td>
<td><a href="https://matrix.to/#/@floppydisk:arcticfoxes.net">@floppydisk:arcticfoxes.net</a></td>
</tr>
</table>
@stop

View file

@ -1,66 +0,0 @@
@extends('layouts.default')
@section('title', 'Music')
@section('description', '')
@section('content')
@php
$cfg = app('config')->get('services')['lastfm'];
$api_root = app('config')->get('app')['api_root'];
$api_alive = true;
try {
$data = file_get_contents($api_root.'/lastfm/current');
} catch (Exception $e) {
$api_alive = false;
}
@endphp
@if (!$api_alive)
@include('components.errors.api-error')
@else
@php
$current_track = json_decode(file_get_contents($api_root . '/lastfm/current'));
$top_tracks = json_decode(file_get_contents($api_root . '/lastfm/top'));
$count = 0;
@endphp
<table class="info-table" role="presentation" width="100%">
<tr>
<td colspan="4">
<h2>Last/Current Track:</h2>
</td>
</tr>
<tr>
<td colspan="4">
<a href="{{ $current_track->url }}">{{ $current_track->title }} {{ $current_track->artist }}</a><br>
</td>
</tr>
</table>
<hr>
<table class="music-top10">
<tr>
<td colspan="4">
<h2 style="margin-bottom: 5px">Top {{ $cfg['toptracks'] }} Tracks (Last 7 days)</h2>
</td>
</tr>
<tr>
<td style="text-align: right"><b>#</b></td>
<td><b>Track</b></td>
<td><b>Artist</b></td>
<td><b>Plays</b></td>
</tr>
@foreach ($top_tracks as $track)
@php $count++ @endphp
@if ($count >= $cfg['toptracks']+1)
@break
@endif
<tr>
<td style="text-align: right">{{ $count }}</td>
<td style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:1px;" width="50%"><a href="{{ $track->url }}">{{ $track->title }}</a></td>
<td style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:1px;" width="50%">{{ $track->artist }}</td>
<td>{{ $track->playcount }}</td>
</tr>
@endforeach
</table>
@endif
@stop

View file

@ -1,16 +0,0 @@
<?php $categories = app('config')->get('projects'); ?>
@extends('layouts.default')
@section('title', 'Projects')
@section('description', 'My projects')
@section('content')
@foreach ($categories as $category)
<h2>{{ $category['name']}}</h2>
@foreach ($category['projects'] as $project)
<div>
<a href="{{ $project['url'] }}">{{ $project['name'] }}</a> - {{ $project['description'] }}<br>
<b>Languages:</b> {{ implode(", ", $project['languages']) }}
</div>
<br>
@endforeach
@endforeach
@stop

View file

@ -1,6 +0,0 @@
@extends('layouts.default')
@section('title', 'Page Title')
@section('description', 'Page description goes here')
@section('content')
<p>page content</p>
@stop

View file

@ -1,61 +0,0 @@
@extends('layouts.default')
@section('title', 'Weather')
@section('description', 'Data from my weather station')
@section('content')
@php
$api_root = app('config')->get('app')['api_root'];
function degreesToCompassDirection($degrees) {
$cardinalDirections = [
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'
];
return $cardinalDirections[round($degrees*16/360)];
}
$api_alive = true;
try {
$data = file_get_contents($api_root.'/weather');
} catch (Exception $e) {
$api_alive = false;
}
@endphp
@if (!$api_alive)
@include('components.errors.api-error')
@else
@php
$data = json_decode(file_get_contents($api_root.'/weather'));
$updated = gmdate('H:i Y-m-d', $data->updated);
$data = $data->current;
@endphp
<table class="info-table" role="presentation">
<caption>
<h2>Local Weather</h2>
<hr>
</caption>
<tr>
<td><b>Wind Speed:</b></td>
<td>{{ $data->wind->speed }} mph</td>
</tr>
<tr>
<td><b>Wind Direction:</b></td>
<td>{{ $data->wind->direction->degrees }}°, {{ $data->wind->direction->cardinal }}</td>
</tr>
<tr>
<td><b>Temperature:</b></td>
<td>{{ $data->temperature }}°C</td>
</tr>
<tr>
<td><b>Rain Rate:</b></td>
<td>{{ $data->rain_rate }} mm/hr</td>
</tr>
<tr>
<td><b>Humidity:</b></td>
<td>{{ $data->humidity }}%</td>
</tr>
</table>
<br>
<small><i>(Last Update: {{ $updated }})</i></small>
@endif
@stop

View file

@ -1,8 +1,15 @@
<?php
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\AdminBookmarksController;
use App\Http\Controllers\AdminGuestbookController;
use App\Http\Controllers\AdminImportController;
use App\Http\Controllers\BookmarksController;
use App\Http\Controllers\CalculatorsController;
use App\Http\Controllers\ComputersController;
use App\Http\Controllers\GuestbookController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\MusicController;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;
/*
|--------------------------------------------------------------------------
@ -15,87 +22,23 @@
|
*/
Route::get('/', function () {
return View::make('pages.home');
});
Route::get('/bookmarks', function () {
return View::make('pages.bookmarks');
});
Route::get('/projects', function () {
return View::make('pages.projects');
});
Route::get('/calculators', function () {
return View::make('pages.calculators');
});
Route::get('/computers', function () {
return View::make('pages.computers');
});
Route::get('/guestbook', 'App\Http\Controllers\GuestbookController@guestbook')
->name('guestbook');
Route::post('/guestbook', 'App\Http\Controllers\GuestbookController@guestbookpost')
->name('guestbookPost')
Route::get('/', [HomeController::class, 'show']);
Route::get('/bookmarks', [BookmarksController::class, 'show']);
Route::get('/guestbook', [GuestbookController::class, 'show']);
Route::post('/guestbook', [GuestbookController::class, 'addEntry'])
->middleware('rate_limit');
Route::get('/calculators', [CalculatorsController::class, 'show']);
Route::get('/computers', [ComputersController::class, 'show']);
Route::get('/music', [MusicController::class, 'show']);
Route::get('/weather', function () {
return View::make('pages.weather');
});
Route::get('/music', function () {
return View::make('pages.music');
});
Route::get('/bot', function () {
return View::make('pages.bot');
});
/* ------------------------------ Admin Routes ------------------------------ */
//Route::get('/admin', function () {
// if (!auth()->check()) {
// return View::make('errors.no-auth');
// }
// return View::make('pages.admin.index');
//});
//
//Route::get('/admin/guestbook', function () {
// if (!auth()->check()) {
// return View::make('errors.no-auth');
// }
// return View::make('pages.admin.guestbook');
//});
//
//Route::get('/admin/guestbook/delete', function () {
// if (!auth()->check()) {
// return View::make('errors.no-auth');
// }
//
// $id = request()->input('id');
// $entry = DB::table('guestbook__entries')->find($id);
//
// if ($entry) {
// // Render a confirmation view
// return View::make('pages.admin.guestbook-del-confirm', compact('entry'));
// } else {
// return View::make('errors.generic-error')
// ->with('error', "Entry not found")
// ->with('description', "The specified entry does not exist!");
// }
//});
//
//Route::post('/admin/guestbook/delete', function () {
// if (!auth()->check()) {
// return View::make('errors.no-auth');
// }
//
// $id = request()->input('id');
// DB::table('guestbook__entries')->where('id', $id)->delete();
//
// return back()->with('success', 'Entry deleted successfully!');
//});
// Admin pages
Route::get('/admin/guestbook', [AdminGuestbookController::class, 'show']);
// TODO: Re-enable before release
// ->middleware('auth');
Route::get('/admin/bookmarks', [AdminBookmarksController::class, 'show']);
// TODO: Re-enable before release
// ->middleware('auth');
Route::get('/admin/import', [AdminImportController::class, 'show']);
Route::post('/admin/import', [AdminImportController::class, 'submit'])
->name('admin.import.submit');