Compare commits
13 Commits
072d6a7e73
...
2d9eb8640b
Author | SHA1 | Date | |
---|---|---|---|
2d9eb8640b | |||
78bb0f72d5 | |||
a14e1b20c0 | |||
6241539cb3 | |||
b87104c22d | |||
5b8a3b3714 | |||
5f9d23e24a | |||
962f8eb6ad | |||
28a7b3a387 | |||
5dbfc74c3b | |||
7f1dbd0f14 | |||
76790b4ebf | |||
33d9e5ec06 |
@ -34,6 +34,12 @@ REDIS_HOST=redis
|
|||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
SCOUT_DRIVER=meilisearch
|
||||||
|
SCOUT_PREFIX=
|
||||||
|
SCOUT_QUEUE=false
|
||||||
|
MEILISEARCH_HOST=http://localhost:7700
|
||||||
|
MEILISEARCH_KEY=
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=mailhog
|
MAIL_HOST=mailhog
|
||||||
MAIL_PORT=1125
|
MAIL_PORT=1125
|
||||||
@ -58,8 +64,17 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
|||||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
INTEGRITY_HASH_HUMANS_TXT=""
|
INTEGRITY_HASH_HUMANS_TXT=""
|
||||||
|
INTEGRITY_HASH_ROBOTS_TXT=""
|
||||||
INTEGRITY_HASH_COPYRIGHT_HTML=""
|
INTEGRITY_HASH_COPYRIGHT_HTML=""
|
||||||
|
INTEGRITY_HASH_COPYRIGHT_MD=""
|
||||||
|
INTEGRITY_HASH_RSS_FEED=""
|
||||||
|
INTEGRITY_HASH_ATOM_FEED=""
|
||||||
|
INTEGRITY_HASH_FAVICON_ICO=""
|
||||||
|
INTEGRITY_HASH_FAVICON_PNG=""
|
||||||
|
INTEGRITY_HASH_FAVICON_SVG=""
|
||||||
INTEGRITY_HASH_NUNITO_REGULAR_WOFF2_FONT=""
|
INTEGRITY_HASH_NUNITO_REGULAR_WOFF2_FONT=""
|
||||||
INTEGRITY_HASH_POIRETONE_REGULAR_WOFF2_FONT=""
|
INTEGRITY_HASH_POIRETONE_REGULAR_WOFF2_FONT=""
|
||||||
|
INTEGRITY_HASH_WEBMANIFEST_JSON=""
|
||||||
|
INTEGRITY_HASH_MIX_MANIFEST_JSON=""
|
||||||
INTEGRITY_HASH_APP_CSS=""
|
INTEGRITY_HASH_APP_CSS=""
|
||||||
INTEGRITY_HASH_APP_JS=""
|
INTEGRITY_HASH_APP_JS=""
|
||||||
|
@ -9,10 +9,14 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Inertia\Response;
|
use Inertia\Response;
|
||||||
use Jenssegers\Agent\Agent;
|
use Jenssegers\Agent\Agent;
|
||||||
|
use Laravel\Fortify\Features;
|
||||||
|
use Laravel\Jetstream\Http\Controllers\Inertia\Concerns\ConfirmsTwoFactorAuthentication;
|
||||||
use Laravel\Jetstream\Jetstream;
|
use Laravel\Jetstream\Jetstream;
|
||||||
|
|
||||||
class UserProfileController extends Controller
|
class UserProfileController extends Controller
|
||||||
{
|
{
|
||||||
|
use ConfirmsTwoFactorAuthentication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the general profile settings screen.
|
* Show the general profile settings screen.
|
||||||
*
|
*
|
||||||
@ -27,8 +31,9 @@ class UserProfileController extends Controller
|
|||||||
$this->validateTwoFactorAuthenticationState($request);
|
$this->validateTwoFactorAuthenticationState($request);
|
||||||
|
|
||||||
return Jetstream::inertia()->render($request, 'Profile/Show', [
|
return Jetstream::inertia()->render($request, 'Profile/Show', [
|
||||||
'sessions' => $this->sessions($request)->all(),
|
'confirmsTwoFactorAuthentication' => Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'),
|
||||||
'timezones' => timezone_identifiers_list(),
|
'sessions' => $this->sessions($request)->all(),
|
||||||
|
'timezones' => timezone_identifiers_list(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ class CheckCustomSessionData
|
|||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
if ((! session()->has('timezone_name') || empty(session('timezone_name'))) && $request->user()) {
|
if ((! session()->has('thing') || empty(session('thing'))) && $request->user()) {
|
||||||
session()->put('timezone_name', $request->user()->timezone_name);
|
session()->put('thing', $request->user()->thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
33
src/app/Listeners/SuccessfulLogin.php
Normal file
33
src/app/Listeners/SuccessfulLogin.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Login;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class SuccessfulLogin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Auth\Events\Login $event
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(Login $event): void
|
||||||
|
{
|
||||||
|
Session::put('timezone_name', $event->user->timezone_name);
|
||||||
|
}
|
||||||
|
}
|
32
src/app/Listeners/SuccessfulLogout.php
Normal file
32
src/app/Listeners/SuccessfulLogout.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Logout;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class SuccessfulLogout
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Auth\Events\Logout $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(Logout $event)
|
||||||
|
{
|
||||||
|
Session::forget('timezone_name');
|
||||||
|
}
|
||||||
|
}
|
@ -64,7 +64,7 @@ class User extends Authenticatable
|
|||||||
/** @var array */
|
/** @var array */
|
||||||
protected $appends = [
|
protected $appends = [
|
||||||
'full_name',
|
'full_name',
|
||||||
'name_full',
|
'surname_full',
|
||||||
'profile_photo_url',
|
'profile_photo_url',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ class User extends Authenticatable
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||||
*/
|
*/
|
||||||
public function fullNameReversed(): Attribute
|
public function surnameFull(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: fn ($value, $attributes) => "{$attributes['surname']}, {$attributes['name']}",
|
get: fn ($value, $attributes) => "{$attributes['surname']}, {$attributes['name']}",
|
||||||
|
76
src/app/Providers/CarbonServiceProvider.php
Normal file
76
src/app/Providers/CarbonServiceProvider.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class CarbonServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
Carbon::macro('getHumanInterval', function ($other) {
|
||||||
|
$isNow = $other === null;
|
||||||
|
|
||||||
|
if ($isNow) {
|
||||||
|
$other = static::now($this->tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
$diffInMinutes = $this->diffInMinutes($other);
|
||||||
|
|
||||||
|
$minutes = $diffInMinutes % 60;
|
||||||
|
|
||||||
|
$diffInHours = $diffInMinutes / 60;
|
||||||
|
$hours = $diffInHours % 60;
|
||||||
|
|
||||||
|
$diffInDays = $diffInHours / 24;
|
||||||
|
$days = $diffInDays % 24;
|
||||||
|
|
||||||
|
$diffInWeeks = $diffInDays / 24;
|
||||||
|
$weeks = $diffInWeeks % 24;
|
||||||
|
|
||||||
|
$diffInMonths = $diffInWeeks / 7;
|
||||||
|
$months = $diffInMonths % 7;
|
||||||
|
|
||||||
|
$diffInYears = $diffInMonths / 12;
|
||||||
|
$years = $diffInYears % 12;
|
||||||
|
|
||||||
|
$outputArray = [];
|
||||||
|
if ($years > 0) {
|
||||||
|
$outputArray['years'] = "$years years";
|
||||||
|
}
|
||||||
|
if ($months > 0) {
|
||||||
|
$outputArray['months'] = "$months months";
|
||||||
|
}
|
||||||
|
if ($weeks > 0 && $days === 0) {
|
||||||
|
$outputArray['weeks'] = "$weeks weeks";
|
||||||
|
}
|
||||||
|
if ($days > 0) {
|
||||||
|
$outputArray['days'] = "$days days";
|
||||||
|
}
|
||||||
|
if ($hours > 0) {
|
||||||
|
$outputArray['hours'] = "$hours hours";
|
||||||
|
}
|
||||||
|
if ($minutes > 0) {
|
||||||
|
$outputArray['minutes'] = "$minutes minutes";
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(', ', $outputArray);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
52
src/app/Providers/EventServiceProvider.php
Normal file
52
src/app/Providers/EventServiceProvider.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Listeners\SuccessfulLogin;
|
||||||
|
//use App\Listeners\SuccessfulLogout;
|
||||||
|
use Illuminate\Auth\Events\Login;
|
||||||
|
//use Illuminate\Auth\Events\Logout;
|
||||||
|
use Illuminate\Auth\Events\Registered;
|
||||||
|
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||||
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
|
use Illuminate\Support\Facades\Event;
|
||||||
|
|
||||||
|
class EventServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The event to listener mappings for the application.
|
||||||
|
*
|
||||||
|
* @var array<class-string, array<int, class-string>>
|
||||||
|
*/
|
||||||
|
protected $listen = [
|
||||||
|
Registered::class => [
|
||||||
|
SendEmailVerificationNotification::class,
|
||||||
|
],
|
||||||
|
Login::class => [
|
||||||
|
SuccessfulLogin::class,
|
||||||
|
],
|
||||||
|
/*Logout::class => [
|
||||||
|
SuccessfulLogout::class,
|
||||||
|
],*/
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any events for your application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if events and listeners should be automatically discovered.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function shouldDiscoverEvents()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
22
src/config/app.php
Normal file
22
src/config/app.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application Service Providers...
|
||||||
|
*/
|
||||||
|
...
|
||||||
|
App\Providers\CarbonServiceProvider::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
];
|
@ -5,6 +5,8 @@ if (! function_exists('snake2Title')) {
|
|||||||
* Convert a snake case string to a title with spaces
|
* Convert a snake case string to a title with spaces
|
||||||
* and every word capitalized.
|
* and every word capitalized.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param string $stakeSlug A snake case string, commonly a slug
|
* @param string $stakeSlug A snake case string, commonly a slug
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
@ -22,6 +24,8 @@ if (! function_exists('carbon')) {
|
|||||||
* It will attempt to find a timezone in the current
|
* It will attempt to find a timezone in the current
|
||||||
* session but default to UTC.
|
* session but default to UTC.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param string|null $timestring
|
* @param string|null $timestring
|
||||||
*
|
*
|
||||||
* @return \Carbon\Carbon
|
* @return \Carbon\Carbon
|
||||||
@ -40,6 +44,8 @@ if (! function_exists('jddayofweek')) {
|
|||||||
/**
|
/**
|
||||||
* Returns the day of the week. Can return a string or an integer depending on the mode.
|
* Returns the day of the week. Can return a string or an integer depending on the mode.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param int|null $intDay
|
* @param int|null $intDay
|
||||||
* @param int $mode
|
* @param int $mode
|
||||||
*
|
*
|
||||||
@ -59,10 +65,106 @@ if (! function_exists('jddayofweek')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! function_exists('is_serialized')) {
|
||||||
|
/**
|
||||||
|
* Check a value to find if it was serialized.
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @param bool $strict
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function is_serialized($data, bool $strict = true): bool
|
||||||
|
{
|
||||||
|
// If it isn't a string, it isn't serialized.
|
||||||
|
if (! is_string($data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = trim($data);
|
||||||
|
if ('N;' === $data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strlen($data) < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (':' !== $data[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($strict) {
|
||||||
|
$lastc = substr($data, -1);
|
||||||
|
if (';' !== $lastc && '}' !== $lastc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$semicolon = strpos($data, ';');
|
||||||
|
$brace = strpos($data, '}');
|
||||||
|
// Either ; or } must exist.
|
||||||
|
if (!$semicolon && !$brace) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// But neither must be in the first X characters.
|
||||||
|
if ($semicolon && $semicolon < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($brace && $brace < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$token = $data[0];
|
||||||
|
switch ($token) {
|
||||||
|
case 's':
|
||||||
|
if ($strict) {
|
||||||
|
if ('"' !== substr($data, -2, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif (!strpos($data, '"')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Or else fall through.
|
||||||
|
case 'a':
|
||||||
|
case 'O':
|
||||||
|
return (bool) preg_match("/^{$token}:[0-9]+:/s", $data);
|
||||||
|
case 'b':
|
||||||
|
case 'i':
|
||||||
|
case 'd':
|
||||||
|
$end = $strict ? '$' : '';
|
||||||
|
return (bool) preg_match("/^{$token}:[0-9.E+-]+;$end/", $data);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! function_exists('maybe_unserialize')) {
|
||||||
|
/**
|
||||||
|
* Unserialize data only if it was serialized. Will return
|
||||||
|
* an array if it was a serialized string, otherwise it
|
||||||
|
* will return whatever was passed into the function
|
||||||
|
* leaving it untouched.
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function maybe_unserialize($data)
|
||||||
|
{
|
||||||
|
if (is_serialized($data)) { // Don't attempt to unserialize data that wasn't serialized going in.
|
||||||
|
return @unserialize(trim($data));
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! function_exists('cel2Fah')) {
|
if (! function_exists('cel2Fah')) {
|
||||||
/**
|
/**
|
||||||
* Convert from celsius to fahrenheit.
|
* Convert from celsius to fahrenheit.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $celsius
|
* @param float|int|string $celsius
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -78,6 +180,8 @@ if (! function_exists('fah2Cel')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from fahrenheit to celsius.
|
* Convert from fahrenheit to celsius.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $fahrenheit
|
* @param float|int|string $fahrenheit
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -93,6 +197,8 @@ if (! function_exists('meters2Miles')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from meters to miles.
|
* Convert from meters to miles.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $meters
|
* @param float|int|string $meters
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -108,6 +214,8 @@ if (! function_exists('kilometers2Miles')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from kilometers to meters.
|
* Convert from kilometers to meters.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $kilometers
|
* @param float|int|string $kilometers
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -123,6 +231,8 @@ if (! function_exists('m2Km')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from meters to kilometers.
|
* Convert from meters to kilometers.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $meters
|
* @param float|int|string $meters
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -138,6 +248,8 @@ if (! function_exists('mm2Inches')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from milimeters to inches.
|
* Convert from milimeters to inches.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $milimeters
|
* @param float|int|string $milimeters
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
@ -153,6 +265,8 @@ if (! function_exists('pa2Mbar')) {
|
|||||||
/**
|
/**
|
||||||
* Convert from pascals to milibars.
|
* Convert from pascals to milibars.
|
||||||
*
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
* @param float|int|string $pascals
|
* @param float|int|string $pascals
|
||||||
* @param int $precision
|
* @param int $precision
|
||||||
*
|
*
|
||||||
|
BIN
src/public/fonts/RobotoMono/RobotoMono-Bold.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-Bold.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-BoldItalic.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-BoldItalic.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-Italic.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-Italic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-Regular.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-Regular.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-SemiBold.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-SemiBold.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-SemiBoldItalic.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-SemiBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/RobotoMono/RobotoMono-VariableFont_wght.woff2
Normal file
BIN
src/public/fonts/RobotoMono/RobotoMono-VariableFont_wght.woff2
Normal file
Binary file not shown.
@ -1,3 +1,11 @@
|
|||||||
|
.spin {
|
||||||
|
animation: spin 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
/** https://thinkdobecreate.com/articles/css-animating-newly-added-element/ **/
|
/** https://thinkdobecreate.com/articles/css-animating-newly-added-element/ **/
|
||||||
|
|
||||||
.anim-show {
|
.anim-show {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
@import 'tailwindcss/utilities';
|
@import 'tailwindcss/utilities';
|
||||||
|
|
||||||
@import 'animations.css';
|
@import 'animations.css';
|
||||||
@import 'typography.css';
|
@import 'fontfaces.css';
|
||||||
|
|
||||||
@import 'components/buttons.css';
|
@import 'components/buttons.css';
|
||||||
@import 'components/cards.css';
|
@import 'components/cards.css';
|
||||||
|
@ -2,6 +2,58 @@
|
|||||||
/** | Sans fonts | **/
|
/** | Sans fonts | **/
|
||||||
/** +--------------------------------+ **/
|
/** +--------------------------------+ **/
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-Regular.woff2') format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-Italic.woff2') format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-SemiBold.woff2') format("woff2");
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-SemiBoldItalic.woff2') format("woff2");
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-Bold.woff2') format("woff2");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "OpenSans";
|
||||||
|
src: url('/fonts/OpenSans/OpenSans-BoldItalic.woff2') format("woff2");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** +--------------------------------+ **/
|
||||||
|
/** | Serif fonts | **/
|
||||||
|
/** +--------------------------------+ **/
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Nunito";
|
font-family: "Nunito";
|
||||||
src: url('/fonts/Nunito/Nunito-Regular.woff2') format("woff2");
|
src: url('/fonts/Nunito/Nunito-Regular.woff2') format("woff2");
|
||||||
@ -50,12 +102,6 @@
|
|||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** +--------------------------------+ **/
|
|
||||||
/** | Serif fonts | **/
|
|
||||||
/** +--------------------------------+ **/
|
|
||||||
|
|
||||||
/**/
|
|
||||||
|
|
||||||
/** +--------------------------------+ **/
|
/** +--------------------------------+ **/
|
||||||
/** | Monospace fonts | **/
|
/** | Monospace fonts | **/
|
||||||
/** +--------------------------------+ **/
|
/** +--------------------------------+ **/
|
||||||
|
81
src/resources/js/Components/DarkModeToggle.vue
Normal file
81
src/resources/js/Components/DarkModeToggle.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<script setup>
|
||||||
|
import { reactive, computed, onBeforeMount, provide } from 'vue'
|
||||||
|
|
||||||
|
const emit = defineEmits(['themeUpdate'])
|
||||||
|
|
||||||
|
let settings = reactive({
|
||||||
|
theme: 'light',
|
||||||
|
})
|
||||||
|
|
||||||
|
const htmlNode = document.documentElement
|
||||||
|
let mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
|
||||||
|
// computed properties
|
||||||
|
const isDarkMode = computed(() => {
|
||||||
|
return settings.theme === 'dark'
|
||||||
|
})
|
||||||
|
|
||||||
|
const isLightMode = computed(() => {
|
||||||
|
return settings.theme === 'light'
|
||||||
|
})
|
||||||
|
|
||||||
|
// lifecycle hooks
|
||||||
|
onBeforeMount(() => {
|
||||||
|
window.addEventListener('storage', update)
|
||||||
|
|
||||||
|
if (mediaQuery?.addEventListener) {
|
||||||
|
mediaQuery.addEventListener('change', update)
|
||||||
|
}
|
||||||
|
|
||||||
|
update()
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
provide('darkMode', isDarkMode)
|
||||||
|
})
|
||||||
|
|
||||||
|
// methods
|
||||||
|
const update = () => {
|
||||||
|
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
setModeDark()
|
||||||
|
} else {
|
||||||
|
setModeLight()
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('themeUpdate')
|
||||||
|
}
|
||||||
|
|
||||||
|
const setModeDark = () => {
|
||||||
|
settings.theme = 'dark'
|
||||||
|
localStorage.theme = 'dark'
|
||||||
|
htmlNode.classList.remove('light')
|
||||||
|
htmlNode.classList.add('dark')
|
||||||
|
}
|
||||||
|
|
||||||
|
const setModeLight = () => {
|
||||||
|
settings.theme = 'light'
|
||||||
|
localStorage.theme = 'light'
|
||||||
|
htmlNode.classList.remove('dark')
|
||||||
|
htmlNode.classList.add('light')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center cursor-pointer">
|
||||||
|
<svg v-show="isDarkMode" @click="setModeLight" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" preserveAspectRatio="xMidYMid meet">
|
||||||
|
<circle cx="12" cy="12" r="5"></circle>
|
||||||
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||||
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||||
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||||
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-show="isLightMode" @click="setModeDark" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" preserveAspectRatio="xMidYMid meet">
|
||||||
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -1,5 +1,62 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { Link } from '@inertiajs/inertia-vue3'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
paginationData: Object,
|
||||||
|
})
|
||||||
|
|
||||||
|
// computed properties
|
||||||
|
const onFirstPage = computed(() => {
|
||||||
|
return props.paginationData.current_page === 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasMorePages = computed(() => {
|
||||||
|
return props.paginationData.current_page < props.paginationData.last_page
|
||||||
|
})
|
||||||
|
|
||||||
|
const nextPageUrl = computed(() => {
|
||||||
|
return props.paginationData.next_page_url
|
||||||
|
})
|
||||||
|
|
||||||
|
const previousPageUrl = computed(() => {
|
||||||
|
return props.paginationData.prev_page_url
|
||||||
|
})
|
||||||
|
|
||||||
|
const firstItem = computed(() => {
|
||||||
|
if (props.paginationData.from == null) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
return props.paginationData.from
|
||||||
|
})
|
||||||
|
|
||||||
|
const lastItem = computed(() => {
|
||||||
|
if (props.paginationData.to == null) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
return props.paginationData.to
|
||||||
|
})
|
||||||
|
|
||||||
|
const total = computed(() => {
|
||||||
|
if (isNaN(props.paginationData.total)) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
return props.paginationData.total
|
||||||
|
})
|
||||||
|
|
||||||
|
// watchers
|
||||||
|
|
||||||
|
// lifecycle hooks
|
||||||
|
|
||||||
|
// methods
|
||||||
|
const isFirstOrLastOrDots = (index, linksLength, label) => {
|
||||||
|
return index === 0 || index === linksLength - 1 || label.includes('...')
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav v-if="pagi !== undefined" class="flex items-center justify-between" role="navigation">
|
<nav v-if="paginationData !== undefined" class="flex items-center justify-between" role="navigation">
|
||||||
<div class="flex justify-between flex-1 sm:hidden">
|
<div class="flex justify-between flex-1 sm:hidden">
|
||||||
<span v-if="onFirstPage" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-gray-100 border border-gray-300 cursor-default leading-5 rounded-md">
|
<span v-if="onFirstPage" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-gray-100 border border-gray-300 cursor-default leading-5 rounded-md">
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
@ -45,8 +102,8 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div v-for="(link, index) in pagi.links">
|
<div v-for="(link, index) in paginationData.links">
|
||||||
<Link v-if="!isFirstOrLastOrDots(index, pagi.links.length, link.label)" :class="{ 'bg-blue-200' : link.active }" :href="link.url" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150" v-html="link.label"></Link>
|
<Link v-if="!isFirstOrLastOrDots(index, paginationData.links.length, link.label)" :class="{ 'bg-blue-200' : link.active }" :href="link.url" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150" v-html="link.label"></Link>
|
||||||
<span v-else-if="link.label === '...'" aria-disabled="true" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 cursor-default leading-5" v-html="link.label"></span>
|
<span v-else-if="link.label === '...'" aria-disabled="true" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 cursor-default leading-5" v-html="link.label"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -65,63 +122,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
|
||||||
import { defineComponent } from "vue"
|
|
||||||
import { Link } from "@inertiajs/inertia-vue3"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: {
|
|
||||||
pagi: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
components: {
|
|
||||||
Link,
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
onFirstPage() {
|
|
||||||
return this.pagi.current_page === 1
|
|
||||||
},
|
|
||||||
|
|
||||||
hasMorePages() {
|
|
||||||
return this.pagi.current_page < this.pagi.last_page
|
|
||||||
},
|
|
||||||
|
|
||||||
nextPageUrl() {
|
|
||||||
return this.pagi.next_page_url
|
|
||||||
},
|
|
||||||
|
|
||||||
previousPageUrl() {
|
|
||||||
return this.pagi.prev_page_url
|
|
||||||
},
|
|
||||||
|
|
||||||
firstItem() {
|
|
||||||
if (this.pagi.from == null) {
|
|
||||||
return '-'
|
|
||||||
}
|
|
||||||
return this.pagi.from
|
|
||||||
},
|
|
||||||
|
|
||||||
lastItem() {
|
|
||||||
if (this.pagi.to == null) {
|
|
||||||
return '-'
|
|
||||||
}
|
|
||||||
return this.pagi.to
|
|
||||||
},
|
|
||||||
|
|
||||||
total() {
|
|
||||||
if (isNaN(this.pagi.total)) {
|
|
||||||
return '0'
|
|
||||||
}
|
|
||||||
return this.pagi.total
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
isFirstOrLastOrDots(index, linksLength, label) {
|
|
||||||
return index === 0 || index === linksLength - 1 || label.includes('...')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
{{-- <link href="https://de.example.com/2010/06/title-of-my-article" rel="alternate" hreflang="de"> --}}
|
{{-- <link href="https://de.example.com/2010/06/title-of-my-article" rel="alternate" hreflang="de"> --}}
|
||||||
|
|
||||||
<!-- Android web manifest file -->
|
<!-- Android web manifest file -->
|
||||||
{{-- <link href="{{ url('/.webmanifest') }}" rel="manifest"> --}}
|
{{-- <link href="{{ url('/site.webmanifest') }}" rel="manifest" integrity="{{ env('INTEGRITY_HASH_WEBMANIFEST_JSON') }}"> --}}
|
||||||
|
|
||||||
<!-- Files listing who was involved in this site and copyrights -->
|
<!-- Files listing who was involved in this site and copyrights -->
|
||||||
<link href="{{ url('/humans.txt') }}" rel="author" integrity="{{ env('INTEGRITY_HASH_HUMANS_TXT') }}">
|
<link href="{{ url('/humans.txt') }}" rel="author" integrity="{{ env('INTEGRITY_HASH_HUMANS_TXT') }}">
|
||||||
@ -63,9 +63,9 @@
|
|||||||
<link rel="alternate" type="text/xml+oembed" href="https://example.com/services/oembed?url=http%3A%2F%2Fexample.com%2Ffoo%2F&format=xml" title="oEmbed Profile: XML">
|
<link rel="alternate" type="text/xml+oembed" href="https://example.com/services/oembed?url=http%3A%2F%2Fexample.com%2Ffoo%2F&format=xml" title="oEmbed Profile: XML">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
{{-- <link href="{{ asset('/favicon.ico') }}" rel="icon" sizes="16x16" type="image/icon"> --}}
|
{{-- <link href="{{ asset('/favicon.ico') }}" rel="icon" sizes="16x16" type="image/icon" integrity="{{ env('INTEGRITY_HASH_FAVICON_ICO') }}"> --}}
|
||||||
{{-- <link href="{{ asset('/favicon.svg') }}" rel="icon" type="image/svg+xml"> --}}
|
{{-- <link href="{{ asset('/favicon.svg') }}" rel="icon" type="image/svg+xml" integrity="{{ env('INTEGRITY_HASH_FAVICON_SVG') }}"> --}}
|
||||||
{{-- <link href="{{ asset('/favicon.png') }}" rel="icon" sizes="192x192"> --}}
|
{{-- <link href="{{ asset('/favicon.png') }}" rel="icon" sizes="192x192" integrity="{{ env('INTEGRITY_HASH_FAVICON_PNG') }}"> --}}
|
||||||
|
|
||||||
<!-- Font preloads (should be done for each font file) -->
|
<!-- Font preloads (should be done for each font file) -->
|
||||||
<link href="{{ asset('/fonts/Nunito/Nunito-Regular.woff2') }}" rel="preload" as="font" type="font/woff2" integrity="{{ env('INTEGRITY_HASH_NUNITO_REGULAR_WOFF2_FONT') }}" crossorigin="anonymous">
|
<link href="{{ asset('/fonts/Nunito/Nunito-Regular.woff2') }}" rel="preload" as="font" type="font/woff2" integrity="{{ env('INTEGRITY_HASH_NUNITO_REGULAR_WOFF2_FONT') }}" crossorigin="anonymous">
|
||||||
|
@ -3,9 +3,18 @@ const { exec } = require('child_process');
|
|||||||
|
|
||||||
const resIntegrityFiles = [
|
const resIntegrityFiles = [
|
||||||
{ "envKey": "HUMANS_TXT", "path": "public/humans.txt" },
|
{ "envKey": "HUMANS_TXT", "path": "public/humans.txt" },
|
||||||
|
{ "envKey": "ROBOTS_TXT", "path": "public/robots.txt" },
|
||||||
{ "envKey": "COPYRIGHT_HTML", "path": "public/copyright.html" },
|
{ "envKey": "COPYRIGHT_HTML", "path": "public/copyright.html" },
|
||||||
|
{ "envKey": "COPYRIGHT_MD", "path": "public/copyright.md" },
|
||||||
|
{ "envKey": "RSS_FEED", "path": "public/rss.xml" },
|
||||||
|
{ "envKey": "ATOM_FEED", "path": "public/feed.atom" },
|
||||||
|
{ "envKey": "FAVICON_ICO", "path": "public/favicon.ico" },
|
||||||
|
{ "envKey": "FAVICON_SVG", "path": "public/favicon.svg" },
|
||||||
|
{ "envKey": "FAVICON_PNG", "path": "public/favicon.png" },
|
||||||
{ "envKey": "NUNITO_REGULAR_WOFF2_FONT", "path": "public/fonts/Nunito/Nunito-Regular.woff2" },
|
{ "envKey": "NUNITO_REGULAR_WOFF2_FONT", "path": "public/fonts/Nunito/Nunito-Regular.woff2" },
|
||||||
{ "envKey": "POIRETONE_REGULAR_WOFF2_FONT", "path": "public/fonts/PoiretOne/PoiretOne-Regular.woff2" },
|
{ "envKey": "POIRETONE_REGULAR_WOFF2_FONT", "path": "public/fonts/PoiretOne/PoiretOne-Regular.woff2" },
|
||||||
|
{ "envKey": "WEBMANIFEST_JSON", "path": "public/site.webmanifest" },
|
||||||
|
{ "envKey": "MIX_MANIFEST_JSON", "path": "public/mix-manifest.json" },
|
||||||
{ "envKey": "APP_CSS", "path": "public/css/app.css" },
|
{ "envKey": "APP_CSS", "path": "public/css/app.css" },
|
||||||
{ "envKey": "APP_JS", "path": "public/js/app.js" },
|
{ "envKey": "APP_JS", "path": "public/js/app.js" },
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user