Compare commits

...

117 Commits

Author SHA1 Message Date
ac751f5f28 adding prefers reduced motion and clamp width to percent between values on body 2024-08-12 12:44:35 -06:00
a1aecdf3e2 adding AbuseIPDB to composer list 2024-08-12 12:43:44 -06:00
a747ef0129 adding a security.txt file 2024-03-18 11:18:25 -06:00
80aa487e7e updating some status codes 2024-02-28 14:52:37 -07:00
5048abc3e6 adding some text gradient CSS 2023-12-12 14:00:23 -07:00
afd34e9b4e adding profile photo trait 2023-12-12 13:59:55 -07:00
a81ce8a922 adding glossy button CSS 2023-12-12 13:59:44 -07:00
9d25befeba adding a method to also generate an avatar for a user 2023-12-12 13:58:31 -07:00
5d9f7e3997 adding package to convert heic/heif to jpeg, also paperclip 2023-12-12 13:58:10 -07:00
ecfae3e01a using new style of attribute casting 2023-12-12 13:57:42 -07:00
9e6c93ba95 adding some defaults to image tags 2023-12-12 13:57:12 -07:00
231dd959af adding some gradient border CSS 2023-12-12 13:56:57 -07:00
5607425bde adding a security template file 2023-12-12 13:56:38 -07:00
ac99d29109 removing unnecessary code to properly extend Jetstream user profile controller 2023-03-27 10:24:09 -06:00
d4f0044656 moving to mailpit from mailhog, adding paths to SSLs 2023-03-27 10:23:28 -06:00
9d455bdcf7 moving around some stuff with PHPCS config file 2023-03-27 10:22:57 -06:00
3b39ae0470 adding require pin package 2023-03-27 10:22:07 -06:00
9551f661c1 adding more colors 2023-03-27 10:21:52 -06:00
c02b40071f adding some colors as a markdown file 2023-03-27 10:21:34 -06:00
a0dc0e01f3 adding an action for genering profile photos 2023-03-27 10:21:08 -06:00
8876f07ac6 fixing some text and height stuff for the body tag 2023-03-27 10:20:56 -06:00
2ac78ef539 adding some variables for colors 2023-03-27 10:20:41 -06:00
56cef79880 fixing path to SSLs 2023-03-27 10:20:09 -06:00
aa5753cc82 adding a Vite SSR file 2023-03-27 10:19:55 -06:00
4dcb6b6ebe adding a clamp function 2023-03-27 10:19:42 -06:00
22946bc031 Adding some fonts 2023-03-27 10:19:09 -06:00
e2ce420764 wip: a wave/ripple effect 2022-12-27 14:19:05 -07:00
7583883d64 adding some css resets 2022-12-27 14:18:49 -07:00
fb5bde70ef checking for a user on the request before checking admin email 2022-12-16 10:48:18 -07:00
5e2a386b15 changing some URLs in the app view 2022-12-16 10:47:58 -07:00
75d052af88 updating Lucide icons to inherit height and width 2022-12-16 10:47:39 -07:00
87cd634613 adding a defines comment to input error vue component 2022-12-07 11:45:25 -07:00
48a34d5acf tweaking form label color 2022-12-07 11:44:55 -07:00
05ca3574b0 moving a transition property that was in it's own selector without reason 2022-12-07 11:44:29 -07:00
739c2b79e9 adding universally unique lexicographically sortable identifier (ULID) 2022-12-07 11:43:52 -07:00
6e7ded098b updating docblock 2022-12-07 11:43:09 -07:00
64d4d326b7 updating user and language models 2022-12-07 11:42:36 -07:00
fdba9f1ae7 updating create user and reset password with new return constants 2022-12-07 11:42:12 -07:00
27032f433a updating pre-commit 2022-12-07 11:41:52 -07:00
0c8a6c410d adding money castable 2022-12-07 11:41:43 -07:00
3f340d57fc adding a bunch of wip: i18n stuff 2022-11-28 12:32:48 -07:00
995cc32578 adding a middleware to handle super basic admin role check 2022-11-28 12:32:29 -07:00
5f5b443df7 wip: adding a team scope 2022-11-28 12:31:57 -07:00
e5366171fd adding some stuff for vite 2022-11-28 12:31:45 -07:00
1c650fbb64 removing check custom session data middleware 2022-11-28 12:30:56 -07:00
a784d44d16 adding a bubbles in background animation 2022-11-28 12:30:12 -07:00
e27aa8969f adding minio, admin email, session stuff, and clockwork env vars 2022-11-28 12:29:29 -07:00
433ad39a08 adding some form vue components 2022-11-28 12:28:41 -07:00
e78324e92a wip: adding user observer 2022-11-10 12:16:20 -07:00
5ceb315b6c adding some geo-spatial mysql stuff 2022-11-10 12:16:09 -07:00
58a4701ba3 fixing syntax error in global functions 2022-11-10 12:15:55 -07:00
a1f677ff9b adding Lucide icon set 2022-11-10 12:15:39 -07:00
ebb6a4721a moving Icons to FeatherIcons 2022-11-10 12:15:00 -07:00
625dfeb79f lots of updates 2022-10-19 14:33:03 -06:00
427d4e2500 finishing up adding all the icons from Feather icons 2022-09-28 14:30:10 -06:00
bdf5121d71 adding new call to not silently fail on fillable model exception for local env 2022-09-28 13:29:55 -06:00
16e07e0a53 adding adding doctrine dbal 2022-09-28 13:29:04 -06:00
d43dbe7c1c reording some stuff 2022-09-28 13:28:32 -06:00
0e3aaafc2f renaming trash icon 2022-09-28 13:27:40 -06:00
0ed9aef8d0 removing edit icon, will add it back 2022-09-28 13:27:27 -06:00
b7ac751b10 moving back to auto-incrementing IDs because of performance 2022-09-27 11:54:02 -06:00
400edc9b38 adding new layouts and updating AppLayout 2022-09-27 11:12:36 -06:00
a2a747c489 adding some dropdown components 2022-09-27 11:12:13 -06:00
5f87596b2f changing page layout assignment to work with Vite now 2022-09-27 11:12:05 -06:00
606899494c adding some grid layouts 2022-09-27 11:11:36 -06:00
08761f991b tweaking forms CSS 2022-09-27 11:11:27 -06:00
275b2f83b7 adding phpcs and a Laravel standard as packages 2022-09-27 11:11:16 -06:00
5c46e01a7f adding daisyui to the packages file 2022-09-27 11:11:01 -06:00
8312c5e54e fixing up the global functions and adding more conversions 2022-09-27 11:10:40 -06:00
bcf14cc604 updating phpcs config file 2022-09-27 11:10:25 -06:00
b8df8a8d4d modifying icons to have a default height, width, and optionally a title 2022-09-27 11:10:15 -06:00
e7bbacd59e adding blank changelog 2022-09-27 11:09:46 -06:00
a1c307df64 adding more colors to tailwind config 2022-09-27 11:09:38 -06:00
54eab9cd4a adding octogonal icons 2022-09-15 15:04:51 -06:00
51d047be86 adding Feather icons 2022-09-15 10:48:01 -06:00
9fab41ae2a adding a variables file 2022-09-15 10:47:39 -06:00
1c85d0b3cd adding a disco button 2022-09-15 10:46:26 -06:00
e39547e77e adding a disco thing for animations 2022-09-15 10:45:33 -06:00
10aae0a9f2 adding some comment headers to constants and global functions 2022-09-15 10:45:04 -06:00
e5c0eae622 updating how modals are done 2022-09-01 12:49:25 -06:00
2120fc8c4d rewrite to conform with latest Laravel dropdown element 2022-09-01 12:48:53 -06:00
c5612ba108 adjusting text shadow offsets 2022-09-01 12:48:23 -06:00
90e5ddee96 removing default border on gradient buttons, means the hover is broken 2022-09-01 12:48:03 -06:00
7fa9bbca77 fixing template columns for some grid extensions 2022-09-01 12:47:35 -06:00
0e325bfbca adding a select to list 2022-09-01 12:47:04 -06:00
252fab0084 adding Meilisearch master key variable 2022-09-01 12:46:32 -06:00
b11660329b changing password prompt to be secret 2022-09-01 12:46:09 -06:00
0ff04a5ecd adding some hexagon stuff, should be able to do a honeycomb layout with it 2022-08-18 14:17:41 -06:00
a7df7a64f0 adding date and time inputs to form CSS 2022-08-18 14:17:16 -06:00
90f3709f4b adding some colors 2022-08-18 14:16:54 -06:00
842e1994bd updating PHPCS config file 2022-08-18 14:16:31 -06:00
2a8eb7013d adding stuff to override sanctum token, can make them non-auto-incrementing 2022-07-29 14:15:14 -06:00
2c254b1a3e tweaking font faces 2022-07-29 13:47:50 -06:00
74215ba317 updating forms css 2022-07-29 13:47:43 -06:00
f9b31ef296 removing text shadow offset 2022-07-29 13:47:36 -06:00
f50d0203e5 tweaking ui for modals, navbars, and pagination 2022-07-29 13:47:14 -06:00
7359f4c00d fixing some font stuff with tailwind 2022-07-29 13:46:49 -06:00
a83b61c264 adding another sdk to composer 2022-07-29 13:46:35 -06:00
a6849c201a removing a git hook that is more reserved for server-side repos 2022-07-29 13:46:23 -06:00
6fa1c5ca95 adding some fonts 2022-07-29 13:45:52 -06:00
2c44584c81 adding a create user command 2022-07-19 14:11:54 -06:00
374ea35e42 making app name camelcase in inertia middleware 2022-07-19 14:11:36 -06:00
2b13367970 adding a note about language setter in successful login event 2022-07-19 14:11:09 -06:00
64454ddee7 fixing user id reference in session migration 2022-07-19 14:10:39 -06:00
78d6383b15 adding empty css classes to prevent build errors 2022-07-19 14:10:07 -06:00
a29f28c11d using my own tailwindcss-neu package 2022-07-19 14:09:40 -06:00
b8e8f212d6 adding webpack alias 2022-07-19 14:09:16 -06:00
b56dd305c1 updating some node package versions 2022-07-19 14:09:00 -06:00
cf828164c3 adding a bucket full of packages that I might find useful 2022-07-19 14:08:39 -06:00
75d5f8c6c3 fixing dirty state variable 2022-07-19 14:08:14 -06:00
3e42869bbb fixing git hook scripts 2022-07-19 14:07:50 -06:00
46b6cb678e adding a PHP Code Sniffer config file 2022-07-19 14:07:37 -06:00
58c5c57cc3 adding more env variables 2022-06-29 13:46:45 -06:00
f2ebea7de3 Adding another session variable to successful login event 2022-06-29 13:46:20 -06:00
0e88b9b198 minor tweaks to how JS is set up 2022-06-29 13:46:07 -06:00
dabcb49292 moving some CSS around 2022-06-29 13:45:45 -06:00
9577395516 Removing unused View component 2022-06-29 13:45:24 -06:00
1313 changed files with 55334 additions and 1732 deletions

