Compare commits
28 Commits
fb5bde70ef
...
master
Author | SHA1 | Date | |
---|---|---|---|
ac751f5f28
|
|||
a1aecdf3e2
|
|||
a747ef0129
|
|||
80aa487e7e
|
|||
5048abc3e6
|
|||
afd34e9b4e
|
|||
a81ce8a922
|
|||
9d25befeba
|
|||
5d9f7e3997
|
|||
ecfae3e01a
|
|||
9e6c93ba95
|
|||
231dd959af
|
|||
5607425bde
|
|||
ac99d29109
|
|||
d4f0044656
|
|||
9d455bdcf7
|
|||
3b39ae0470
|
|||
9551f661c1
|
|||
c02b40071f
|
|||
a0dc0e01f3
|
|||
8876f07ac6
|
|||
2ac78ef539
|
|||
56cef79880
|
|||
aa5753cc82
|
|||
4dcb6b6ebe
|
|||
22946bc031
|
|||
e2ce420764
|
|||
7583883d64
|
60
colors.md
Normal file
60
colors.md
Normal file
@ -0,0 +1,60 @@
|
||||
Colors
|
||||
|
||||
### Sunbaked Mint
|
||||
HEX: #80e8d4
|
||||
RGB: 128, 232, 212
|
||||
CMYK: 43, 0, 25, 0
|
||||
|
||||
|
||||
### Honey Dijon
|
||||
HEX: #e2ae61
|
||||
RGB: 226, 174, 97
|
||||
CMYK: 1, 32, 72, 0
|
||||
|
||||
|
||||
### Ultimate Gray
|
||||
HEX: #97999b
|
||||
RGB: 151, 153, 155
|
||||
CMYK (approximation): 44, 35, 34, 1
|
||||
|
||||
|
||||
### Frosty Blue
|
||||
HEX: #bcddfc
|
||||
RGB: 188, 221, 252
|
||||
CMYK: 23, 5, 0, 0
|
||||
|
||||
|
||||
### Electric Tangerine
|
||||
HEX: #ff825c
|
||||
RGB: 255, 130, 92
|
||||
CMYK: 0, 61, 64, 0
|
||||
|
||||
|
||||
### Holo Lilac
|
||||
HEX: #c5d2fe
|
||||
RGB: 197, 210, 254
|
||||
CMYK: 22, 17, 0, 0
|
||||
|
||||
|
||||
### Poppy Sunset
|
||||
HEX: #ee645b
|
||||
RGB: 238, 100, 91
|
||||
CMYK: 2, 76, 62, 0
|
||||
|
||||
|
||||
### Lime Nouveau
|
||||
HEX: #cddf8b
|
||||
RGB: 205, 223, 139
|
||||
CMYK: 22, 1, 58, 5
|
||||
|
||||
|
||||
### Very Peri
|
||||
HEX: #6667ab
|
||||
RGB: 102, 103, 171
|
||||
CMYK (approximation): 40, 40, 0, 33
|
||||
|
||||
|
||||
### Classic Blue
|
||||
HEX: #0f4c81
|
||||
RGB: 15, 76, 129
|
||||
CMYK (approximation): 99, 76, 24, 8
|
@ -39,8 +39,8 @@ REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1125
|
||||
MAIL_HOST=mailpit
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
@ -74,8 +74,14 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_HOST=
|
||||
PUSHER_PORT=443
|
||||
PUSHER_SCHEME=https
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
VITE_SSL_KEY_FILE_PATH="/code/docker/configs/nginx/ssls/${APP_DOMAIN}/${APP_DOMAIN}.key"
|
||||
VITE_SSL_CERT_FILE_PATH="/code/docker/configs/nginx/ssls/${APP_DOMAIN}/${APP_DOMAIN}.crt"
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
MIX_PUSHER_HOST="${PUSHER_HOST}"
|
||||
|
@ -1,17 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PSR2" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/src/Standards/PSR2/ruleset.xml">
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PSR2" xsi:noNamespaceSchemaLocation="vendor/slevomat/coding-standard">
|
||||
<description>PHP Codesniffer ruleset for this project</description>
|
||||
|
||||
<file>./app/Models</file>
|
||||
<file>./config</file>
|
||||
<file>./database</file>
|
||||
<file>./helpers</file>
|
||||
<file>./lang</file>
|
||||
<file>./resources/views</file>
|
||||
<file>./routes</file>
|
||||
|
||||
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="parallel" value="4"/>
|
||||
<arg name="report" value="full"/>
|
||||
@ -24,6 +14,16 @@
|
||||
|
||||
<autoload>./vendor/autoload.php</autoload>
|
||||
|
||||
<file>./app/Models</file>
|
||||
<file>./config</file>
|
||||
<file>./database</file>
|
||||
<file>./helpers</file>
|
||||
<file>./lang</file>
|
||||
<file>./resources/views</file>
|
||||
<file>./routes</file>
|
||||
|
||||
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||
|
||||
<!-- Don't hide tokenizer exceptions -->
|
||||
<rule ref="Internal.Tokenizer.Exception">
|
||||
<type>error</type>
|
||||
|
6
src/.well-known/security.txt
Normal file
6
src/.well-known/security.txt
Normal file
@ -0,0 +1,6 @@
|
||||
Contact: mailto:person@domain.com
|
||||
Contact: https://twitter.com/person
|
||||
Expires: 2024-09-14T14:00:00.000Z
|
||||
Encryption: https://keybase.io/person
|
||||
Encryption: https://domain.com/pgp-key.txt
|
||||
Preferred-Languages: en
|
30
src/SECURITY.md
Normal file
30
src/SECURITY.md
Normal file
@ -0,0 +1,30 @@
|
||||
<!-- AUTO-GENERATED, DO NOT EDIT! -->
|
||||
<!-- Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/SECURITY.md -->
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Security Policy](#security-policy)
|
||||
- [Supported Versions](#supported-versions)
|
||||
- [Reporting a Vulnerability](#reporting-a-vulnerability)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We release patches for security vulnerabilities. Which versions are eligible for
|
||||
receiving such patches depends on the CVSS v3.0 Rating:
|
||||
|
||||
| CVSS v3.0 | Supported Versions |
|
||||
| --------- | ----------------------------------------- |
|
||||
| 9.0-10.0 | Releases within the previous three months |
|
||||
| 4.0-8.9 | Most recent release |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report (suspected) security vulnerabilities to
|
||||
**[security@ory.sh](mailto:security@ory.sh)**. You will receive a response from
|
||||
us within 48 hours. If the issue is confirmed, we will release a patch as soon
|
||||
as possible depending on complexity but historically within a few days.
|
28
src/app/Actions/Chained/GenerateProfilePhoto.php
Normal file
28
src/app/Actions/Chained/GenerateProfilePhoto.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Chained;
|
||||
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
|
||||
class GenerateProfilePhoto
|
||||
{
|
||||
/**
|
||||
* Generates a profile photo for a user and saves it
|
||||
* to disk.
|
||||
*
|
||||
* @package App\Actions\Chained\GenerateProfilePhoto
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return \App\Models\User
|
||||
*/
|
||||
public function __invoke(User $user, Closure $next): User
|
||||
{
|
||||
//
|
||||
|
||||
return $next($user);
|
||||
}
|
||||
}
|
@ -2,21 +2,14 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Inertia\Response;
|
||||
use Jenssegers\Agent\Agent;
|
||||
use Laravel\Fortify\Features;
|
||||
use Laravel\Jetstream\Http\Controllers\Inertia\Concerns\ConfirmsTwoFactorAuthentication;
|
||||
use Laravel\Jetstream\Http\Controllers\Inertia\UserProfileController as JetstreamUserProfileController;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
class UserProfileController extends Controller
|
||||
class UserProfileController extends JetstreamUserProfileController
|
||||
{
|
||||
use ConfirmsTwoFactorAuthentication;
|
||||
|
||||
/**
|
||||
* Show the general profile settings screen.
|
||||
*
|
||||
@ -36,56 +29,4 @@ class UserProfileController extends Controller
|
||||
'timezones' => timezone_identifiers_list(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current sessions.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function sessions(Request $request): Collection
|
||||
{
|
||||
if (config('session.driver') !== 'database') {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return collect(
|
||||
DB::connection(config('session.connection'))->table(config('session.table', 'sessions'))
|
||||
->where('user_id', $request->user()->getAuthIdentifier())
|
||||
->orderBy('last_activity', 'desc')
|
||||
->get()
|
||||
)->map(function ($session) use ($request) {
|
||||
$agent = $this->createAgent($session);
|
||||
|
||||
return (object) [
|
||||
'agent' => [
|
||||
'is_desktop' => $agent->isDesktop(),
|
||||
'platform' => $agent->platform(),
|
||||
'browser' => $agent->browser(),
|
||||
],
|
||||
'ip_address' => $session->ip_address,
|
||||
'is_current_device' => $session->id === $request->session()->getId(),
|
||||
'last_active' => Carbon::createFromTimestamp($session->last_activity)->diffForHumans(),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new agent instance from the given session.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed $session
|
||||
*
|
||||
* @return \Jenssegers\Agent\Agent
|
||||
*/
|
||||
protected function createAgent($session): Agent
|
||||
{
|
||||
return tap(new Agent, function ($agent) use ($session) {
|
||||
$agent->setUserAgent($session->user_agent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,54 +2,50 @@
|
||||
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
trait FormattedPhoneTrait
|
||||
{
|
||||
/**
|
||||
* Format a phone number to be human readable.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPhoneNumberAttribute(): string
|
||||
{
|
||||
$phoneLength = strlen($this->phone);
|
||||
$phoneNumber = preg_replace('//', '', $this->phone);
|
||||
|
||||
if ($phoneLength > 10) {
|
||||
$countryCode = substr($phoneNumber, 0, $phoneLength - 10);
|
||||
$areaCode = substr($phoneNumber, -10, 3);
|
||||
$nextThree = substr($phoneNumber, -7, 3);
|
||||
$lastFour = substr($phoneNumber, -4, 4);
|
||||
|
||||
$phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}";
|
||||
} elseif ($phoneLength == 10) {
|
||||
$areaCode = substr($phoneNumber, 0, 3);
|
||||
$nextThree = substr($phoneNumber, 3, 3);
|
||||
$lastFour = substr($phoneNumber, 6, 4);
|
||||
|
||||
$phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}";
|
||||
} elseif ($phoneLength == 7) {
|
||||
$nextThree = substr($phoneNumber, 0, 3);
|
||||
$lastFour = substr($phoneNumber, 3, 4);
|
||||
|
||||
$phoneNumber = "{$nextThree}-{$lastFour}";
|
||||
}
|
||||
|
||||
return $phoneNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all non-numeric characters from the phone number.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $value
|
||||
* @package Namespace\App\Contact
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPhoneNumberAttribute($value): void
|
||||
protected function phoneNumber(): Attribute
|
||||
{
|
||||
$this->attributes['phone'] = preg_replace('/[^0-9]/', '', $value);
|
||||
return Attribute::make(
|
||||
get: function (mixed $value, array $attributes) {
|
||||
$phoneLength = strlen($attributes['phone_number']);
|
||||
$phoneNumber = preg_replace('/[^0-9]/', '', $attributes['phone_number']);
|
||||
|
||||
if ($phoneLength > 10) {
|
||||
$countryCode = substr($phoneNumber, 0, $phoneLength - 10);
|
||||
$areaCode = substr($phoneNumber, -10, 3);
|
||||
$nextThree = substr($phoneNumber, -7, 3);
|
||||
$lastFour = substr($phoneNumber, -4, 4);
|
||||
|
||||
$phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}";
|
||||
} elseif ($phoneLength == 10) {
|
||||
$areaCode = substr($phoneNumber, 0, 3);
|
||||
$nextThree = substr($phoneNumber, 3, 3);
|
||||
$lastFour = substr($phoneNumber, 6, 4);
|
||||
|
||||
$phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}";
|
||||
} elseif ($phoneLength == 7) {
|
||||
$nextThree = substr($phoneNumber, 0, 3);
|
||||
$lastFour = substr($phoneNumber, 3, 4);
|
||||
|
||||
$phoneNumber = "{$nextThree}-{$lastFour}";
|
||||
}
|
||||
|
||||
return $phoneNumber;
|
||||
},
|
||||
set: function (mixed $value) {
|
||||
return preg_replace('/[^0-9]/', '', $value);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
88
src/app/Models/Traits/HasProfilePhoto.php
Normal file
88
src/app/Models/Traits/HasProfilePhoto.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Jetstream;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
trait HasProfilePhoto
|
||||
{
|
||||
/**
|
||||
* Update the user's profile photo.
|
||||
*
|
||||
* @param \Illuminate\Http\UploadedFile $photo
|
||||
* @param string $storagePath
|
||||
* @return void
|
||||
*/
|
||||
public function updateProfilePhoto(UploadedFile $photo, $storagePath = 'profile-photos')
|
||||
{
|
||||
tap($this->profile_photo_path, function ($previous) use ($photo, $storagePath) {
|
||||
$this->forceFill([
|
||||
'profile_photo_path' => $photo->storePublicly(
|
||||
$storagePath, ['disk' => $this->profilePhotoDisk()]
|
||||
),
|
||||
])->save();
|
||||
|
||||
if ($previous) {
|
||||
Storage::disk($this->profilePhotoDisk())->delete($previous);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user's profile photo.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteProfilePhoto()
|
||||
{
|
||||
if (! Features::managesProfilePhotos()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($this->profile_photo_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Storage::disk($this->profilePhotoDisk())->delete($this->profile_photo_path);
|
||||
|
||||
$this->forceFill([
|
||||
'profile_photo_path' => null,
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to the user's profile photo.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||
*/
|
||||
public function profilePhotoUrl(): Attribute
|
||||
{
|
||||
return Attribute::get(function () {
|
||||
return $this->profile_photo_path
|
||||
? Storage::disk($this->profilePhotoDisk())->url($this->profile_photo_path)
|
||||
: $this->defaultProfilePhotoUrl();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default profile photo URL if no profile photo has been uploaded.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function defaultProfilePhotoUrl()
|
||||
{
|
||||
return 'https://avatars.test/avatar?size=256';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the disk that profile photos should be stored on.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function profilePhotoDisk()
|
||||
{
|
||||
return isset($_ENV['VAPOR_ARTIFACT_NAME']) ? 's3' : config('jetstream.profile_photo_disk', 'public');
|
||||
}
|
||||
}
|
@ -17,6 +17,9 @@
|
||||
"spatie/laravel-permission": "",
|
||||
"zizaco/entrust": "",
|
||||
|
||||
// Security stuff
|
||||
"abuseipdb/laravel": "", // API to check an IP for abusive behavior with option to report IP for abusive behavior
|
||||
|
||||
// Options/Flags
|
||||
"spatie/laravel-model-flags": "", // add a simple true/false flag to any model
|
||||
|
||||
@ -30,6 +33,9 @@
|
||||
"torann/geoip": "", // support for multiple GeoIP services
|
||||
"coderjerk/nasa-php": "", // NASA API integrations
|
||||
|
||||
// File management
|
||||
"czim/laravel-paperclip": "", // attach files to an Eloquent model
|
||||
|
||||
// Media (image/video/audio) Management
|
||||
"intervention/image": "", // image manipulation
|
||||
"intervention/imagecache": "", // caching for intervention/image
|
||||
@ -37,6 +43,7 @@
|
||||
"spatie/laravel-image-optimizer": "", // optimize png, jpg, svg, and gif
|
||||
"unisharp/laravel-filemanager": "", // File manager (including uploads)
|
||||
"pbmedia/laravel-ffmpeg": "", // Integration with FFMpeg
|
||||
"maestroerror/php-heic-to-jpg": "", // Use Go(?) to convert HEIC/HEIF to JPEG
|
||||
|
||||
// Localization
|
||||
"mcamara/laravel-localization": "", // localization that also handles route translations
|
||||
@ -69,6 +76,7 @@
|
||||
"protonemedia/laravel-verify-new-email": "", // must verify new email address before email update will be completed
|
||||
"protonemedia/inertiajs-tables-laravel-query-builder": "", // datatables for InertiaJS/Vue and Laravel
|
||||
|
||||
"ikechukwukalu/requirepin": "", // use password/pin protection for routes
|
||||
|
||||
"doctrine/dbal": "", // useful for artisan db:show
|
||||
},
|
||||
|
@ -6,6 +6,7 @@ use App\Models\Language;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Jetstream\Features;
|
||||
|
||||
@ -71,4 +72,25 @@ class UserFactory extends Factory
|
||||
'ownedTeams'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user should have an avatar image.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withAvatar()
|
||||
{
|
||||
if (! Features::enabled(Features::profilePhotos())) {
|
||||
return $this->state([]);
|
||||
}
|
||||
|
||||
$imageUrl = 'https://avatars.test/';
|
||||
$imageContents = file_get_contents($imageUrl);
|
||||
$imageName = md5($imageContents) . '.jpg';
|
||||
Storage::put("public/avatars/{$imageName}", $imageContents);
|
||||
|
||||
return $this->state([
|
||||
'profile_photo_path' => "avatars/{$imageName}"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ $httpCodes = [
|
||||
204 => 'HTTP_NO_CONTENT',
|
||||
205 => 'HTTP_RESET_CONTENT',
|
||||
206 => 'HTTP_PARTIAL_CONTENT',
|
||||
218 => 'HTTP_THIS_IS_FINE', // Apache specific
|
||||
|
||||
// 300's (redirections / "go away")
|
||||
300 => 'HTTP_MULTIPLE_CHOICE',
|
||||
@ -57,12 +58,14 @@ $httpCodes = [
|
||||
236 => 'HTTP_UPGRADE_REQUIRED',
|
||||
428 => 'HTTP_PRECONDITION_REQUIRED',
|
||||
429 => 'HTTP_TOO_MANY_REQUESTS',
|
||||
444 => 'HTTP_NO_RESPONSE', // Nginx specific, used internally to return no info and close connection immediately
|
||||
451 => 'HTTP_GAG_ORDER',
|
||||
|
||||
// 500's (server-level problem, process died or configuration is incorrect / "server screwed up")
|
||||
500 => 'HTTP_SERVER_ERROR',
|
||||
501 => 'HTTP_NOT_IMPLEMENTED',
|
||||
503 => 'HTTP_UNAVAILABLE',
|
||||
529 => 'HTTP_SITE_OVERLOADED', // Qualys specific, API response to indicate server resources are over capacity
|
||||
530 => 'HTTP_SUSPENDED',
|
||||
];
|
||||
|
||||
|
@ -15,6 +15,47 @@ require_once "functions/temperatures.php";
|
||||
|
|
||||
*/
|
||||
|
||||
if (! function_exists('clamp')) {
|
||||
/**
|
||||
* Ensure a numerical value is between two bounds.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int|float|string $number The value to be clamped between two other values.
|
||||
* @param int|float|string $minNumber The miminum value for clamping bounds.
|
||||
* @param int|float|string $maxNumber The maximum value for clamping bounds.
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
function clamp($number, $minNumber, $maxNumber)
|
||||
{
|
||||
if (! is_numeric($number)) {
|
||||
throw new Exception('Clamp number must be numeric in value.');
|
||||
}
|
||||
|
||||
if (! is_numeric($minNumber)) {
|
||||
throw new Exception('Clamped minimum number must be numeric in value.');
|
||||
}
|
||||
|
||||
if (! is_numeric($maxNumber)) {
|
||||
throw new Exception('Clamped maximum number must be numeric in value.');
|
||||
}
|
||||
|
||||
$returnValue = $number;
|
||||
if ($minNumber >= $number) {
|
||||
$returnValue = $minNumber;
|
||||
}
|
||||
|
||||
if ($maxNumber <= $number) {
|
||||
$returnValue = $maxNumber;
|
||||
}
|
||||
|
||||
return $returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('humanBytes')) {
|
||||
/**
|
||||
* Convert bytes to a human-friendly format.
|
||||
@ -195,7 +236,7 @@ if (! function_exists('maybe_unserialize')) {
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return mixed
|
||||
* @return array|string|bool
|
||||
*/
|
||||
function maybe_unserialize($data)
|
||||
{
|
||||
|
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Bold.woff2
Normal file
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Bold.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Italic.woff2
Normal file
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Italic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Medium.woff2
Normal file
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Medium.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Regular.woff2
Normal file
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-Regular.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-SemiBold.woff2
Normal file
BIN
src/public/fonts/BarlowCondensed/BarlowCondensed-SemiBold.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-Bold.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-Bold.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-BoldItalic.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-Italic.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-Italic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-Medium.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-Medium.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-MediumItalic.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-Regular.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-Regular.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-SemiBold.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-SemiBold.woff2
Normal file
Binary file not shown.
BIN
src/public/fonts/Montserrat/Montserrat-SemiBoldItalic.woff2
Normal file
BIN
src/public/fonts/Montserrat/Montserrat-SemiBoldItalic.woff2
Normal file
Binary file not shown.
30
src/resources/css/animations/ripple.css
Normal file
30
src/resources/css/animations/ripple.css
Normal file
@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--ripple-color: #fff;
|
||||
--ripple-radius: 9999px;
|
||||
--ripple-duration: 600ms;
|
||||
--ripple-timing-function: linear;
|
||||
}
|
||||
|
||||
.ripple {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ripple span {
|
||||
position: absolute;
|
||||
border-radius: var(--ripple-radius);
|
||||
opacity: 0.5;
|
||||
background: var(--ripple-color);
|
||||
transform: scale(0);
|
||||
animation: ripple var(--ripple-duration) var(--ripple-timing-function);
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
@ -26,10 +26,54 @@
|
||||
@import 'components/navbars.css';
|
||||
@import 'components/pagination.css';
|
||||
|
||||
:root {
|
||||
--primary-text-color: hsl(0, 90.4%, 59.2%);
|
||||
--primary-text-color-gradient-start: hsl(270, 66.9%, 47.5%);
|
||||
--primary-text-color-gradient-end: hsl(330, 100%, 50%);
|
||||
|
||||
--text-info-color: hsl(191, 82%, 50%);
|
||||
--text-info-color-gradient-start: hsl(227, 100%, 56.5%);
|
||||
--text-info-color-gradient-end: hsl(191, 98.2%, 56.1%);
|
||||
|
||||
--text-success-color: hsl(86, 81.4%, 46.3%);
|
||||
--text-success-color-gradient-start: hsl(133, 76.5%, 38.4%);
|
||||
--text-success-color-gradient-end: hsl(72, 81.1%, 52.4%);
|
||||
|
||||
--text-warning-color: hsl(47, 96.2%, 59.2%);
|
||||
--text-warning-color-gradient-start: hsl(0, 90.4%, 59.2%);
|
||||
--text-warning-color-gradient-end: hsl(47, 96.2%, 59.2%);
|
||||
|
||||
--text-danger-color: hsl(0, 95%, 47.1%);
|
||||
--text-danger-color-gradient-start: hsl(0, 92.8%, 43.5%);
|
||||
--text-danger-color-gradient-end: hsl(344, 100%, 70%);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0s !important;
|
||||
/* additional recommendation */
|
||||
transition: none !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
background-image: linear-gradient(100deg, hsl(0, 0%, 98%), hsl(240, 5.9%, 90%));
|
||||
color: hsl(240, 5.9%, 10%);
|
||||
/*color: lch(8.35%, 2.25, 285.92);*/
|
||||
-webkit-font-smoothing: antialiased;
|
||||
min-height: 100dvh;
|
||||
overflow: auto;
|
||||
scrollbar-gutter: stable both-edges;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.1;
|
||||
|
||||
/* these will clamp the width between the two values
|
||||
and keep it at 90% of the max when between them */
|
||||
max-width: clamp(320px, 90%, 1280px);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@ -46,6 +90,16 @@ nav {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
font-style: italic;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
shape-margin: 0.75rem;
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
.grid-container {
|
||||
@apply grid-cols-1;
|
||||
|
106
src/resources/css/elements/glossy-buttons.css
Normal file
106
src/resources/css/elements/glossy-buttons.css
Normal file
@ -0,0 +1,106 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: 4em 1em;
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
--h: 196;
|
||||
--s: 100%;
|
||||
--l: 41%;
|
||||
}
|
||||
.secondary-button {
|
||||
--h: 28;
|
||||
--s: 100%;
|
||||
--l: 41%;
|
||||
}
|
||||
|
||||
.glass-button {
|
||||
font-size: clamp(1.2rem, 5vw + 1rem, 2.5rem);
|
||||
width: 10em;
|
||||
height: 4em;
|
||||
border-radius: 0.5em;
|
||||
background-image: linear-gradient(#0003,#0000);
|
||||
box-shadow:
|
||||
0 -0.125em 0.25em #0002,
|
||||
0 0.25em 0.25em hsl(var(--h) var(--s) var(--l) / 0.5),
|
||||
0 0 0 0.1em hsl(var(--h) var(--s) var(--l) / 0.5),
|
||||
0 0.175em 0.3em hsl(var(--h) var(--s) var(--l) / 0.5) inset,
|
||||
0 -0.025em 0.175em hsl(var(--h) var(--s) var(--l) / 0.4) inset,
|
||||
0 -0.25em 1em 0.3em hsl(var(--h) var(--s) var(--l) / 0.3) inset,
|
||||
0 0.6em 0 hsl(var(--h) var(--s) var(--l) / 0.3) inset,
|
||||
0 2em 1em #0004;
|
||||
backdrop-filter: blur(0.15em);
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
color: hsl(var(--h) var(--s) var(--l) / .7);
|
||||
text-shadow:
|
||||
0.03em 0.03em #fff5,
|
||||
-0.03em -0.03em #0005;
|
||||
cursor: pointer;
|
||||
transition: 0.1s ease;
|
||||
padding-top: 0.2em;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.glass-button:before {
|
||||
content: '';
|
||||
height: 1.5em;
|
||||
left: 10%;
|
||||
top: 100%;
|
||||
position: absolute;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.glass-button:after {
|
||||
content: '';
|
||||
inset: 0;
|
||||
top: 0.5em;
|
||||
position: absolute;
|
||||
background-image:
|
||||
linear-gradient(
|
||||
105deg,
|
||||
transparent 20%,
|
||||
hsl(var(--h) var(--s) var(--l) / .2) 20%,
|
||||
hsl(var(--h) var(--s) var(--l) / .2) 30%,
|
||||
transparent 30%,
|
||||
transparent 32%,
|
||||
hsl(var(--h) var(--s) var(--l) / .2) 5%,
|
||||
hsl(var(--h) var(--s) var(--l) / .2) 40%,
|
||||
transparent 0%
|
||||
);
|
||||
background-size: 400% 100%;
|
||||
background-position: 100% 0%;
|
||||
transition: .3s ease;
|
||||
}
|
||||
|
||||
.glass-button:active:after {
|
||||
background-position: -50% 0%;
|
||||
}
|
||||
|
||||
.glass-button:active {
|
||||
backdrop-filter: blur(0.08em);
|
||||
box-shadow:
|
||||
0 -0.125em 0.25em #0002,
|
||||
0 0.25em 0.25em hsl(var(--h) var(--s) var(--l) / 0.5),
|
||||
0 0 0 0.1em hsl(var(--h) var(--s) var(--l) / 0.5),
|
||||
0 0.175em 0.3em hsl(var(--h) var(--s) var(--l) / 0.8) inset,
|
||||
0 -0.025em 0.175em hsl(var(--h) var(--s) var(--l) / 0.4) inset,
|
||||
0 -0.25em 1em 0.3em hsl(var(--h) var(--s) var(--l) / 0.3) inset,
|
||||
0 0.6em 0 hsl(var(--h) var(--s) var(--l) / 0.3) inset,
|
||||
0 1em 0.5em #0004;
|
||||
translate: .01em .25em;
|
||||
}
|
||||
|
||||
.glass-button:active:before {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
/*body {
|
||||
background-color: #3d3d3d;
|
||||
display: grid;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
place-content: center;
|
||||
}*/
|
74
src/resources/css/resets/andy-bell.reset.css
Normal file
74
src/resources/css/resets/andy-bell.reset.css
Normal file
@ -0,0 +1,74 @@
|
||||
/* Box sizing rules */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Remove default margin */
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
p,
|
||||
figure,
|
||||
blockquote,
|
||||
dl,
|
||||
dd {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
|
||||
ul[role='list'],
|
||||
ol[role='list'] {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* Set core root defaults */
|
||||
html:focus-within {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Set core body defaults */
|
||||
body {
|
||||
min-height: 100vh;
|
||||
text-rendering: optimizeSpeed;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* A elements that don't have a class get default styles */
|
||||
a:not([class]) {
|
||||
text-decoration-skip-ink: auto;
|
||||
}
|
||||
|
||||
/* Make images easier to work with */
|
||||
img,
|
||||
picture {
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Inherit fonts for inputs and buttons */
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html:focus-within {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
48
src/resources/css/resets/eric-meyer.reset.css
Normal file
48
src/resources/css/resets/eric-meyer.reset.css
Normal file
@ -0,0 +1,48 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
349
src/resources/css/resets/nicolas-allagher.normalize.css
Normal file
349
src/resources/css/resets/nicolas-allagher.normalize.css
Normal file
@ -0,0 +1,349 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers.
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10.
|
||||
* 2. Remove the padding in IE 10.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Misc
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10+.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
@ -3,6 +3,70 @@
|
||||
/** +--------------------------------+ **/
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-Medium.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-MediumItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-SemiBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-SemiBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-Bold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "BarlowCondensed";
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/BarlowCondensed/BarlowCondensed-BoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/*@font-face {
|
||||
font-family: "Lato";
|
||||
src: url('/fonts/Lato/Lato-Regular.woff2') format("woff2");
|
||||
font-weight: 400;
|
||||
@ -48,13 +112,77 @@
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
}*/
|
||||
|
||||
/** +--------------------------------+ **/
|
||||
/** | Serif fonts | **/
|
||||
/** +--------------------------------+ **/
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-Medium.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-MediumItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-SemiBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-SemiBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-Bold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Montserrat/Montserrat-BoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/*@font-face {
|
||||
font-family: "Nunito";
|
||||
src: url('/fonts/Nunito/Nunito-Regular.woff2') format("woff2");
|
||||
font-weight: 400;
|
||||
@ -118,7 +246,7 @@
|
||||
font-stretch: 75% 125%;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*@font-face {
|
||||
font-family: "Raleway";
|
||||
|
45
src/resources/css/typography/text-gradient.css
Normal file
45
src/resources/css/typography/text-gradient.css
Normal file
@ -0,0 +1,45 @@
|
||||
.text-gradient {
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.text-gradient.text-primary {
|
||||
background-image: linear-gradient(310deg, var(--primary-text-color-gradient-start), var(--primary-text-color-gradient-end));
|
||||
}
|
||||
.text-primary {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.text-gradient.text-info {
|
||||
background-image: linear-gradient(310deg, var(--text-info-color-gradient-start), var(--text-info-color-gradient-end));
|
||||
}
|
||||
.text-info {
|
||||
color: var(--text-info-color);
|
||||
}
|
||||
|
||||
.text-gradient.text-success {
|
||||
background-image: linear-gradient(310deg, var(--text-success-color-gradient-start), var(--text-success-color-gradient-end));
|
||||
color: hsl(86, 81.4%, 46.3%);
|
||||
}
|
||||
.text-success {
|
||||
color: var(--text-success-color);
|
||||
}
|
||||
|
||||
.text-gradient.text-warning {
|
||||
background-image: linear-gradient(310deg, var(--text-warning-color-gradient-start), var(--text-warning-color-gradient-end));
|
||||
color: hsl(47, 96.2%, 59.2%);
|
||||
}
|
||||
.text-warning {
|
||||
color: var(--text-warning-color);
|
||||
}
|
||||
|
||||
.text-gradient.text-danger {
|
||||
background-image: linear-gradient(310deg, var(--text-danger-color-gradient-start), var(--text-danger-color-gradient-end));
|
||||
color: hsl(0, 95%, 47.1%);
|
||||
}
|
||||
.text-danger {
|
||||
color: var(--text-danger-color);
|
||||
}
|
@ -1,3 +1,30 @@
|
||||
.button-row {
|
||||
@apply inline-grid grid-flow-col auto-cols-max items-center; /* intentionally leaving gap out so that it can be set on per-case basis */
|
||||
}
|
||||
|
||||
.gradBorder i {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
inset: 0;
|
||||
border-radius: 30px;
|
||||
padding: 1.5px; /* the thickness of the border */
|
||||
/* the below will do the magic */
|
||||
mask:
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
/* this will cover only the content area (no padding) */
|
||||
linear-gradient(#fff 0 0); /* this will cover all the area */
|
||||
-webkit-mask-composite: xor; /* needed for old browsers until the below is more supported */
|
||||
mask-composite: exclude; /* this will exclude the first layer from the second so only the padding area will be kept visible */
|
||||
}
|
||||
|
||||
.gradBorder i::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, #ffffff73 0%, #ffffff10 50%);
|
||||
transition: transform 0.7s linear;
|
||||
}
|
||||
|
@ -1,3 +1,108 @@
|
||||
:root {
|
||||
/**/
|
||||
|
||||
/** ------------------------------
|
||||
* START -- https://coolors.co/022f40-38aecc-0090c1-183446-046e8f
|
||||
* -------------------------------**/
|
||||
/* CSS HEX */
|
||||
--prussian-blue: #022f40ff;
|
||||
--pacific-cyan: #38aeccff;
|
||||
--blue-ncs: #0090c1ff;
|
||||
--prussian-blue-2: #183446ff;
|
||||
--cerulean: #046e8fff;
|
||||
|
||||
/* CSS HSL */
|
||||
--prussian-blue: hsla(196, 94%, 13%, 1);
|
||||
--pacific-cyan: hsla(192, 59%, 51%, 1);
|
||||
--blue-ncs: hsla(195, 100%, 38%, 1);
|
||||
--prussian-blue-2: hsla(203, 49%, 18%, 1);
|
||||
--cerulean: hsla(194, 95%, 29%, 1);
|
||||
|
||||
/* SCSS HEX */
|
||||
$prussian-blue: #022f40ff;
|
||||
$pacific-cyan: #38aeccff;
|
||||
$blue-ncs: #0090c1ff;
|
||||
$prussian-blue-2: #183446ff;
|
||||
$cerulean: #046e8fff;
|
||||
|
||||
/* SCSS HSL */
|
||||
$prussian-blue: hsla(196, 94%, 13%, 1);
|
||||
$pacific-cyan: hsla(192, 59%, 51%, 1);
|
||||
$blue-ncs: hsla(195, 100%, 38%, 1);
|
||||
$prussian-blue-2: hsla(203, 49%, 18%, 1);
|
||||
$cerulean: hsla(194, 95%, 29%, 1);
|
||||
|
||||
/* SCSS RGB */
|
||||
$prussian-blue: rgba(2, 47, 64, 1);
|
||||
$pacific-cyan: rgba(56, 174, 204, 1);
|
||||
$blue-ncs: rgba(0, 144, 193, 1);
|
||||
$prussian-blue-2: rgba(24, 52, 70, 1);
|
||||
$cerulean: rgba(4, 110, 143, 1);
|
||||
|
||||
/* SCSS Gradient */
|
||||
/*$gradient-top: linear-gradient(0deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-right: linear-gradient(90deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-bottom: linear-gradient(180deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-left: linear-gradient(270deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-top-right: linear-gradient(45deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-bottom-right: linear-gradient(135deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-top-left: linear-gradient(225deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-bottom-left: linear-gradient(315deg, #022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/*$gradient-radial: radial-gradient(#022f40ff, #38aeccff, #0090c1ff, #183446ff, #046e8fff);*/
|
||||
/** ------------------------------
|
||||
* END -- https://coolors.co/022f40-38aecc-0090c1-183446-046e8f
|
||||
* -------------------------------**/
|
||||
|
||||
|
||||
/** ------------------------------
|
||||
* START -- https://coolors.co/8ac482-47783f-ffbe86-ffb5c2-3777ff
|
||||
* -------------------------------**/
|
||||
/* CSS HEX */
|
||||
--pistachio: #8ac482ff;
|
||||
--fern-green: #47783fff;
|
||||
--peach: #ffbe86ff;
|
||||
--cherry-blossom-pink: #ffb5c2ff;
|
||||
--blue-crayola: #3777ffff;
|
||||
|
||||
/* CSS HSL */
|
||||
--pistachio: hsla(113, 36%, 64%, 1);
|
||||
--fern-green: hsla(112, 31%, 36%, 1);
|
||||
--peach: hsla(28, 100%, 76%, 1);
|
||||
--cherry-blossom-pink: hsla(349, 100%, 85%, 1);
|
||||
--blue-crayola: hsla(221, 100%, 61%, 1);
|
||||
|
||||
/* SCSS HEX */
|
||||
$pistachio: #8ac482ff;
|
||||
$fern-green: #47783fff;
|
||||
$peach: #ffbe86ff;
|
||||
$cherry-blossom-pink: #ffb5c2ff;
|
||||
$blue-crayola: #3777ffff;
|
||||
|
||||
/* SCSS HSL */
|
||||
$pistachio: hsla(113, 36%, 64%, 1);
|
||||
$fern-green: hsla(112, 31%, 36%, 1);
|
||||
$peach: hsla(28, 100%, 76%, 1);
|
||||
$cherry-blossom-pink: hsla(349, 100%, 85%, 1);
|
||||
$blue-crayola: hsla(221, 100%, 61%, 1);
|
||||
|
||||
/* SCSS RGB */
|
||||
$pistachio: rgba(138, 196, 130, 1);
|
||||
$fern-green: rgba(71, 120, 63, 1);
|
||||
$peach: rgba(255, 190, 134, 1);
|
||||
$cherry-blossom-pink: rgba(255, 181, 194, 1);
|
||||
$blue-crayola: rgba(55, 119, 255, 1);
|
||||
|
||||
/* SCSS Gradient */
|
||||
/*$gradient-top: linear-gradient(0deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-right: linear-gradient(90deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-bottom: linear-gradient(180deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-left: linear-gradient(270deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-top-right: linear-gradient(45deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-bottom-right: linear-gradient(135deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-top-left: linear-gradient(225deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-bottom-left: linear-gradient(315deg, #8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/*$gradient-radial: radial-gradient(#8ac482ff, #47783fff, #ffbe86ff, #ffb5c2ff, #3777ffff);*/
|
||||
/** ------------------------------
|
||||
* END -- https://coolors.co/8ac482-47783f-ffbe86-ffb5c2-3777ff
|
||||
* -------------------------------**/
|
||||
|
||||
}
|
||||
|
96
src/resources/js/ripple.js
Normal file
96
src/resources/js/ripple.js
Normal file
@ -0,0 +1,96 @@
|
||||
import { getCustomColorFromModifiers, getCustomRadiusFromModifiers, willHaveAMouseUpEvent, toStyles } from './utils';
|
||||
|
||||
let rippleClass = 'ripple';
|
||||
let removeTimeout = 1000;
|
||||
|
||||
/**
|
||||
* Add a ripple effect to the element.
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
* @param {HTMLElement} el
|
||||
* @param {Array} modifiers
|
||||
*/
|
||||
export const addRipple = (event, el, modifiers) => {
|
||||
if (! willHaveAMouseUpEvent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ripple = document.createElement('span');
|
||||
rippleClass.split(' ').forEach(className => ripple.classList.add(className));
|
||||
|
||||
el.appendChild(ripple);
|
||||
|
||||
const size = ripple.offsetWidth,
|
||||
position = ripple.getBoundingClientRect(),
|
||||
innerRipple = document.createElement('span');
|
||||
|
||||
const x = event.pageX - position.left - (size / 2),
|
||||
y = event.pageY - position.top - (size / 2);
|
||||
|
||||
const style = {
|
||||
top: `${y}px`,
|
||||
left: `${x}px`,
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
};
|
||||
|
||||
const color = getCustomColorFromModifiers(modifiers);
|
||||
if (color.indexOf('bg-') === 0) {
|
||||
// Prefix with '!' for !important (requires Tailwind).
|
||||
innerRipple.classList.add(`!${color}`);
|
||||
} else if (color.indexOf('#') === 0 || color.indexOf('rgb') === 0) {
|
||||
style['--ripple-color'] = color;
|
||||
}
|
||||
|
||||
const radius = getCustomRadiusFromModifiers(modifiers);
|
||||
if (radius) {
|
||||
style['--ripple-radius'] = radius;
|
||||
}
|
||||
|
||||
ripple.appendChild(innerRipple);
|
||||
innerRipple.setAttribute('style', toStyles(style));
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the ripple from the element.
|
||||
*
|
||||
* @param {HTMLElement} el
|
||||
*/
|
||||
export const removeRipple = el => {
|
||||
setTimeout(() => {
|
||||
// We are only removing the first instance to prevent ripples from subsequent clicks
|
||||
// being removed too quickly before the ripple effect can properly be seen.
|
||||
const ripple = el.querySelector(`.${rippleClass.replace(' ', '.')}`);
|
||||
|
||||
ripple && ripple.remove();
|
||||
}, removeTimeout);
|
||||
};
|
||||
|
||||
function Ripple(Alpine) {
|
||||
Alpine.directive('ripple', (el, { modifiers, expression }, { cleanup }) => {
|
||||
const clickHandler = event => addRipple(event, el, modifiers);
|
||||
const mouseUpHandler = () => removeRipple(el);
|
||||
|
||||
el.addEventListener('mousedown', clickHandler);
|
||||
el.addEventListener('mouseup', mouseUpHandler);
|
||||
|
||||
cleanup(() => {
|
||||
el.removeEventListener('mousedown', clickHandler);
|
||||
el.removeEventListener('mouseup', mouseUpHandler);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Ripple.configure = config => {
|
||||
if (config.hasOwnProperty('class') && typeof config.class === 'string') {
|
||||
rippleClass = config.class;
|
||||
}
|
||||
|
||||
if (config.hasOwnProperty('removeTimeout') && typeof config.removeTimeout === 'number') {
|
||||
removeTimeout = config.removeTimeout;
|
||||
}
|
||||
|
||||
return Ripple;
|
||||
};
|
||||
|
||||
export default Ripple;
|
67
src/resources/js/utils.js
Normal file
67
src/resources/js/utils.js
Normal file
@ -0,0 +1,67 @@
|
||||
export const getCustomColorFromModifiers = modifiers => {
|
||||
if (! modifiers.includes('color')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const nextModifier = modifiers[modifiers.indexOf('color') + 1] || 'invalid-color';
|
||||
if (nextModifier.indexOf('#') === 0 || nextModifier.indexOf('rgb') === 0) {
|
||||
return nextModifier;
|
||||
}
|
||||
|
||||
return nextModifier.indexOf('bg') === 0
|
||||
? nextModifier
|
||||
: `bg-${nextModifier}`;
|
||||
};
|
||||
|
||||
export const getCustomRadiusFromModifiers = modifiers => {
|
||||
if (! modifiers.includes('radius')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let nextModifier = modifiers[modifiers.indexOf('radius') + 1] || 'invalid-radius';
|
||||
|
||||
// _ allows us to use decimals, such as 0.5.
|
||||
nextModifier = nextModifier.replace('_', '.');
|
||||
|
||||
// Separate the numeric value from the unit in nextModifier.
|
||||
// Possible values for nextModifier: 50, 50.5, 50.5px, 50px, 50%, 50rem, 50em
|
||||
const numericValue = nextModifier.match(/^[0-9]+(\.[0-9]+)?/)[0];
|
||||
let unit = nextModifier.replace(numericValue, '');
|
||||
if (! unit) {
|
||||
unit = '%';
|
||||
}
|
||||
|
||||
return `${numericValue}${unit}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an object of style properties to a string of CSS.
|
||||
*
|
||||
* @param {Object} styles
|
||||
* @returns {string}
|
||||
*/
|
||||
export const toStyles = styles => Object.entries(styles).map(([key, value]) => `${formatStyleKey(key)}: ${value}`).join(';');
|
||||
|
||||
/**
|
||||
* Convert a style key to a CSS property.
|
||||
* Example: backgroundColor -> background-color
|
||||
*
|
||||
* @param {string} key
|
||||
* @returns {string}
|
||||
*/
|
||||
const formatStyleKey = key => key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
|
||||
/**
|
||||
* Some events, such as a right click or ctrl + left click won't trigger a mouseup event,
|
||||
* so we need to prevent the ripple from being added in those cases.
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const willHaveAMouseUpEvent = event => {
|
||||
if (event.ctrlKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return event.button === 0 || event.button === 1;
|
||||
};
|
@ -19,6 +19,14 @@ module.exports = {
|
||||
|
||||
extend: {
|
||||
colors: {
|
||||
'sherwin': {
|
||||
'marshmallow': '#eee9e0'
|
||||
'ice-cube': '#e3e4e1',
|
||||
'peppercorn': '#585858',
|
||||
'black-magic': '#323132',
|
||||
'tricorn-black': '#2f2f30',
|
||||
},
|
||||
|
||||
// use https://uicolors.app/create
|
||||
// neutals
|
||||
'nomad': {
|
||||
@ -35,6 +43,19 @@ module.exports = {
|
||||
},
|
||||
|
||||
// reds
|
||||
'crimson': {
|
||||
50: '#fff1f1',
|
||||
100: '#ffe0e0',
|
||||
200: '#ffc6c6',
|
||||
300: '#ff9e9e',
|
||||
400: '#ff6666',
|
||||
500: '#fd3636',
|
||||
600: '#eb1717',
|
||||
700: '#c60f0f',
|
||||
800: '#a31111',
|
||||
900: '#871515',
|
||||
},
|
||||
|
||||
'monza': {
|
||||
50: '#fff0f0',
|
||||
100: '#ffdede',
|
||||
@ -74,6 +95,19 @@ module.exports = {
|
||||
900: '#811a39',
|
||||
},
|
||||
|
||||
'violet-red': {
|
||||
50: '#fff1f3',
|
||||
100: '#ffe3e8',
|
||||
200: '#ffccd7',
|
||||
300: '#ffa2b6',
|
||||
400: '#ff6d8f',
|
||||
500: '#f94373',
|
||||
600: '#e61858',
|
||||
700: '#c20e4b',
|
||||
800: '#a30e45',
|
||||
900: '#8b1041',
|
||||
},
|
||||
|
||||
|
||||
// oranges
|
||||
'saffron-mango': {
|
||||
@ -102,8 +136,48 @@ module.exports = {
|
||||
900: '#7a250d',
|
||||
},
|
||||
|
||||
'hot-cinnamon': {
|
||||
50: '#fdf8ed',
|
||||
100: '#f9eacc',
|
||||
200: '#f3d394',
|
||||
300: '#edb75c',
|
||||
400: '#e89e37',
|
||||
500: '#e17e1f',
|
||||
600: '#d3631a',
|
||||
700: '#a54118',
|
||||
800: '#86341a',
|
||||
900: '#6f2c18',
|
||||
},
|
||||
|
||||
'fire-bush': {
|
||||
50: '#fef7ec',
|
||||
100: '#faeacb',
|
||||
200: '#f5d292',
|
||||
300: '#efb65a',
|
||||
400: '#ea9727',
|
||||
500: '#e47d1c',
|
||||
600: '#ca5b15',
|
||||
700: '#a74016',
|
||||
800: '#883218',
|
||||
900: '#702a17',
|
||||
},
|
||||
|
||||
|
||||
// yellows
|
||||
'vesuvius': {
|
||||
50: '#fffbeb',
|
||||
100: '#fef3c7',
|
||||
200: '#fde58a',
|
||||
300: '#fbd24e',
|
||||
400: '#fabe25',
|
||||
500: '#f49d0c',
|
||||
600: '#d87607',
|
||||
700: '#bc560a',
|
||||
800: '#923f0e',
|
||||
900: '#78340f',
|
||||
},
|
||||
|
||||
|
||||
'mango-tango': {
|
||||
50: '#fefbe8',
|
||||
100: '#fff6c2',
|
||||
@ -236,6 +310,19 @@ module.exports = {
|
||||
900: '#163e2f',
|
||||
},
|
||||
|
||||
'caribbean-green': {
|
||||
50: '#effef9',
|
||||
100: '#cafdef',
|
||||
200: '#94fbe0',
|
||||
300: '#57f1cf',
|
||||
400: '#24ddba',
|
||||
500: '#0ccaa9',
|
||||
600: '#069b84',
|
||||
700: '#0a7b6c',
|
||||
800: '#0d6257',
|
||||
900: '#105149',
|
||||
},
|
||||
|
||||
|
||||
// teals
|
||||
'aquamarine': {
|
||||
@ -357,6 +444,20 @@ module.exports = {
|
||||
900: '#193961',
|
||||
},
|
||||
|
||||
'azure-radiance': {
|
||||
50: '#edfaff',
|
||||
100: '#d6f2ff',
|
||||
200: '#b5eaff',
|
||||
300: '#83dfff',
|
||||
400: '#48cbff',
|
||||
500: '#1eacff',
|
||||
600: '#068eff',
|
||||
700: '#007aff',
|
||||
800: '#085dc5',
|
||||
900: '#0d519b',
|
||||
},
|
||||
|
||||
|
||||
// purples
|
||||
'lilac-bush': {
|
||||
50: '#f8f5fd',
|
||||
@ -397,6 +498,45 @@ module.exports = {
|
||||
900: '#4b05ad',
|
||||
},
|
||||
|
||||
'medium-purple': {
|
||||
50: '#f0f1fd',
|
||||
100: '#e3e5fc',
|
||||
200: '#cccdf9',
|
||||
300: '#adadf4',
|
||||
400: '#948ced',
|
||||
500: '#8170e4',
|
||||
600: '#7558d7',
|
||||
700: '#6346bc',
|
||||
800: '#503b98',
|
||||
900: '#443679',
|
||||
},
|
||||
|
||||
'wisteria': {
|
||||
50: '#faf7fc',
|
||||
100: '#f4eef9',
|
||||
200: '#eaddf1',
|
||||
300: '#dbc1e6',
|
||||
400: '#c69dd5',
|
||||
500: '#ac75c0',
|
||||
600: '#965ca9',
|
||||
700: '#774586',
|
||||
800: '#633a6e',
|
||||
900: '#54335c',
|
||||
},
|
||||
|
||||
'amethyst': {
|
||||
50: '#fcf5fe',
|
||||
100: '#f7e9fe',
|
||||
200: '#efd3fb',
|
||||
300: '#e6b0f7',
|
||||
400: '#d880f2',
|
||||
500: '#c450e5',
|
||||
600: '#b543d2',
|
||||
700: '#8f25a6',
|
||||
800: '#762088',
|
||||
900: '#631f70',
|
||||
},
|
||||
|
||||
'seance': {
|
||||
50: '#fcf3ff',
|
||||
100: '#fae7ff',
|
||||
@ -464,6 +604,19 @@ module.exports = {
|
||||
900: '#8c0f45',
|
||||
},
|
||||
|
||||
'sea-pink': {
|
||||
50: '#fdf3f4',
|
||||
100: '#fbe8eb',
|
||||
200: '#f6d5da',
|
||||
300: '#ea9daa',
|
||||
400: '#e58799',
|
||||
500: '#d75c77',
|
||||
600: '#c13d60',
|
||||
700: '#a22e4f',
|
||||
800: '#882947',
|
||||
900: '#752642',
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
39
src/vite-ssr.config.js
Normal file
39
src/vite-ssr.config.js
Normal file
@ -0,0 +1,39 @@
|
||||
import fs from 'fs';
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
export default ({ mode }) => {
|
||||
process.env = Object.assign(process.env, loadEnv(mode, process.cwd(), ''));
|
||||
|
||||
return defineConfig({
|
||||
build: {
|
||||
reportCompressedSize: true,
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
input: 'resources/js/app.js',
|
||||
ssr: 'resources/js/ssr.js',
|
||||
refresh: true,
|
||||
}),
|
||||
vue({
|
||||
template: {
|
||||
transformAssetUrls: {
|
||||
base: null,
|
||||
includeAbsolute: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
ssr: {
|
||||
noExternal: ['@inertiajs/server'],
|
||||
},
|
||||
server: {
|
||||
host: process.env.APP_DOMAIN,
|
||||
https: {
|
||||
key: fs.readFileSync(`${process.env.VITE_SSL_KEY_FILE_PATH}`),
|
||||
cert: fs.readFileSync(`${process.env.VITE_SSL_CERT_FILE_PATH}`),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
@ -10,6 +10,13 @@ export default ({ mode }) => {
|
||||
build: {
|
||||
reportCompressedSize: true,
|
||||
},
|
||||
server: {
|
||||
host: process.env.APP_DOMAIN,
|
||||
https: {
|
||||
key: fs.readFileSync(`${process.env.VITE_SSL_KEY_FILE_PATH}`),
|
||||
cert: fs.readFileSync(`${process.env.VITE_SSL_CERT_FILE_PATH}`),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
input: 'resources/js/app.js',
|
||||
@ -25,15 +32,5 @@ export default ({ mode }) => {
|
||||
},
|
||||
}),
|
||||
],
|
||||
ssr: {
|
||||
noExternal: ['@inertiajs/server'],
|
||||
},
|
||||
server: {
|
||||
host: process.env.APP_DOMAIN,
|
||||
https: {
|
||||
key: fs.readFileSync(`/code/docker/configs/nginx/ssls/${process.env.APP_DOMAIN}/${process.env.APP_DOMAIN}.key`),
|
||||
cert: fs.readFileSync(`/code/docker/configs/nginx/ssls/${process.env.APP_DOMAIN}/${process.env.APP_DOMAIN}.crt`),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user