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,6 +31,7 @@ class UserProfileController extends Controller
|
|||||||
$this->validateTwoFactorAuthenticationState($request);
|
$this->validateTwoFactorAuthenticationState($request);
|
||||||
|
|
||||||
return Jetstream::inertia()->render($request, 'Profile/Show', [
|
return Jetstream::inertia()->render($request, 'Profile/Show', [
|
||||||
|
'confirmsTwoFactorAuthentication' => Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'),
|
||||||
'sessions' => $this->sessions($request)->all(),
|
'sessions' => $this->sessions($request)->all(),
|
||||||
'timezones' => timezone_identifiers_list(),
|
'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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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']}",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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 | **/
|
||||||
/** +--------------------------------+ **/
|
/** +--------------------------------+ **/
|
||||||
|
|||||||
@@ -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" },
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user