60
colors.md Normal file
View 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

View File

@ -5,9 +5,9 @@ sed -i "/^GIT_HASH=\".*\"/ s//GIT_HASH=\"${SHORT_HASH}\"/" .env
DIRTY_STATE=$(git diff --stat)
if [ -n "$DIRTY_STATE" ]; then
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=true/" .env
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_DIRTY_STATE=true/" .env
else
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=false/" .env
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_DIRTY_STATE=false/" .env
fi
GIT_TAG=$(git tag --points-at HEAD)

View File

@ -5,17 +5,21 @@ sed -i "/^GIT_HASH=\".*\"/ s//GIT_HASH=\"${SHORT_HASH}\"/" .env
DIRTY_STATE=$(git diff --stat)
if [ -n "$DIRTY_STATE" ]; then
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=true/" .env
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_DIRTY_STATE=true/" .env
else
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=false/" .env
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_DIRTY_STATE=false/" .env
fi
SHORT_HASH=$(git rev-parse --short HEAD)
sed -i "/^GIT_HASH=\".*\"/ s//GIT_HASH=\"${SHORT_HASH}\"/" .env
GIT_TAG=$(git tag --points-at HEAD)
if [ -n "$GIT_TAG" ]; then
sed -i "/^GIT_TAG=\".*\"/ s//GIT_TAG=\"${GIT_TAG}\"/" .env
else
sed -i "/^GIT_TAG=\".*\"/ s//GIT_TAG=\"\"/" .env
fi
GIT_BRANCH=$(git branch --show-current)
if [ -n "$GIT_BRANCH" ]; then
sed -i "/^GIT_BRANCH=\".*\"/ s//GIT_BRANCH=\"${GIT_BRANCH}\"/" .env
else
sed -i "/^GIT_BRANCH=\".*\"/ s//GIT_BRANCH=\"\"/" .env
fi

View File

@ -1,25 +0,0 @@
#!/usr/bin/env bash
SHORT_HASH=$(git rev-parse --short HEAD)
sed -i "/^GIT_HASH=\".*\"/ s//GIT_HASH=\"${SHORT_HASH}\"/" .env
DIRTY_STATE=$(git diff --stat)
if [ -n "$DIRTY_STATE" ]; then
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=true/" .env
else
sed -i "/^GIT_DIRTY_STATE=.*/ s//GIT_TAG=false/" .env
fi
GIT_TAG=$(git tag --points-at HEAD)
if [ -n "$GIT_TAG" ]; then
sed -i "/^GIT_TAG=\".*\"/ s//GIT_TAG=\"${GIT_TAG}\"/" .env
else
sed -i "/^GIT_TAG=\".*\"/ s//GIT_TAG=\"\"/" .env
fi
GIT_BRANCH=$(git branch --show-current)
if [ -n "$GIT_BRANCH" ]; then
sed -i "/^GIT_BRANCH=\".*\"/ s//GIT_BRANCH=\"${GIT_BRANCH}\"/" .env
else
sed -i "/^GIT_BRANCH=\".*\"/ s//GIT_BRANCH=\"\"/" .env
fi

32
git-hooks/pre-commit Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env bash
# get bash colors and styles here:
# http://misc.flogisoft.com/bash/tip_colors_and_formatting
C_RESET='\e[0m'
C_RED='\e[31m'
C_GREEN='\e[32m'
C_YELLOW='\e[33m'
function __run() #(step, name, cmd)
{
local color output exitcode
printf "${C_YELLOW}[%s]${C_RESET} %-20s" "$1" "$2"
output=$(eval "$3" 2>&1)
exitcode=$?
if [[ 0 == $exitcode || 130 == $exitcode ]]; then
echo -e "${C_GREEN}OK!${C_RESET}"
else
echo -e "${C_RED}NOK!${C_RESET}\n\n$output"
exit 1
fi
}
modified="git diff --diff-filter=M --name-only --cached | grep \".php$\""
ignore="resources/lang,resources/views,bootstrap/helpers,database/migrations,bin"
phpcs="vendor/bin/phpcs --report=code --colors --report-width=80 --ignore=${ignore}"
__run "1/2" "php lint" "${modified} | xargs -r php -l"
__run "2/2" "code sniffer" "${modified} | xargs -r ${phpcs}"
# __run "3/3" "phpstan" "${modified} | xargs -r vendor/bin/phpstan analyse"

View File

@ -4,11 +4,12 @@ APP_KEY=base64:hSCTwZ507IdKQ5QJHJ+mQw0DSMgDdAspasjwHCdiB8Y=
APP_DEBUG=true
APP_DOMAIN=localhost
APP_URL="https://${APP_DOMAIN}"
APP_UID_BYTES=8
ADMIN_EMAIL=""
GIT_HASH="00000000"
GIT_TAG="x.x.x"
GIT_BRANCH="master"
GIT_DIRTY_STATE=false
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
@ -27,27 +28,42 @@ FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=database
SESSION_LIFETIME=120
#SESSION_STORE=redis
#SESSION_DOMAIN="${APP_DOMAIN}"
#SESSION_SECURE_COOKIE=true
MEMCACHED_HOST=memcached
MEMCACHED_HOST=memcache
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@${APP_DOMAIN}"
MAIL_FROM_NAME="${APP_NAME}"
SCOUT_DRIVER=meilisearch
SCOUT_PREFIX=
SCOUT_QUEUE=false
MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_KEY=
MEILISEARCH_PRIVATE_KEY=
MEILISEARCH_PUBLIC_KEY=
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1125
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="no-reply@${APP_DOMAIN}"
MAIL_FROM_NAME="${APP_NAME}"
GOOGLE_GEOCODE_API_KEY=
MINIO_USERNAME=
MINIO_PASSWORD=
MINIO_DEFAULT_REGION=us-west-1
MINIO_BUCKET=
MINIO_URL=
MINIO_ENDPOINT=
MINIO_USE_PATH_STYLE_ENDPOINT=false
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
@ -58,10 +74,19 @@ 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}"
MIX_PUSHER_PORT="${PUSHER_PORT}"
MIX_PUSHER_SCHEME="${PUSHER_SCHEME}"
INTEGRITY_HASH_HUMANS_TXT=""
INTEGRITY_HASH_ROBOTS_TXT=""
@ -78,3 +103,13 @@ INTEGRITY_HASH_WEBMANIFEST_JSON=""
INTEGRITY_HASH_MIX_MANIFEST_JSON=""
INTEGRITY_HASH_APP_CSS=""
INTEGRITY_HASH_APP_JS=""
## Clockwork debug helpers
## default values are set, except for the main enable switch
CLOCKWORK_ENABLE=true
CLOCKWORK_WEB=true
CLOCKWORK_AUTHENTICATION=false
#CLOCKWORK_AUTHENTICATION_PASSWORD=VerySecretPassword
CLOCKWORK_CACHE_COLLECT_VALUES=true
#CLOCKWORK_DATABASE_SLOW_THRESHOLD= # time in miliseconds
#CLOCKWORK_REQUESTS_SLOW_THRESHOLD= # time in miliseconds

36
src/.phpcs.xml Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<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>
<arg name="basepath" value="."/>
<arg name="parallel" value="4"/>
<arg name="report" value="full"/>
<arg name="extensions" value="php"/>
<arg name="colors"/>
<arg name="no-cache"/>
<arg value="nps"/>
<ini name="memory_limit" value="64M"/>
<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>
</rule>
<!-- Include all sniffs in the PSR-2 standard -->
<rule ref="PSR2">
<exclude name="Generic.Files.LineLength.TooLong"/>
</rule>
</ruleset>

View 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

26
src/CHANGELOG.md Normal file
View File

@ -0,0 +1,26 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
-
### Changed
-
### Removed
-
## [1.0.0] - 20XX-01-01
### Added
-
### Changed
-
### Removed
-

30
src/SECURITY.md Normal file
View 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.

View 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);
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
class CreateUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:create {--e|email= : The email address of the user}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new user';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
$email = trim($this->option('email'));
$name = $this->ask("Please provide a name");
$surname = $this->ask("Please provide a surname");
if (empty($email)) {
$email = $this->ask("Please provide an email address");
}
if (empty($password)) {
// TODO: have a way to hide the input and do a confirm password input
$password = $this->secret("Please provide a password");
}
try {
User::create([
'name' => trim($name),
'surname' => trim($surname),
'email' => trim($email),
'password' => Hash::make(trim($password)),
]);
$this->info("$email created successfully.");
return Command::SUCCESS;
} catch (\Exception $e) {
$this->error('Unable to create your user.');
$this->line($e->getMessage());
return 1;
}
}
}

View File

@ -52,7 +52,7 @@ class ResetPassword extends Command
$column = 'email';
$value = $email;
} else {
$column = strtolower($this->choice('What column would you like to search by?', ['ID', 'Email']));
$column = strtolower($this->choice('What database column would you like to search by?', ['ID', 'Email']));
$value = $this->ask("Please provide an $column to search for");
}
@ -68,7 +68,7 @@ class ResetPassword extends Command
try {
$user->update(['password' => Hash::make($password)]);
$this->info("User {$user->id} ({$user->email}) password update successful!");
return 0;
return Command::SUCCESS;
} catch (\Exception $e) {
$this->error('Unable to set the password!');
$this->line($e->getMessage());

View File

@ -0,0 +1,83 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TranslationCheckerCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'i18n:check-json {--l|locale= : The source of truth locale}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Uses one JSON file as the source of truth to check other lang files against.';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$masterLocale = 'en';
if (!empty($this->option('locale'))) {
$masterLocale = trim($this->option('locale'));
}
$langDir = base_path('lang');
$langFiles = scandir($langDir);
$bigCount = count($langFiles);
for ($i = 0; $i < $bigCount; $i++) {
if (! preg_match('/.*\.json$/', $langFiles[$i]) || "{$masterLocale}.json" === $langFiles[$i]) {
unset($langFiles[$i]);
}
}
$langFilesCount = count($langFiles);
$this->info("Checking {$langFilesCount} file(s) against {$masterLocale}...");
$masterLocaleTranslations = translations(base_path("lang/{$masterLocale}.json"));
foreach ($langFiles as $localeFile) {
$otherLocaleTranslations = translations(base_path("lang/{$localeFile}"));
$counts = 0;
$mergedTranslations = $this->recursiveMergeArray($masterLocaleTranslations, $otherLocaleTranslations, $counts);
file_put_contents(base_path("lang/{$localeFile}"), json_encode($mergedTranslations, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
$this->info("{$localeFile} had {$counts} missing translations.");
}
return Command::SUCCESS;
}
public function recursiveMergeArray(array $firstArray, array $secondArray, int &$counts)
{
$mergedArray = $secondArray;
foreach ($firstArray as $key => $value) {
if (is_array($value)) {
if (!array_key_exists($key, $secondArray)) {
$mergedArray[$key] = $value;
} else {
$subDiff = $this->recursiveMergeArray($value, $secondArray[$key], $counts);
if (!empty($subDiff)) {
$mergedArray[$key] = $subDiff;
}
}
} else {
if (!array_key_exists($key, $secondArray)) {
$counts++;
$mergedArray[$key] = $value;
}
}
}
return $mergedArray;
}
}

View File

@ -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);
});
}
}

33
src/app/Http/Kernel.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
//...
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
//...
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\SetLocale::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
//...
],
'admin' => [
//...
\Laravel\Jetstream\Http\Middleware\ShareInertiaData::class,
\App\Http\Middleware\SetLocale::class,
\App\Http\Middleware\AuthorizeAdmin::class,
//...
],
];
}

View File

@ -5,22 +5,20 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckCustomSessionData
class AuthorizeAdmin
{
/**
* Handle an incoming request.
*
* @since 1.0.0
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
*
* @return mixed
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if ((! session()->has('thing') || empty(session('thing'))) && $request->user()) {
session()->put('thing', $request->user()->thing);
if ($request->user()->email !== env('ADMIN_EMAIL')) {
abort(HTTP_NOT_FOUND);
}
return $next($request);

View File

@ -2,6 +2,7 @@
namespace App\Http\Middleware;
use App\Models\Language;
use Illuminate\Http\Request;
use Inertia\Middleware;
@ -41,19 +42,58 @@ class HandleInertiaRequests extends Middleware
*/
public function share(Request $request): array
{
$localeFields = ['locale_name', 'iso_code', 'name', 'localized_name'];
$currentLocale = $request->session()->get('locale', null);
if (is_null($currentLocale)) {
$currentLocale = Language::where(['locale_name' => 'en', 'iso_code' => 'en_US'])->get($localeFields)[0]->toArray();
$request->session()->put('locale', [
'locale_name' => $currentLocale['locale_name'],
'iso_code' => $currentLocale['iso_code'],
'name' => $currentLocale['name'],
'localized_name' => $currentLocale['localized_name'],
]);
}
$localeFilePath = base_path("lang/{$currentLocale['locale_name']}.json");
$notifications = [];
$notificationsCount = count($notifications);
$unreadNotifications = false;
if (! is_null($request->user())) {
$notifications = $request->user()->notifications;
$notificationsCount = count($notifications);
for ($i = 0; $i < $notificationsCount; $i++) {
$newData = $notifications[$i]->data;
$createdAt = carbon($notifications[$i]->created_at);
$dateFormat = 'F j';
if (!$createdAt->is(gmdate('Y'))) {
$dateFormat = 'F j, Y';
}
$newData['created_at_date'] = $createdAt->copy()->format($dateFormat);
$newData['created_at_time'] = $createdAt->copy()->format('H:i');
$notifications[$i]->data = $newData;
}
if (count($request->user()->unreadNotifications) > 0) {
$unreadNotifications = true;
}
}
return array_merge(parent::share($request), [
'app_name' => config('app.name'),
$additionalData = [
'appName' => config('app.name'),
'availableLocales' => Language::get($localeFields),
'currentLocale' => $currentLocale,
'language' => translations($localeFilePath),
'notifications' => $notifications,
'unreadNotifications' => $unreadNotifications,
]);
];
if (! is_null($request->user())) {
if ($request->user()->email === env('ADMIN_EMAIL')) {
$additionalData['is_admin_user'] = true;
}
}
return array_merge(parent::share($request), $additionalData);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class SetLocale
{
/**
* Handle an incoming request.
*
* @package App\Http\Middleware\SetLocale
* @since 1.0.0
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
*
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (session()->has('locale')) {
app()->setLocale(session('locale')['locale']);
}
return $next($request);
}
}

View File

@ -30,6 +30,11 @@ class SuccessfulLogin
{
Session::put('timezone_name', $event->user->timezone_name);
// TODO: this may need to be reworked so that the language is stored
// in a cookie and attempted to be retrieved from there
// first before pulling from the database.
Session::put('language', $event->user->language->locale);
// Optionally log the info
/*
$loginPayload = [

View File

@ -3,7 +3,6 @@
namespace App\Models;
use App\Models\Traits\FormattedAddressTrait;
use App\Models\Traits\HasUidTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -14,18 +13,11 @@ class Address extends Model
{
use FormattedAddressTrait;
use HasFactory;
use HasUidTrait;
use Prunable;
/** @var string */
protected $table = 'addresses';
/** @var string */
protected $keyType = 'string';
/** @var bool */
public $incrementing = false;
/** @var array */
protected $fillable = [
'addressable_type',

View File

@ -0,0 +1,51 @@
<?php
namespace App\Models\Casts;
use Brick\Money\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class MoneyCastable implements CastsAttributes
{
/**
* Get the value from the database and modify it to casted type
* before returning.
*
* @package App\Models\Casts\MoneyCastable
* @since 1.0.0
*
* @param \Illuminate\Database\Eloquent\Model $model The Model that is being used
* @param string $key The attribute key
* @param mixed $value The value stored in the database
* @param array $attributes The array of model attributes
*
* @return \Brick\Money\Money
*/
public function get(Model $model, string $key, $value, array $attributes): Money
{
return Money::ofMinor($attributes['amount'], $attributes['currency']);
}
/**
* Store the data .
*
* @package App\Models\Casts\MoneyCastable
* @since 1.0.0
*
* @param \Illuminate\Database\Eloquent\Model $model The Model that is being used
* @param string $key The attribute key
* @param mixed $value The value stored in the database
* @param array $attributes The array of model attributes
*
* @return mixed
*/
public function set(Model $model, string $key, $value, array $attributes)
{
if (! $value instanceof Money) {
return $value;
}
return $value->getMinorAmount()->toInt();
}
}

117
src/app/Models/Language.php Normal file
View File

@ -0,0 +1,117 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Language extends Model
{
use HasFactory;
use Prunable;
use SoftDeletes;
/** @var string */
protected $table = 'languages';
/** @var array<int,string> */
protected $fillable = [
'locale_name',
'iso_code',
'name',
'localized_name',
];
/**
|--------------------------------------------------------------------------
| Class Constants
|--------------------------------------------------------------------------
|
*/
//
/**
|--------------------------------------------------------------------------
| Custom/Private Methods
|--------------------------------------------------------------------------
|
*/
/**
* Get the prunable model query.
*
* @package App\Models\Language
* @since 1.0.0
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function prunable(): Builder
{
//return static::where('deleted_at', '<=', now()->subMonth());
}
/**
* Prepare the model for pruning.
*
* @package App\Models\Language
* @since 1.0.0
*
* @return void
*/
protected function pruning(): void
{
//
}
/**
|--------------------------------------------------------------------------
| Accessors
|--------------------------------------------------------------------------
|
*/
//
/**
|--------------------------------------------------------------------------
| Mutators
|--------------------------------------------------------------------------
|
*/
//
/**
|--------------------------------------------------------------------------
| Scopes
|--------------------------------------------------------------------------
|
*/
//
/**
|--------------------------------------------------------------------------
| Relationships
|--------------------------------------------------------------------------
|
*/
/**
* User relationship.
*
* @package App\Models\Language
* @since 1.0.0
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function users(): HasMany
{
return $this->hasMany(User::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class OnTeamScope implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
*
* @return void
*/
public function apply(Builder $builder, Model $model): void
{
$builder->where('current_team_id', );
}
}

View File

@ -2,19 +2,24 @@
namespace App\Models\Traits;
use Illuminate\Database\Eloquent\Casts\Attribute;
trait FormattedPhoneTrait
{
/**
* Format a phone number to be human readable.
*
* @package Namespace\App\Contact
* @since 1.0.0
*
* @return string
* @return void
*/
public function getPhoneNumberAttribute(): string
protected function phoneNumber(): Attribute
{
$phoneLength = strlen($this->phone);
$phoneNumber = preg_replace('//', '', $this->phone);
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);
@ -37,19 +42,10 @@ trait FormattedPhoneTrait
}
return $phoneNumber;
}
/**
* Remove all non-numeric characters from the phone number.
*
* @since 1.0.0
*
* @param string $value
*
* @return void
*/
public function setPhoneNumberAttribute($value): void
{
$this->attributes['phone'] = preg_replace('/[^0-9]/', '', $value);
},
set: function (mixed $value) {
return preg_replace('/[^0-9]/', '', $value);
},
);
}
}

View 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');
}
}

View File

@ -2,7 +2,6 @@
namespace App\Models;
use App\Models\Traits\HasUidTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Prunable;
@ -20,7 +19,6 @@ class User extends Authenticatable
use HasFactory;
use HasProfilePhoto;
use HasTeams;
use HasUidTrait;
use Notifiable;
use Prunable;
use TwoFactorAuthenticatable;
@ -39,6 +37,7 @@ class User extends Authenticatable
'name',
'surname',
'timezone_name',
'language_id',
'current_team_id',
'profile_photo_path',
'email',
@ -185,4 +184,17 @@ class User extends Authenticatable
{
return $this->morphOne(Address::class, 'addressable');
}
/**
* Language relationship.
*
* @package App\Models\User
* @since 1.0.0
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function language(): BelongsTo
{
return $this->belongsTo(Language::class);
}
}

View File

@ -0,0 +1,125 @@
<?php
namespace App\Observers;
use App\Models\User;
class UserObserver
{
/**
* Handle events after all transactions are committed.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @var bool
*/
public $afterCommit = true;
/**
* Handle the User "retrieve" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function retrieved(User $user)
{
//
}
/**
* Handle the User "saving" event.
* This may apply as either a create
* or an update event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function saving(User $user)
{
//
}
/**
* Handle the User "created" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function created(User $user)
{
//
}
/**
* Handle the User "updated" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function updated(User $user)
{
//
}
/**
* Handle the User "deleted" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function deleted(User $user)
{
//
}
/**
* Handle the User "restored" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function restored(User $user)
{
//
}
/**
* Handle the User "forceDeleted" event.
*
* @package App\Observers\UserObserver
* @since 1.0.0
*
* @param \App\Models\User $user
*
* @return void
*/
public function forceDeleted(User $user)
{
//
}
}

View File

@ -14,7 +14,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
//
Model::preventSilentlyDiscardingAttributes($this->app->isLocal());
}
/**

View File

@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use App\Models\PersonalAccessToken;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Sanctum\Sanctum;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
//...
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}
}

View File

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

View File

@ -1,4 +1,94 @@
{
//...
"require": {
//..
// Laravel provided stuff
"laravel/cashier": "", // fluent interface to Stripe
"laravel/horizon": "", // dashboard and configuration for Laravel queues
"laravel/telescope": "", // debugging tool from Laravel for Laravel
"laravel/scout": "", // full-text search to Eloquent models
"meilisearch/meilisearch-php": "", // use Meilisearch for Scout funtionality
"http-interop/http-factory-guzzle": "", // use Meilisearch for Scout funtionality
"dwarfdk/laravel-meilitools": "", // additional tools for Meilisearch (https://github.com/dwarfhq/laravel-meilitools)
// Roles / Permissions
"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
// SDKs
"aws/aws-sdk-php-laravel": "", // interact with S3 or S3-compatible storage
"propaganistas/laravel-phone": "", // uses Google's libphonenumber API to (try to) sanely handle phone numbers
"vladimir-yuldashev/laravel-queue-rabbitmq": "", // Interface with RabbitMQ servers
"grimzy/laravel-mysql-spatial": "", // Adds Geo-spatial column support for MySQL (WARNING: only works with Laravel v8 or lower)
"matanyadaev/laravel-eloquent-spatial": "", // Adds Geo-spatial column support for MySQL
"irazasyed/telegram-bot-sdk": "", // unofficial Telegram Bot API/SDK
"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
"spatie/laravel-medialibrary": "", // manage a small or large amount of media smartly
"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
"barryvdh/laravel-translation-manager": "", // self-evident
// PDF stuff
"creagia/laravel-sign-pad": "", // allows signatures on documents
// Geo-spatial
"brick/geo": "", // GIS geometry library
"stevebauman/location": "", // retrieve a user's location by their IP address
// Websockets
"beyondcode/laravel-websockets": "", // use websockets in the same laravel application
// Helpers/Generators
"infyomlabs/laravel-calendar-events": "", // help with handling future dates without having to store records in the database
"lab404/laravel-impersonate": "", // Impersonate other users in your application
"kitloong/laravel-migrations-generator": "", // create migrations based on your existing database
"spatie/laravel-sitemap": "", // generate site maps
"artesaos/seotools": "", // automatic SEO tools
"eumanito/php-capitalize-names": "", // Capitalize names with funky rules
"robinvdvleuten/ulid": "", // Universally Unique Lexicographically Sortable Identifier (ULID)
// Others/uncategorized
"appstract/laravel-opcache": "", // provides artisan commands to interact with opcache (not sure if site-specific)
"brick/math": "", // arbitrary-precision arithmetic library
"brick/money": "", // money and currency library
"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
},
"require-dev": {
//..
"itsgoingd/clockwork": "",
"phpstan/phpstan": "",
"psalm/plugin-laravel": "",
"vimeo/psalm": "",
"slevomat/coding-standard": "^8.5", // additional coding standards to match Laravel
"squizlabs/php_codesniffer": "^3.7"
},
//...
"autoload": {
//...,

View File

@ -2,9 +2,11 @@
namespace Database\Factories;
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;
@ -31,6 +33,7 @@ class UserFactory extends Factory
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'timezone_name' => $this->faker->timezone(),
'language_id' => Language::all()->random()->id,
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
@ -69,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}"
]);
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('languages', function (Blueprint $table) {
$table->id();
$table->string('locale_name')->index();
$table->string('iso_code')->unique();
$table->string('name');
$table->string('localized_name');
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('languages');
}
};

View File

@ -14,13 +14,14 @@ return new class extends Migration
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->string('id', 64)->primary();
$table->id();
$table->string('name');
$table->string('surname');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('timezone_name')->default('UTC');
$table->string('current_team_id', 64)->nullable();
$table->foreignId('language_id');
$table->foreignId('current_team_id')->nullable();
$table->string('profile_photo_path', 2048)->nullable();
$table->string('password');
$table->text('two_factor_secret')->nullable();

View File

@ -15,12 +15,12 @@ return new class extends Migration
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('user_id', 64);
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable()->index();
$table->text('payload');
$table->integer('last_activity')->index();
$table->timestamp('vr_last_activity_at')->virtualAs('FROM_UNIXTIME(last_activity)');
$table->timestamp('vrt_last_activity_at')->virtualAs('FROM_UNIXTIME(last_activity)');
});
}

View File

@ -14,8 +14,8 @@ return new class extends Migration
public function up()
{
Schema::create('addresses', function (Blueprint $table) {
$table->string('id', 64)->primary();
$table->uuidMorphs('addressable');
$table->id();
$table->morphs('addressable');
$table->string('street');
$table->string('unit')->nullable();
$table->string('city');

View File

@ -14,16 +14,11 @@ return new class extends Migration
public function up()
{
Schema::create('address_user', function (Blueprint $table) {
$table->string('address_id', 64);
$table->string('user_id', 64);
$table->foreign('address_id')
->references('id')->on('addresss')
->cascadeOnUpdate()->cascadeOnDelete();
$table->foreign('user_id')
->references('id')->on('users')
->cascadeOnUpdate()->cascadeOnDelete();
$table->id();
$table->foreignId('address_id')->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnUpdate()->cascadeOnDelete();
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
});
}

View File

@ -16,55 +16,18 @@ class LanguageSeeder extends Seeder
*/
public function run()
{
$languages = [
[
'iso_code' => 'en_US',
'locale' => 'en',
'country_code' => 'US',
'title' => 'English',
'title_localized' => 'English',
],
[
'iso_code' => 'de_DE',
'locale' => 'de',
'country_code' => 'DE',
'title' => 'German',
'title_localized' => 'Deutsch',
],
[
'iso_code' => 'fr_FR',
'locale' => 'fr',
'country_code' => 'FR',
'title' => 'French',
'title_localized' => 'Français',
],
[
'iso_code' => 'es_SP',
'locale' => 'es',
'country_code' => 'SP',
'title' => 'Spanish',
'title_localized' => 'Español',
],
[
'iso_code' => 'jp_JP',
'locale' => 'jp',
'country_code' => 'JP',
'title' => 'Japanese',
'title_localized' => '日本',
],
[
'iso_code' => 'zh_TW',
'locale' => 'zh',
'country_code' => 'TW',
'title' => 'Taiwanese',
'title_localized' => '台湾',
],
$languagesData = [
['locale' => 'en', 'iso_code' => 'en_US', 'name' => 'English', 'localized_name' => 'English (US)'],
['locale' => 'de', 'iso_code' => 'de_DE', 'name' => 'German', 'localized_name' => 'Deutsch'],
['locale' => 'fr', 'iso_code' => 'fr_FR', 'name' => 'French', 'localized_name' => 'Français'],
['locale' => 'jp', 'iso_code' => 'jp_JP', 'name' => 'Japanese', 'localized_name' => '日本'],
['locale' => 'mx', 'iso_code' => 'es_MX', 'name' => 'Spanish', 'localized_name' => 'Español'],
];
$startTime = Carbon::now();
$offset = 0;
foreach ($languages as $language) {
foreach ($languagesData as $language) {
$datetime = $startTime->copy()->addMinute($offset)->toDateTimeString();
$offset++;
$language['created_at'] = $datetime;

View File

@ -1,5 +1,15 @@
<?php
/*
|--------------------------------------------------------------------------
| Cache TTL (Time-To-Live)
|--------------------------------------------------------------------------
|
| Here is a collection of intervals in seconds that are commong to use
| when caching, but written as a more human-friendly phrase.
|
*/
define('CACHE_TTL_FIVE_MINUTES', 300);
define('CACHE_TTL_FIFTEEN_MINUTES', 900);

View File

@ -1,5 +1,15 @@
<?php
/*
|--------------------------------------------------------------------------
| HTTP Status Codes
|--------------------------------------------------------------------------
|
| Here is a collection of HTTP status codes and a corresponding string
| that is human-friendly and easy to remember.
|
*/
$httpCodes = [
// 100's (informational / "hold on")
100 => 'HTTP_CONTINUE',
@ -14,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',
@ -47,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',
];

View File

@ -0,0 +1,76 @@
<?php
/**
|--------------------------------------------------------------------------
| Global Date/Time Functions
|--------------------------------------------------------------------------
|
| This is a home for functions that don't belong to any one class and
| that should be available anywhere in the application.
|
*/
if (! function_exists('secondsToTime')) {
/**
* Convert seconds to hour:minute:second with hour being omitted
* if the amount of seconds is less than an hour.
*
* @since 1.0.0
*
* @param datatype $seconds
*
* @return string
*/
function secondsToTime($seconds): string
{
$seconds = intval($seconds);
if ($seconds >= 3600) {
return sprintf('%02d:%02d:%02d', ($seconds / 3600), (($seconds / 60) % 60), ($seconds % 60));
}
return sprintf('%02d:%02d', (($seconds / 60) % 60), ($seconds % 60));
}
}
if (! function_exists('minutesToTime')) {
/**
* Convert minutes to HH:MM
*
* @since 1.0.0
*
* @param datatype $minutes
*
* @return string
*/
function minutesToTime($minutes): string
{
$minutes = intval($minutes);
return sprintf('%d:%02d', floor($minutes / 60), ($minutes % 60));
}
}
if (! function_exists('jddayofweek')) {
/**
* 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 $mode
*
* @return string
*/
function jddayofweek(?int $intDay = null, int $mode = 0): string
{
if (is_null($intDay)) {
$intDay = date('l');
}
if ($mode === 0) {
return $intDay;
}
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][$intDay];
}
}

View File

@ -0,0 +1,233 @@
<?php
/**
|--------------------------------------------------------------------------
| Global Distance Functions
|--------------------------------------------------------------------------
|
| This is a home for functions that don't belong to any one class and
| that should be available anywhere in the application.
|
*/
/**
|--------------------------------------------------------------------------
| Metric functions
|--------------------------------------------------------------------------
| Functions that convert from metric to imperial or from a smaller
| metric unit to a larger one.
|
*/
if (! function_exists('centimeters2Inches')) {
/**
* Convert from centimeters to inches.
*
* @since 1.0.0
*
* @param float|int|string $centimeters
* @param int $precision
*
* @return float
*/
function centimeters2Inches($centimeters, int $preceision = 1): float
{
return round(($centimeters / 2.54), $preceision);
}
}
if (! function_exists('centimeters2Feet')) {
/**
* Convert from centimeters to inches.
*
* @since 1.0.0
*
* @param float|int|string $centimeters
* @param int $precision
*
* @return float
*/
function centimeters2Feet($centimeters, int $preceision = 1): float
{
return round((($centimeters / 2.54) * 12), $preceision);
}
}
if (! function_exists('centimeters2Meters')) {
/**
* Convert from centimeters to meters.
*
* @since 1.0.0
*
* @param float|int|string $centimeters
* @param int $precision
*
* @return float
*/
function centimeters2Meters($centimeters, int $preceision = 1): float
{
return round(($centimeters / 100), $preceision);
}
}
if (! function_exists('centimeters2Yards')) {
/**
* Convert from centimeters to yards.
*
* @since 1.0.0
*
* @param float|int|string $centimeters
* @param int $precision
*
* @return float
*/
function centimeters2Yards($centimeters, int $preceision = 1): float
{
return round(($centimeters / 91.44), $preceision);
}
}
if (! function_exists('meters2Miles')) {
/**
* Convert from meters to miles.
*
* @since 1.0.0
*
* @param float|int|string $meters
* @param int $precision
*
* @return float
*/
function meters2Miles($meters, int $preceision = 1): float
{
return round(($meters * 0.00062137), $preceision);
}
}
if (! function_exists('kilometers2Miles')) {
/**
* Convert from kilometers to meters.
*
* @since 1.0.0
*
* @param float|int|string $kilometers
* @param int $precision
*
* @return float
*/
function kilometers2Miles($kilometers, int $preceision = 1): float
{
return round(($kilometers * 1.609), $preceision);
}
}
if (! function_exists('meters2Kilometers')) {
/**
* Convert from meters to kilometers.
*
* @since 1.0.0
*
* @param float|int|string $meters
* @param int $precision
*
* @return float
*/
function meters2Kilometers($meters, int $preceision = 1): float
{
return round(($meters / 1000), $preceision);
}
}
if (! function_exists('millimeters2Inches')) {
/**
* Convert from millimeters to inches.
*
* @since 1.0.0
*
* @param float|int|string $millimeters
* @param int $precision
*
* @return float
*/
function millimeters2Inches($millimeters, int $preceision = 1): float
{
return round(($millimeters / 25.4), $preceision);
}
}
/**
|--------------------------------------------------------------------------
| Imperial functions
|--------------------------------------------------------------------------
| Functions that convert from imperial to metric or from a smaller
| imperial unit to a larger one.
|
*/
if (! function_exists('inches2Millimeters')) {
/**
* Convert from inches to millimeters.
*
* @since 1.0.0
*
* @param float|int|string $inches
* @param int $precision
*
* @return float
*/
function inches2Millimeters($inches, int $preceision = 1): float
{
return round(($inches * 2.54), $preceision);
}
}
if (! function_exists('inches2Meters')) {
/**
* Convert from inches to meters.
*
* @since 1.0.0
*
* @param float|int|string $inches
* @param int $precision
*
* @return float
*/
function inches2Meters($inches, int $preceision = 1): float
{
return round(($inches / 39.37), $preceision);
}
}
if (! function_exists('inches2Yards')) {
/**
* Convert from inches to yards.
*
* @since 1.0.0
*
* @param float|int|string $inches
* @param int $precision
*
* @return float
*/
function inches2Yards($inches, int $preceision = 1): float
{
return round(($inches / 36), $preceision);
}
}
if (! function_exists('inches2Feet')) {
/**
* Convert from inches to feet.
*
* @since 1.0.0
*
* @param float|int|string $inches
* @param int $precision
*
* @return float
*/
function inches2Feet($inches, int $preceision = 1): float
{
return round(($inches * 12), $preceision);
}
}

View File

@ -0,0 +1,29 @@
<?php
// phpcs:ignore
/**
|--------------------------------------------------------------------------
| Global String Functions
|--------------------------------------------------------------------------
|
| This is a home for functions that don't belong to any one class and
| that should be available anywhere in the application.
|
*/
if (! function_exists('snake2Title')) {
/**
* Convert a snake case string to a title with spaces
* and every word capitalized.
*
* @param string $snakeSlug A snake case string, commonly a slug
*
* @since 1.0.0
*
* @return string
*/
function snake2Title(string $snakeSlug): string
{
$output = preg_replace('/\_/', ' ', $snakeSlug);
return ucwords($output);
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
|--------------------------------------------------------------------------
| Global Temperature Functions
|--------------------------------------------------------------------------
|
| This is a home for functions that don't belong to any one class and
| that should be available anywhere in the application.
|
*/
if (! function_exists('celsius2Fahrenheit')) {
/**
* Convert from celsius to fahrenheit.
*
* @since 1.0.0
*
* @param float|int|string $celsius
* @param int $precision
*
* @return float
*/
function celsius2Fahrenheit($celsius, int $preceision = 0): float
{
return round((($celsius * (9/5)) + 32), $preceision);
}
}
if (! function_exists('fahrenheit2Celsius')) {
/**
* Convert from fahrenheit to celsius.
*
* @since 1.0.0
*
* @param float|int|string $fahrenheit
* @param int $precision
*
* @return float
*/
function fahrenheit2Celsius($fahrenheit, int $preceision = 1): float
{
return round(($fahrenheit - 32 * (5/9)), $preceision);
}
}

View File

@ -1,20 +1,86 @@
<?php
if (! function_exists('snake2Title')) {
require_once "functions/strings.php";
require_once "functions/date_and_time.php";
require_once "functions/distances.php";
require_once "functions/temperatures.php";
/**
|--------------------------------------------------------------------------
| Global Functions
|--------------------------------------------------------------------------
|
| This is a home for functions that don't belong to any one class and
| that should be available anywhere in the application.
|
*/
if (! function_exists('clamp')) {
/**
* Convert a snake case string to a title with spaces
* and every word capitalized.
* Ensure a numerical value is between two bounds.
*
* @since 1.0.0
*
* @param string $stakeSlug A snake case string, commonly a slug
* @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.
*
* @since 1.0.0
*
* @param int|string $number
* @param int|string|null $precision Decimal places to show (optional)
*
* @return string
*/
function snake2Title(string $snakeSlug): string
function humanBytes($number, $precision = null): string
{
$output = preg_replace('/\_/', ' ', $snakeSlug);
return ucwords($output);
if (empty($number)) {
return '0 B';
}
static $units = ['B', 'KB', 'MB', 'GB'];
static $bytePreceision = [0, 0, 1, 2];
$divisor = 1024;
for ($i = 0; $number / $divisor >= 0.9 && $i < 4; $i++) {
$number /= $divisor;
}
return round($number, is_null($precision) ? $bytePreceision[$i] : $precision) . $units[$i];
}
}
@ -40,28 +106,50 @@ if (! function_exists('carbon')) {
}
}
if (! function_exists('jddayofweek')) {
if (! function_exists('translations')) {
/**
* Returns the day of the week. Can return a string or an integer depending on the mode.
* Loads translations from a JSON file.
*
* @since 1.0.0
*
* @param int|null $intDay
* @param int $mode
* @param string $jsonFilePath
*
* @return string
* @return array
*/
function jddayofweek(?int $intDay = null, int $mode = 0): string
function translations(string $jsonFilePath): array
{
if (is_null($intDay)) {
$intDay = date('l');
if (! file_exists($jsonFilePath)) {
return [];
}
if ($mode === 0) {
return $intDay;
$payload = [];
$jsonData = json_decode(file_get_contents($jsonFilePath), true);
switch (json_last_error()) {
case JSON_ERROR_NONE:
$payload = $jsonData;
break;
case JSON_ERROR_DEPTH:
throw new \Exception('Maximum stack depth exceeded');
break;
case JSON_ERROR_STATE_MISMATCH:
throw new \Exception('Underflow or the modes mismatch');
break;
case JSON_ERROR_CTRL_CHAR:
throw new \Exception('Unexpected control character found');
break;
case JSON_ERROR_SYNTAX:
throw new \Exception('Syntax error, malformed JSON');
break;
case JSON_ERROR_UTF8:
throw new \Exception('Malformed UTF-8 characters, possibly incorrectly encoded');
break;
default:
throw new \Exception('Generic or unknown JSON error while decoding');
break;
}
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][$intDay];
return $payload;
}
}
@ -84,25 +172,25 @@ if (! function_exists('is_serialized')) {
}
$data = trim($data);
if ('N;' === $data) {
if ($data === 'N;') {
return true;
}
if (strlen($data) < 4) {
return false;
}
if (':' !== $data[1]) {
if ($data[1] !== ':') {
return false;
}
if ($strict) {
$lastc = substr($data, -1);
if (';' !== $lastc && '}' !== $lastc) {
if ($lastc !== ';' && $lastc !== '}') {
return false;
}
} else {
$semicolon = strpos($data, ';');
$brace = strpos($data, '}');
// Either ; or } must exist.
if (!$semicolon && !$brace) {
if (! $semicolon && ! $brace) {
return false;
}
// But neither must be in the first X characters.
@ -117,10 +205,10 @@ if (! function_exists('is_serialized')) {
switch ($token) {
case 's':
if ($strict) {
if ('"' !== substr($data, -2, 1)) {
if (substr($data, -2, 1) !== '"') {
return false;
}
} elseif (!strpos($data, '"')) {
} elseif (! strpos($data, '"')) {
return false;
}
// Or else fall through.
@ -148,132 +236,19 @@ if (! function_exists('maybe_unserialize')) {
*
* @param mixed $data
*
* @return mixed
* @return array|string|bool
*/
function maybe_unserialize($data)
{
if (is_serialized($data)) { // Don't attempt to unserialize data that wasn't serialized going in.
return @unserialize(trim($data));
if (! is_string($data)) {
return false;
}
$data = trim($data);
// Don't attempt to unserialize data that wasn't serialized going in.
if (is_serialized($data)) {
return unserialize(trim($data));
}
return $data;
}
}
if (! function_exists('cel2Fah')) {
/**
* Convert from celsius to fahrenheit.
*
* @since 1.0.0
*
* @param float|int|string $celsius
* @param int $precision
*
* @return float
*/
function cel2Fah($celsius, int $preceision = 0): float
{
return round((($celsius * (9/5)) + 32), $preceision);
}
}
if (! function_exists('fah2Cel')) {
/**
* Convert from fahrenheit to celsius.
*
* @since 1.0.0
*
* @param float|int|string $fahrenheit
* @param int $precision
*
* @return float
*/
function fah2Cel($fahrenheit, int $preceision = 1): float
{
return round(($fahrenheit - 32 * (5/9)), $preceision);
}
}
if (! function_exists('meters2Miles')) {
/**
* Convert from meters to miles.
*
* @since 1.0.0
*
* @param float|int|string $meters
* @param int $precision
*
* @return float
*/
function meters2Miles($meters, int $preceision = 1): float
{
return round(($meters * 0.00062137), $preceision);
}
}
if (! function_exists('kilometers2Miles')) {
/**
* Convert from kilometers to meters.
*
* @since 1.0.0
*
* @param float|int|string $kilometers
* @param int $precision
*
* @return float
*/
function kilometers2Miles($kilometers, int $preceision = 1): float
{
return round(($kilometers * 1.609), $preceision);
}
}
if (! function_exists('m2Km')) {
/**
* Convert from meters to kilometers.
*
* @since 1.0.0
*
* @param float|int|string $meters
* @param int $precision
*
* @return float
*/
function m2Km($meters, int $preceision = 1): float
{
return round(($meters / 1000), $preceision);
}
}
if (! function_exists('mm2Inches')) {
/**
* Convert from milimeters to inches.
*
* @since 1.0.0
*
* @param float|int|string $milimeters
* @param int $precision
*
* @return float
*/
function mm2Inches($milimeters, int $preceision = 1): float
{
return round(($milimeters / 25.4), $preceision);
}
}
if (! function_exists('pa2Mbar')) {
/**
* Convert from pascals to milibars.
*
* @since 1.0.0
*
* @param float|int|string $pascals
* @param int $precision
*
* @return float
*/
function pa2Mbar($pascals, int $preceision = 1): float
{
return round(($pascals / 100), $preceision);
}
}

View File

@ -1,3 +1,88 @@
{
"key": "translation that has :attribute in the string."
"titles": {
"welcome": "Welcome",
"dashboard": "Dashboard",
"secure_area": "Secure Area",
"forgot_password": "Forgot Password",
"my_profile": "My Profile",
"edit_profile": "Edit Profile",
"log_in": "Log In To Your Account",
"register": "Register A New Account",
"reset_password": "Reset Password",
"two_factor_confirmation": "Two-factor Confirmation",
"verify_email": "Email Verification"
},
"labels": {
"type": "Type",
"none": "None",
"title": "Title",
"name": "Name",
"created_at": "Created At",
"updated_at": "Updated At",
"actions": "Actions",
"email": "Email",
"timezone_name": "Timezone",
"language": "Language",
"password": "Password",
"confirm_password": "Confirm Password",
"current_password": "Current Password",
"remember_me": "Remember me",
"first_name": "First Name",
"last_name": "Surname",
"forgot_password": "Forgot your password?",
"already_registered": "Already registered?",
"code": "Code",
"recovery_code": "Recovery Code",
"use_recovery_code": "Use a recovery code",
"use_authentication_code": "Use an authentication code",
"email_verification": "Email Verification",
"user": "User",
"optional": "optional"
},
"actions": {
"save": "Save",
"update": "Update",
"edit": "Edit",
"delete": "Delete",
"confirm": "Confirm",
"log_in": "Log in",
"log_out": "Log Out",
"register": "Register",
"edit_profile": "Edit Profile",
"confirm_password": "Confirm Password",
"reset_password": "Reset Password",
"email_password_reset_link": "Email Password Reset Link",
"resend_verification_email": "Resend Verification Email"
},
"nav": {
"manage_team": "Manage Team",
"team_settings": "Team Settings",
"create_new_team": "Create New Team",
"switch_teams": "Switch Teams",
"manage_account": "Manage Account",
"profile": "My Profile",
"admin_settings": "Admin Settings",
"api_tokens": "API Tokens"
},
"pagination": {
"show_from_to_count": "Showing :from to :to of :count results"
},
"notifications": {
"saved": "Saved.",
"verified": "Verified!",
"unverified": "Unverified.",
"new_email_verification_sent": "A new verification link has been sent to the email address you provided in your profile settings."
},
"pages": {
"profile": {
"titles": {
"update_password": "Update Your Password"
},
"text_blocks": {
"unverified_message": "Please verify your account.",
"verified_message": "Thanks for being amazing.",
"secure_password": "Ensure your account is using a long, random password to stay secure."
}
}
}
}

View File

@ -1,34 +1,32 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.0.0",
"laravel-vite-plugin": "^0.6.0",
"postcss": "^8.4.14",
"vite": "^3.0.0"
},
"dependencies": {
"@inertiajs/inertia": "^0.11.0",
"@inertiajs/inertia-vue3": "^0.6.0",
"@inertiajs/progress": "^0.2.7",
"@tailwindcss/forms": "^0.5.2",
"@tailwindcss/aspect-ratio": "^0.4.0",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.2",
"@vueuse/core": "^8.5.0",
"@vueuse/core": "^8.7.5",
"apexcharts": "^3.35.5",
"axios": "^0.27.2",
"dayjs": "^1.11.2",
"daisyui": "^2.29.0",
"dayjs": "^1.11.3",
"laravel-vue-i18n": "^1.4.3",
"lodash": "^4.17.21",
"notiwind": "^1.2.5",
"tailwindcss": "^3.0.24",
"tailwindcss-neumorphism": "^0.1.0",
"vue": "^3.2.36"
},
"devDependencies": {
"laravel-mix": "^6.0.43",
"postcss": "^8.4.14",
"postcss-import": "^14.1.0",
"vue-loader": "^17.0.0"
"tailwindcss": "^3.1.0",
"tailwindcss-neu": "^0.2.1",
"vue": "^3.2.37"
}
}

218
src/phpcs.xml Normal file
View File

@ -0,0 +1,218 @@
<?xml version="1.0"?>
<ruleset name="Laravel Standards" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<description>PHP Codesniffer ruleset to follow Laravel's coding style</description>
<rule ref="Generic.Classes.DuplicateClassName">
<exclude name="Generic.CodeAnalysis.EmptyStatement.DetectedIf"/>
</rule>
<rule ref="Generic.CodeAnalysis.EmptyStatement"/>
<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop"/>
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
<rule ref="Generic.CodeAnalysis.JumbledIncrementer"/>
<rule ref="Generic.CodeAnalysis.UnconditionalIfStatement"/>
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter">
<exclude-pattern>/app/Http/Resources/*\.php</exclude-pattern>
<exclude-pattern>/routes/*\.php</exclude-pattern>
</rule>
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<rule ref="Generic.Commenting.DocComment">
<exclude name="Generic.Commenting.DocComment.ContentAfterOpen"/>
<exclude name="Generic.Commenting.DocComment.ContentBeforeClose"/>
<exclude name="Generic.Commenting.DocComment.MissingShort"/>
<exclude name="Generic.Commenting.DocComment.NonParamGroup"/>
<exclude name="Generic.Commenting.DocComment.ParamNotFirst"/>
<exclude name="Generic.Commenting.DocComment.TagValueIndent"/>
</rule>
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
<rule ref="Generic.Files.ByteOrderMark"/>
<rule ref="Generic.Files.LineEndings">
<exclude name="Generic.Files.LineEndings.InvalidEOLChar"/>
</rule>
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<rule ref="Generic.Formatting.SpaceAfterCast"/>
<rule ref="Generic.Formatting.SpaceAfterNot"/>
<rule ref="Generic.Functions.CallTimePassByReference"/>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="Generic.Metrics.CyclomaticComplexity">
<properties>
<property name="complexity" value="20"/>
<property name="absoluteComplexity" value="25"/>
</properties>
</rule>
<rule ref="Generic.Metrics.NestingLevel">
<properties>
<property name="nestingLevel" value="5"/>
<property name="absoluteNestingLevel" value="15"/>
</properties>
</rule>
<rule ref="Generic.NamingConventions.ConstructorName"/>
<rule ref="Generic.NamingConventions.CamelCapsFunctionName">
<exclude-pattern>/helpers/global_functions\.php</exclude-pattern>
<exclude-pattern>/tests/*</exclude-pattern>
</rule>
<rule ref="Generic.PHP.LowerCaseConstant"/>
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.PHP.ForbiddenFunctions"/>
<rule ref="Generic.PHP.NoSilencedErrors"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"/>
<property name="tabIndent" value="true"/>
</properties>
</rule>
<rule ref="MySource.PHP.EvalObjectFactory"/>
<rule ref="PSR1.Classes.ClassDeclaration"/>
<rule ref="PSR1.Files.SideEffects">
<exclude-pattern>*/artisan</exclude-pattern>
</rule>
<rule ref="PSR1.Files.SideEffects"/>
<rule ref="PSR2.Classes.ClassDeclaration"/>
<rule ref="PSR2.Classes.PropertyDeclaration"/>
<rule ref="PSR2.ControlStructures.ControlStructureSpacing"/>
<rule ref="PSR2.ControlStructures.ElseIfDeclaration"/>
<rule ref="PSR2.ControlStructures.SwitchDeclaration"/>
<rule ref="PSR2.Files.EndFileNewline"/>
<rule ref="PSR2.Methods.MethodDeclaration"/>
<rule ref="PSR2.Namespaces.NamespaceDeclaration"/>
<rule ref="PSR2.Namespaces.UseDeclaration"/>
<rule ref="PSR1">
<exclude-pattern>*\.php</exclude-pattern>
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"/>
<exclude-pattern>database/*</exclude-pattern>
</rule>
<rule ref="PSR2">
<exclude name="PSR2.ControlStructures.SwitchDeclaration.BodyOnNextLineCASE" />
<properties>
<property name="lineLimit" value="130"/>
<property name="absoluteLineLimit" value="135"/>
</properties>
</rule>
<rule ref="Squiz.Arrays.ArrayDeclaration">
<exclude name="Squiz.Arrays.ArrayDeclaration.ValueNotAligned" />
<exclude name="Squiz.Arrays.ArrayDeclaration.KeyNotAligned" />
<exclude name="Squiz.Arrays.ArrayDeclaration.DoubleArrowNotAligned" />
<exclude name="Squiz.Arrays.ArrayDeclaration.ValueNotAligned" />
<exclude name="Squiz.Arrays.ArrayDeclaration.CloseBraceNotAligned" />
<exclude name="Squiz.Arrays.ArrayDeclaration.ValueNoNewline" />
<exclude name="Squiz.Arrays.ArrayDeclaration.MultiLineNotAllowed" />
<exclude name="Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed" />
<exclude name="Squiz.Arrays.ArrayDeclaration.IndexNoNewline" />
<exclude name="Squiz.Arrays.ArrayDeclaration.CloseBraceNewLine" />
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace" />
<exclude name="Squiz.Arrays.ArrayDeclaration.NoKeySpecified" />
<exclude name="Squiz.Arrays.ArrayDeclaration.KeySpecified" />
</rule>
<rule ref="Squiz.PHP.CommentedOutCode"/>
<rule ref="Squiz.PHP.DisallowSizeFunctionsInLoops"/>
<rule ref="Squiz.PHP.DiscouragedFunctions">
<properties>
<property name="error" value="true"/>
</properties>
</rule>
<rule ref="Squiz.PHP.Eval"/>
<rule ref="Squiz.PHP.GlobalKeyword"/>
<rule ref="Squiz.PHP.Heredoc"/>
<rule ref="Squiz.PHP.LowercasePHPFunctions"/>
<rule ref="Squiz.PHP.NonExecutableCode"/>
<rule ref="Squiz.Scope.MemberVarScope"/>
<rule ref="Squiz.Scope.MethodScope"/>
<rule ref="Squiz.Scope.StaticThisUsage"/>
<rule ref="Squiz.WhiteSpace.CastSpacing"/>
<rule ref="Squiz.WhiteSpace.ControlStructureSpacing"/>
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
<rule ref="Squiz.WhiteSpace.ObjectOperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
<properties>
<property name="ignoreNewlines" value="true"/>
</properties>
</rule>
<rule ref="Squiz.WhiteSpace.PropertyLabelSpacing"/>
<rule ref="Squiz.WhiteSpace.ScopeClosingBrace"/>
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<rule ref="Squiz.Strings.DoubleQuoteUsage.NotRequired"/>
<rule ref="Zend.Files.ClosingTag"/>
<!-- Custom Sniffs -->
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
<properties>
<property name="searchAnnotations" value="true"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Namespaces.UseFromSameNamespace"/>
<rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses">
<properties>
<property name="caseSensitive" value="true"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameInAnnotation"/>
<rule ref="SlevomatCodingStandard.PHP.UselessSemicolon"/>
<rule ref="SlevomatCodingStandard.Classes.MethodSpacing">
<properties>
<property name="minLinesCount" value="1"/>
<property name="maxLinesCount" value="1"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Functions.ArrowFunctionDeclaration">
<properties>
<property name="spacesCountAfterKeyword" value="1"/>
<property name="spacesCountBeforeArrow" value="1"/>
<property name="spacesCountAfterArrow" value="1"/>
<property name="allowMultiLine" value="true"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
<properties>
<property name="rootNamespaces" type="array">
<element key="app" value="App"/>
<element key="database/factories" value="Database\Factories"/>
<element key="database/seeders" value="Database\Seeders"/>
<element key="tests" value="Tests"/>
</property>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
<exclude-pattern>/database/schema/*</exclude-pattern>
<exclude-pattern>/database/migrations/*</exclude-pattern>
</rule>
<file>./app</file>
<file>./config</file>
<file>./resources</file>
<file>./routes</file>
<file>./tests</file>
<exclude-pattern>*/.phpstorm.meta.php</exclude-pattern>
<exclude-pattern>*/_ide_helper.php</exclude-pattern>
<exclude-pattern>*/cache/*</exclude-pattern>
<exclude-pattern>*/config/*</exclude-pattern>
<exclude-pattern>*/database/*</exclude-pattern>
<exclude-pattern>*/docs/*</exclude-pattern>
<exclude-pattern>*/migrations/*</exclude-pattern>
<exclude-pattern>*/storage/*</exclude-pattern>
<exclude-pattern>*/public/index.php</exclude-pattern>
<exclude-pattern>*/resources/lang/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/*.js</exclude-pattern>
<exclude-pattern>*/*.css</exclude-pattern>
<exclude-pattern>*/*.xml</exclude-pattern>
<exclude-pattern>*/*.blade.php</exclude-pattern>
<exclude-pattern>*/autoload.php</exclude-pattern>
<exclude-pattern>*/Console/Kernel.php</exclude-pattern>
<exclude-pattern>*/Exceptions/Handler.php</exclude-pattern>
<exclude-pattern>*/Http/Kernel.php</exclude-pattern>
<arg name="basepath" value="."/>
<arg name="colors"/>
<arg value="nspv"/>
<ini name="memory_limit" value="128M"/>
</ruleset>

6
src/postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,94 @@
Copyright (c) 2010-2015, Łukasz Dziedzic (dziedzic@typoland.com),
with Reserved Font Name Lato.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,93 @@
Copyright 2014 The Nunito Project Authors (https://github.com/googlefonts/nunito)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -0,0 +1,93 @@
Copyright (c) 2011, Denis Masharov (denis.masharov@gmail.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -0,0 +1,95 @@
Copyright (c) 2010, Matt McInerney (matt@pixelspread.com),
Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),
Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,93 @@
Copyright (c) 2021, Rune Bjørnerås (https://github.com/rubjo)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -6,6 +6,13 @@
to { transform: rotate(360deg); }
}
/** **/
@keyframes disco {
from { transform: translateY(-50%) rotate(0deg); }
to { transform: translateY(-50%) rotate(360deg); }
}
/** **/
.animate-removeRow {
animation-name: removeRow;
animation-fill-mode: forwards;

View File

@ -0,0 +1,59 @@
/**
<div class="bubbles-container">
<div class="bubbles">
<span class="animate-bubble" style="style="--i:(random value between 1 and 15);"></span>
<span class="animate-bubble" style="style="--i:(random value between 1 and 15);"></span>
<span class="animate-bubble" style="style="--i:(random value between 1 and 15);"></span>
<span class="animate-bubble" style="style="--i:(random value between 1 and 15);"></span>
<span class="animate-bubble" style="style="--i:(random value between 1 and 15);"></span>
</div>
</div>
**/
.bubbles-container {
background: hsl(216, 57.1%, 11%);
min-height: 100%;
overflow: hidden;
position: relative;
width: 100%;
}
.bubbles {
position: relative;
display: flex;
}
.bubbles span {
border-radius: 50%;
height: 30px;
margin: 0 4px;
position: relative;
width: 30px;
/*animation: bubble 15s linear infinite;*/
/*animation-name: bubbleup;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: calc(300s / calc(var(--i) * 5));*/
}
.bubbles span:nth-child(odd) {
background: hsl(191, 66.8%, 58.6%);
box-shadow: 0 0 0 10px hsla(191, 66.8%, 58.6%, 0.3), 0 0 50px hsl(191, 66.8%, 58.6%), 0 0 100px hsl(191, 66.8%, 58.6%);
}
.bubbles span:nth-child(even) {
background: hsl(339, 100%, 58.8%);
box-shadow: 0 0 0 10px hsla(339, 100%, 58.8%, 0.3), 0 0 50px hsl(339, 100%, 58.8%), 0 0 100px hsl(339, 100%, 58.8%);
}
.animate-bubble {
animation-name: bubbleup;
animation-duration: calc(300s / calc(var(--i) * 5));
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes bubbleup {
0% { transform: translateY(100px) scale(0); }
100% { transform: translateY(-100px) scale(1); }
}

View 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;
}
}

View File

@ -2,35 +2,104 @@
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
@import 'variables.css';
@import 'utilities.css';
@import 'animations.css';
@import 'extends/grid.css';
@import 'animations.css';
@import 'fontfaces.css';
@import 'typography/font-faces.css';
@import 'typography/text-shadows.css';
@import 'components/buttons.css';
@import 'elements/buttons.css';
@import 'elements/forms.css';
@import 'elements/links.css';
@import 'elements/pre-codes.css';
@import 'elements/progress-bars.css';
@import 'elements/tables.css';
@import 'components/accordian-menus.css';
@import 'components/alerts.css';
@import 'components/breadcrumbs.css';
@import 'components/cards.css';
@import 'components/forms.css';
@import 'components/tables.css';
@import 'components/modals.css';
@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 {
transition-duration: 0.05s;
transition-timing-function: ease-in-out;
}
html, body {
transition-property: background, color;
transition-timing-function: ease-in-out;
}
button, a {
transition-property: all;
}
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;

View File

@ -0,0 +1 @@
.accordian {}

View File

@ -0,0 +1 @@
.alert {}

View File

@ -0,0 +1 @@
.breadcrumbs {}

View File

@ -0,0 +1,3 @@
.modal {}
.dialog {}

Some files were not shown because too many files have changed in this diff Show More