From 715224653ddf6505ebd9eb8cd8fbbd87c427445d Mon Sep 17 00:00:00 2001 From: Neill Cox Date: Wed, 26 Jun 2024 14:29:06 +1000 Subject: [PATCH] Initial Commit --- .gitignore | 4 + django_gurps/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 163 bytes .../__pycache__/settings.cpython-312.pyc | Bin 0 -> 3366 bytes django_gurps/__pycache__/urls.cpython-312.pyc | Bin 0 -> 1663 bytes django_gurps/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 661 bytes django_gurps/asgi.py | 16 + django_gurps/settings.py | 157 ++ django_gurps/urls.py | 29 + django_gurps/views.py | 1 + django_gurps/wsgi.py | 16 + gurps_character/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 166 bytes .../__pycache__/admin.cpython-312.pyc | Bin 0 -> 444 bytes .../__pycache__/apps.cpython-312.pyc | Bin 0 -> 489 bytes .../__pycache__/forms.cpython-312.pyc | Bin 0 -> 1500 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 20008 bytes .../__pycache__/urls.cpython-312.pyc | Bin 0 -> 613 bytes .../__pycache__/views.cpython-312.pyc | Bin 0 -> 3465 bytes gurps_character/admin.py | 7 + gurps_character/apps.py | 6 + gurps_character/forms.py | 28 + gurps_character/migrations/0001_initial.py | 28 + .../migrations/0002_gurpscharacter_details.py | 18 + gurps_character/migrations/0003_gamesystem.py | 28 + gurps_character/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 981 bytes ...002_gurpscharacter_details.cpython-312.pyc | Bin 0 -> 781 bytes .../0003_gamesystem.cpython-312.pyc | Bin 0 -> 1034 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 177 bytes gurps_character/models.py | 391 ++++ .../templates/characters/details.css | 1037 +++++++++++ .../templates/characters/details.html | 1626 +++++++++++++++++ .../templates/characters/embedded.html | 1601 ++++++++++++++++ .../templates/characters/list.html | 18 + .../templates/characters/upload.html | 7 + gurps_character/templates/home.html | 8 + gurps_character/templates/navbar.html | 48 + .../templates/registration/login.html | 38 + gurps_character/tests.py | 3 + gurps_character/urls.py | 10 + gurps_character/views.py | 67 + gurps_vars.sh | 5 + manage.py | 22 + notes.txt | 41 + requirements.txt | 4 + theme/__init__.py | 0 theme/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 156 bytes theme/__pycache__/apps.cpython-312.pyc | Bin 0 -> 399 bytes theme/apps.py | 5 + theme/static/css/dist/styles.css | 841 +++++++++ theme/static_src/.gitignore | 1 + theme/static_src/package-lock.json | 1527 ++++++++++++++++ theme/static_src/package.json | 28 + theme/static_src/postcss.config.js | 7 + theme/static_src/src/styles.css | 3 + theme/static_src/tailwind.config.js | 57 + theme/templates/base.html | 27 + 58 files changed, 7760 insertions(+) create mode 100644 .gitignore create mode 100644 django_gurps/__init__.py create mode 100644 django_gurps/__pycache__/__init__.cpython-312.pyc create mode 100644 django_gurps/__pycache__/settings.cpython-312.pyc create mode 100644 django_gurps/__pycache__/urls.cpython-312.pyc create mode 100644 django_gurps/__pycache__/wsgi.cpython-312.pyc create mode 100644 django_gurps/asgi.py create mode 100644 django_gurps/settings.py create mode 100644 django_gurps/urls.py create mode 100644 django_gurps/views.py create mode 100644 django_gurps/wsgi.py create mode 100644 gurps_character/__init__.py create mode 100644 gurps_character/__pycache__/__init__.cpython-312.pyc create mode 100644 gurps_character/__pycache__/admin.cpython-312.pyc create mode 100644 gurps_character/__pycache__/apps.cpython-312.pyc create mode 100644 gurps_character/__pycache__/forms.cpython-312.pyc create mode 100644 gurps_character/__pycache__/models.cpython-312.pyc create mode 100644 gurps_character/__pycache__/urls.cpython-312.pyc create mode 100644 gurps_character/__pycache__/views.cpython-312.pyc create mode 100644 gurps_character/admin.py create mode 100644 gurps_character/apps.py create mode 100644 gurps_character/forms.py create mode 100644 gurps_character/migrations/0001_initial.py create mode 100644 gurps_character/migrations/0002_gurpscharacter_details.py create mode 100644 gurps_character/migrations/0003_gamesystem.py create mode 100644 gurps_character/migrations/__init__.py create mode 100644 gurps_character/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 gurps_character/migrations/__pycache__/0002_gurpscharacter_details.cpython-312.pyc create mode 100644 gurps_character/migrations/__pycache__/0003_gamesystem.cpython-312.pyc create mode 100644 gurps_character/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 gurps_character/models.py create mode 100644 gurps_character/templates/characters/details.css create mode 100644 gurps_character/templates/characters/details.html create mode 100644 gurps_character/templates/characters/embedded.html create mode 100644 gurps_character/templates/characters/list.html create mode 100644 gurps_character/templates/characters/upload.html create mode 100644 gurps_character/templates/home.html create mode 100644 gurps_character/templates/navbar.html create mode 100644 gurps_character/templates/registration/login.html create mode 100644 gurps_character/tests.py create mode 100644 gurps_character/urls.py create mode 100644 gurps_character/views.py create mode 100644 gurps_vars.sh create mode 100755 manage.py create mode 100644 notes.txt create mode 100644 requirements.txt create mode 100644 theme/__init__.py create mode 100644 theme/__pycache__/__init__.cpython-312.pyc create mode 100644 theme/__pycache__/apps.cpython-312.pyc create mode 100644 theme/apps.py create mode 100644 theme/static/css/dist/styles.css create mode 100644 theme/static_src/.gitignore create mode 100644 theme/static_src/package-lock.json create mode 100644 theme/static_src/package.json create mode 100644 theme/static_src/postcss.config.js create mode 100644 theme/static_src/src/styles.css create mode 100644 theme/static_src/tailwind.config.js create mode 100644 theme/templates/base.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2d3c5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +db.sqlite3 +.idea/ +.venv/ +.hidden_notes.txt diff --git a/django_gurps/__init__.py b/django_gurps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_gurps/__pycache__/__init__.cpython-312.pyc b/django_gurps/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9dcecdee09fbe88be8b25163c3a823101e252b37 GIT binary patch literal 163 zcmX@j%ge>Uz`(Hl`0P{={TM``gU>7s3=Gp5Dj75x{Z=v*F)=VOd=YR8Wk{iI30B%PfhH*DI*}#bJ}1 gpHiBWYFEU{z`(%Bz`#%pVtiy~WMnL2W?*0d0B3V4?*IS* literal 0 HcmV?d00001 diff --git a/django_gurps/__pycache__/settings.cpython-312.pyc b/django_gurps/__pycache__/settings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5dae05865aac1183b864886896eb2efd30e72667 GIT binary patch literal 3366 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 R`LTZc^ZK2Wnz;@D{{XCB#PR?D literal 0 HcmV?d00001 diff --git a/django_gurps/asgi.py b/django_gurps/asgi.py new file mode 100644 index 0000000..a38cee8 --- /dev/null +++ b/django_gurps/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for django_gurps project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_gurps.settings") + +application = get_asgi_application() diff --git a/django_gurps/settings.py b/django_gurps/settings.py new file mode 100644 index 0000000..04ce47d --- /dev/null +++ b/django_gurps/settings.py @@ -0,0 +1,157 @@ +""" +Django settings for django_gurps project. + +Generated by 'django-admin startproject' using Django 5.0.1. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +import os +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-x%rs&gy9iphje-l+!^!g@s@w$4@oc0^honvnr-!edwm+uujiu2" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [ + "gcs.neill.id.au", + "localhost", + "127.0.0.1", + ] + +CSRF_TRUSTED_ORIGINS = [ + "https://gcs.neill.id.au", + ] + + +# Application definition + +INSTALLED_APPS = [ + "gurps_character", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "tailwind", + "theme", + "django_browser_reload", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django_browser_reload.middleware.BrowserReloadMiddleware", +] + +ROOT_URLCONF = "django_gurps.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "django_gurps.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.0/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.0/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.environ["GURPS_DATABASE_NAME"], + "USER": os.environ["GURPS_DATABASE_USER"], + "PASSWORD": os.environ["GURPS_DATABASE_PASSWORD"], + "HOST": os.environ["GURPS_DATABASE_HOST"], + "PORT": os.environ["GURPS_DATABASE_PORT"], + } +} + +TAILWIND_APP_NAME = 'theme' + +INTERNAL_IPS = [ + "127.0.0.1", +] + +LOGIN_REDIRECT_URL = "home" +LOGOUT_REDIRECT_URL = "home" diff --git a/django_gurps/urls.py b/django_gurps/urls.py new file mode 100644 index 0000000..438814d --- /dev/null +++ b/django_gurps/urls.py @@ -0,0 +1,29 @@ +""" +URL configuration for django_gurps project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import include, path +from django.views.generic.base import TemplateView +from django.contrib.auth import views + +urlpatterns = [ + path("gurps/", include("gurps_character.urls")), + path("admin/", admin.site.urls), + path("__reload__/", include("django_browser_reload.urls")), + path("accounts/", include("django.contrib.auth.urls")), + path("", TemplateView.as_view(template_name="home.html"), name="home"), + path('logout/', views.LogoutView.as_view(), name='logout'), +] diff --git a/django_gurps/views.py b/django_gurps/views.py new file mode 100644 index 0000000..8ebfb7f --- /dev/null +++ b/django_gurps/views.py @@ -0,0 +1 @@ +def logout(request): diff --git a/django_gurps/wsgi.py b/django_gurps/wsgi.py new file mode 100644 index 0000000..7ba244a --- /dev/null +++ b/django_gurps/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for django_gurps project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_gurps.settings") + +application = get_wsgi_application() diff --git a/gurps_character/__init__.py b/gurps_character/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gurps_character/__pycache__/__init__.cpython-312.pyc b/gurps_character/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36d9788591b30888dc3cb3490988ee97f4634343 GIT binary patch literal 166 zcmZ9CyA8rH6h*HINC+u|(C`*ObhIcNJXwyFj}kk2b|f+h1rsn!#$W=JE)_B*r#R;p zch2(z0Py^@sqdtJmMwq>CLGo61=#>t(r3L=?R!hk_&XKiTWeyV!b@CDboD(CLNM5*3Fqx2x#RXW>|Vf>RyG!P{(&Ht zDf|d4K~W9_!781QLP#Z>7$l`rJl+hJUODr(Ks zlXmB55b7|>Nf&-Il++oUoMbE5C~6`Jv%YFXD$8|zrtN=4St>!P(H;O@wu)=woQjI3 zer$5mcbM5@^FuyRl6V%WbKce}p(r=JP1>j|O!+dp*B|Mj;fvXeRz3KlWMepnE0!?-9>IeWHfB{1SBIF|k z7zV)b9GJz?t5weVcxF4bPg6K3-|QtxU&iBU7_9kBpsHAP3Qi6_V&G$je2Zb`8a zcLteCbbmq>4N|U3mb)&yrg11;cI8HraiQJwY1qqBc{$~R<=deFkzkD)I<>q`NK7M6 zNZueMk}MM@ZxM2nQBiev86VS3q=aUvB;$h1HoX^E8LhuPZz3b^#eux_MoM1uAl2T8 zD=lLxyiyb?mV5sscr;10o6M9kvUqF&&}{&i!*c)l&E8u!5AH9N`6>EC$I6@4od&Fo qwI#e|vSM({sH&fq_nfJn%2jO~{jv~3?{N6Nfl>GIHs(Y*J4-^_da ze(mjz0KhNfKQPF^pJEf3+I9}_0@wrvB{p*6E7_zZ3}*_KO6P9dPmDsrlX+o0+y zXb+Q$u>h)L+j7g#g{s5|Jr|p-K|FQJ;U(7~Ug8tWE>NpdaLPA1cX*z3a(zW2|8SBB zMRgRr4g;fPb^_qhN}CCw(smnVg@jQF?uBAckkhd`is8;KuVzt10W3>( ziH2q+fG4^*wYu~eH2j?$1-M2eTX=6gfm-}l!Df2Jadg|_)2wzb>r`}0zy1Cl zeM+2M)QhfD)+x(7lzE{A#@&Kb<`RI~!2e=rSygAElF!A>YstGatOe7~(_gP$HS~h( z6FN3c>613IT&B;vOtGKk;hm4O6TVWvojmO$R&9C8{W*Hy3%jghR=AaChT^FUmOalrg<2Jhi{{{Q0ImSn zbzMImPtQ0dmM-U=rSv3siY#Ao)02$5PT8{4v}l#59dmk~&$(%THS;qTxAGOn(|&)a z=Bi%rLaV`?O~vS2xmYp=JbHV*T{W7yI$Sz2xxLr&}L1E>1O0 zO&`iqBH4r#PBvv|eSaVIA$IDI==tBG=MO;CQJ*Wb8^7Mrt~X_(j{b8LL9G7(lA3v{ z^{r2AW;e1=`iK3vcX#908rrp{Dyf-c_eB8T4vh_92kKY`I|Jv(uF5+ZWBh`g@9xIn zcRYOCA14esLXndsFuAC82eyo<)8r=-v}vxVDjBjDzc(kUD;o5c!%GJ7BJJmNxSKUX zo@Sb5tHeyxiT4d)0l#eF_9BY}@1xER+0K^1yhX6EXLda7@pW&rvxOC8yB*~)@Lawae+stj` L{sJLae2{+u72aAH literal 0 HcmV?d00001 diff --git a/gurps_character/__pycache__/models.cpython-312.pyc b/gurps_character/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30c54f8c2ec5ee72f23a8ba8f1e8877805d10422 GIT binary patch literal 20008 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 literal 0 HcmV?d00001 diff --git a/gurps_character/__pycache__/urls.cpython-312.pyc b/gurps_character/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39ad7176b925fa4b381fb3167aef4a91df14af05 GIT binary patch literal 613 zcmZvYziSjh6vyA(%--#0vnn|S3ptxWxF*vmh=hZbHX)557vvajo_D*<{$OU;OVZh$ zm3CStjY)__{sem)g#*cgm83`)Nta6IHiusDTYP!%J0IQ~-q#>l00209`3YADz%Sd( zbmP3FdxP_k zMvL=|mGo|K3rM3||Ka?<+<^9d(J_yADld!u+AxS$M@eq{?T0i-dsL>GGULV$iuyR2d(|qNi<>W O7oKyw_QuzD0N@V{0hVn5 literal 0 HcmV?d00001 diff --git a/gurps_character/__pycache__/views.cpython-312.pyc b/gurps_character/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d91d593cd9e80a4f58cdc22fe5c57fb09f00fc3 GIT binary patch literal 3465 zcmbtWOKcm*8UAN?mJcn(hsDTNWLdJDNTE`TaGTh&{3;?@vW!MHEawoSs6cZ@(lSdf zJG;~i%YX(1L_z~tK@V1n0!c5e3=61^Jtpa)1$rS%wIVhOYM{*_H$(0ra4*H|a+k88 zwrKkUTJFw{{+XTc@&A8lZEXPn_{a1wX@3CVul&Icp>gvp3jhy+06{9G_^+U%oRAU_ zzZX?8hf_Ewr6l_qtG=8+7B)9^pR?@NpsW6dO zAQd5@6-Y&wP@?r4zVKuMSw2SdgtCNSg>D!|;SSXcT3)AC{NU3aN)$#jMgm!WM&~Kh z={E=f637aVzjNpI)W}?#r85R)eB_;is-?-8qS7&q_hRm@mxX#nMgq;!Gx^u&?EpL!h5d)upb&h_niq@8;2Legly==5gv~lyD5pL zn2j9qzA?nk8!`9o(V2+Y!SglF0D;lw&Np6i?+A9^yT4P=+_$?H--{^_=`sKq$KC%m zf%r_}F+WoPn1Y0V(rU@LXy_KceQWBjg=Z9%T9T3{bkV{y8p|!mo0F2Nq8o#AMovwH zSO5SlzjiN6Glp)7X;rm+Icm&lgz=+f{Io1-Y~lykr>uaYPtT`Sg;?>qbe^bmx@bdB z$uwV(ar_tuhw=R-FelHCi&Qt5Y_F2h@&;Wr7(Zbh13*ttPtWtWl5<*)Ci59>F?pM5 z_C}JoDbuxlT1}E{IzOvT&lXuhPukaM?@N;N3SH0#3rj4_7v&cYx&9LXD8pW?dpFi! zjrH%wUa!Vpuf@)mZ`LE78#gQA{_^+}fB1v<@4vs%{zrfJUZiVd_7nAEb#wgJZ$Emw z78zc}bvg3j%G#9=ukD3;K0W@cu3vO*&R0*L-w9pVYwO?gZ~JSn4b|E%Rzes57U`-* zx>xa&_Ls}!t7G?X?a8tA{z~V$?F%*eQUzan#-Yj_B)lgJV%xxfFAEcGA(uQQfe5Cc zppt0#9a;dViD-%kXo4pnAqy9a3bBIT`7NLDZuKP1-J^t1;t&Jd#9&d5n>b622BNH; zAM{Cn>Eaj8OAkqQ!bX`;Bdw@9>jnTW2K|BqNA%Qgw67ZN+l>xXqXXNx5*?^T-z-l& ziM+fqQ3>~z$N%nw&@p~=Z*DKtcM`r?e(!)WJ?FLguLnr(| zvYc>-;%G1N+yI#<>-kADT!pf;2IsXMM`t3!Avb7s=M&L|Zwi{bbTgNb;kl3r1QUsS z-vKy%leRD!&$rx~)Qg!6)%9eNsmbN`1E4zkv>~-smk6+995+wejQbOd^9%PUN5Zyx z1qW+etDL(%4SZ!Mr=$4O0MN@Z&e#~&{~u9pMrv(CmC%r@r-qEaw>|S4vi+l)JX*n{ z|Ar4gvnvci1XQq*^RRD*d%lR{bwsrxo~RHs#gye9c_>WCde}F^&F^Ac5=_D2K#6;~ zT^k7IoG9TS7+xjHa_c%2S+CMG!xXn9FSle0rZnyG)5NAU?NvNe%6c`U8SefNEWw$B z>vQEEidTT0M$lxeDVo?6wtOxNOVWQ@<6T&S1y~f{g$0!GPcqITOHhdAFEGunP&l8? zQP#dkte{SfX@jLR)WSNY?^!sjYk5oJJ%?^#M$@F}RqT}e z|8^z|>*;xFg+?{1Pin^XMMXCfJ`2sTKE4-B(nk8gy4=!qZZNzqHTdqxf@|YD{OzXA z^Dl8^9X||z6yAyU)Uouz*!{89b1M^ja^%7A+VFb%;mk)fKb@<|-R03Ia%3H^4VOpj za%4TYc5UN)Rqid1KK1#fj=gyAZhW8`AJ~l#R^x-)qm}qzEq-w|SU=gb8r%tV)H}LX zgCBc0jylTEU!>qxQ-+*Q@|*wBI^6qbBLB0MQomoZ;*|09@tFyX!b?w7)#@ zFH7lOr1R&apWOWT=BG=${X^CMq1wrdzYp$2?v!uT`$j%fewY6|U+ueFzENrIt>QCv zxvhN5w$wz-`Gly`ZVl>l8Z$CQL$_;zB{zoW45Q$DFyF5?Tx6 10**6: + raise ValidationError("File too large") + + try: + data = json.loads(value.read()) + except json.JSONDecodeError: + raise ValidationError("Not a GCS file - json decode") + + try: + version = data['version'] + except KeyError: + import bpdb;bpdb.set_trace() + raise ValidationError("Not a GCS file - key error") + + if version < 4: + raise ValidationError( + f"The file version ({version}) is too old. Please use a newer version (5.20.3) of GCS." + ) + + +class UploadFileForm(forms.Form): + file = forms.FileField(validators=[validate_file]) diff --git a/gurps_character/migrations/0001_initial.py b/gurps_character/migrations/0001_initial.py new file mode 100644 index 0000000..581e4bd --- /dev/null +++ b/gurps_character/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.1 on 2024-01-08 10:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="GURPSCharacter", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("uuid", models.CharField(max_length=128, unique=True)), + ("name", models.CharField(max_length=255, unique=True)), + ], + ), + ] diff --git a/gurps_character/migrations/0002_gurpscharacter_details.py b/gurps_character/migrations/0002_gurpscharacter_details.py new file mode 100644 index 0000000..f1f69a9 --- /dev/null +++ b/gurps_character/migrations/0002_gurpscharacter_details.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.1 on 2024-01-10 07:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("gurps_character", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="gurpscharacter", + name="details", + field=models.JSONField(default={}), + preserve_default=False, + ), + ] diff --git a/gurps_character/migrations/0003_gamesystem.py b/gurps_character/migrations/0003_gamesystem.py new file mode 100644 index 0000000..b26628c --- /dev/null +++ b/gurps_character/migrations/0003_gamesystem.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.1 on 2024-01-16 07:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("gurps_character", "0002_gurpscharacter_details"), + ] + + operations = [ + migrations.CreateModel( + name="GameSystem", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255, unique=True)), + ("description", models.TextField(null=True)), + ], + ), + ] diff --git a/gurps_character/migrations/__init__.py b/gurps_character/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gurps_character/migrations/__pycache__/0001_initial.cpython-312.pyc b/gurps_character/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b48ce8a1ea44a16e458bc512fe636c13c1a42744 GIT binary patch literal 981 zcmZ`%&ubGw82x5*~OD@AUGu>|7AL;C_G@dF{ z@YtJze}S|IFW!3>p#dRbPJ*Z20;vdIl-V>^p?-(q&CYu}-+SMD8XwmI06ub*UuKFRNUevhI0Ho~zz~DH<LX5s7nOZWe4ht1T@n${uT_2NJN%^jy3a_oFRgU zLNZ6{p)x$(lE_%fE?&aU5_F^;N`IL8f0?;|nT~v9jC2mF>+NxKf@>=yzZ-m__Vmfx z`tr8T>_$u(mt0ci(!&R)!VNo#L)>80jw#`}7IS@@wed6B=2}FVYkTes%8logZH5uW zf$dYSB#BE-_eQzeyV#?F6K``h3EZ88az)Tif29N_ta5eBr5=e^%^c6-^e-559b-Qv zi6^ju@lIlULWnURa|1VaZI2s-wrD_T&~RzQ#9(=DIc;`DjF5?3xpCih?j>bZcDh%%*;iq* z(ksm$RJ*15PHDb(%k0hF?#&8tre!9}{Y=&VU?WAJ9Eq5zsr(%9sKQ4W#R8R7? zUSaCe@BJyGG;x->qUn9PP*h(&Vl$(@R!xO#Lw5^gGYvA$ZrJ&>prza!BBSix;aHZ~ kEC3*3={f-PWrWZV6_9zRmXUg(ck^?d{M>gaBQ;h32GhO!hyVZp literal 0 HcmV?d00001 diff --git a/gurps_character/migrations/__pycache__/0002_gurpscharacter_details.cpython-312.pyc b/gurps_character/migrations/__pycache__/0002_gurpscharacter_details.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79d2c458572f70ba7d395d91be55bd2e6f330360 GIT binary patch literal 781 zcmZ8f&ubGw6n?Y6vb&@;E<)ARODM`BWVby_!ApfwW5L^AhV9NY-LSu$-AHp&=)q%e z-aLwu{u$mp1%!k-37)(KQV~4K%qE8V4#W4&dvE4_-^|yI4I2R9%h3n=5dr)VWEJ`n zEcOB5JrE!$ffNNORRRTp0?&Xb7eG{s2F9vs9b>h|fjZJ${ih(V!tFHfv#^TutmHa&T^wg|6^9Aml<9T0L1-1mN$Da1Ps3qS z9k?2|r7)a@Ddn16_0yOpgtrPtOUhnTysYlI7B{i1#F*O{r#TrW0yi;!H4GEcEf}E% z%?Qn+n3ha9%gv{R9EekyP{ggnmoIvfb2~5S(&Nvt5OV)S-dUbfFN^YX@0jHS8dart zOj(&{Vd9ZNnDuik#d-fZ;H@9b^L>A>uKH&IUOLb%MofGHxd>2-UvmN9&Bt?9xnsOJ zn%iJ)zq6-idt$a{TaRY9@6Vjh<-@7dnK+$Kd*7Vy>_O++(k*+gHXP&aA-lUeu;*&r zs;BId6RBUSuCLq@WwQ33&}u%ZP26W~01!`KZUewvMF{;i0J+yj6B(EGw6!y7?fil! HGGzB(D%i^x literal 0 HcmV?d00001 diff --git a/gurps_character/migrations/__pycache__/0003_gamesystem.cpython-312.pyc b/gurps_character/migrations/__pycache__/0003_gamesystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c7536a67def79c368aa2ee210a501c55e28dd07 GIT binary patch literal 1034 zcmZ8f&ubGw6n?Y2S(8oLCLxUmwZ;;u3(_ol(^Ak%f?`Xdf{@Fy%}h5N_eVOrk;ao^ z4<38dqbEU*0O6&J6h#$JU z-0Dz1yy3!${|*55;Ya-bNECANn`a{h5;xu}gZM%}zA(&OAIUIZ80MA^DudioKesfz zr4CEChl`w?C1UgWQ7oRxj@^4q8MW>nRNDzU`)d&_t`G&S^bTz8SnLhT|qDZVo9 n%qlGb0H06)8UTz$gwSspka{NPk$j*G(xra7^b7Jx4zvFOqw5c8 literal 0 HcmV?d00001 diff --git a/gurps_character/migrations/__pycache__/__init__.cpython-312.pyc b/gurps_character/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24fb52f54efc3a9635c95eaaeec38b738260e036 GIT binary patch literal 177 zcmZ9Cu?@m75JkTUNC+u|&~OVNMnKu%WI0yiD6!Gmk;o(zOu#G|g9%W&RLGRP;=Nz| zxhxL=!1L4QzO(*Wwg4WOa8%b9WCLKypS7Yk43@kJcd8_G)}%<4l^DG4sqVCI0ym@F vBK^#!)uK(ZLW65WCl`DqX6IdEKHa8ue;z_T_Vyw>0180N<5MW5qyX>*A~P>v literal 0 HcmV?d00001 diff --git a/gurps_character/models.py b/gurps_character/models.py new file mode 100644 index 0000000..cb70807 --- /dev/null +++ b/gurps_character/models.py @@ -0,0 +1,391 @@ +from django.db import models + +# Create your models here. + +class GameSystem(models.Model): + name = models.CharField(max_length=255, unique=True) + description = models.TextField(null=True) + + + +class GURPSCharacter(models.Model): + uuid = models.CharField(max_length=128, unique=True) + name = models.CharField(max_length=255, unique=True) + details = models.JSONField() + # owner => user + # campaign => campaign + + def adv_points(self): + return sum([ a['calc']['points'] for a in self.details.get('advantages',[]) if a['calc']['points'] > 0 ]) + + def disadv_points(self): + return sum([ a['calc']['points'] for a in self.details.get('advantages', []) if a['calc']['points'] < -1 ]) + + def quirks_points(self): + return sum([ a['calc']['points'] for a in self.details.get('advantages',[]) if a['calc']['points'] == -1 ]) + + def attr_points(self): + return sum([ a['calc']['points'] for a in self.details['attributes'] ]) + + def skills_points(self): + return sum([ s['points'] for s in self.details.get('skills',[]) ]) + + def spells_points(self): + return 0 + + def race_points(self): + return 0 + + def unspent_points(self): + return self.details['total_points'] - self.adv_points() - \ + self.disadv_points() - self.attr_points() - \ + self.skills_points() - self.spells_points() - \ + self.race_points() - self.quirks_points() + + def get_primary_attr(self, attr_id): + return [ a['calc'] for a in self.details['attributes'] if a['attr_id'] == attr_id ][0] + + def st(self): + return self.get_primary_attr('st') + + def iq(self): + return self.get_primary_attr('iq') + + def dx(self): + return self.get_primary_attr('dx') + + def ht(self): + return self.get_primary_attr('ht') + + def will(self): + return self.get_primary_attr('will') + + def fright_check(self): + return self.get_primary_attr('fright_check') + + def per(self): + return self.get_primary_attr('per') + + def vision(self): + return self.get_primary_attr('vision') + + def hearing(self): + return self.get_primary_attr('hearing') + + def taste_smell(self): + return self.get_primary_attr('taste_smell') + + def touch(self): + return self.get_primary_attr('touch') + + def basic_move(self): + return self.get_primary_attr('basic_move') + + def basic_speed(self): + return self.get_primary_attr('basic_speed') + + def hp(self): + return self.get_primary_attr('hp') + + def fp(self): + return self.get_primary_attr('fp') + + def weight_carried(self): + items = [ i['calc']['extended_weight'] for i in self.details['equipment'] ] + + total_weight = 0 + for i in items: + total_weight += float(i.split()[0]) + + return total_weight + + def enc_level(self): + if self.weight_carried() <= self.basic_lift(): + return 0 + elif self.weight_carried() <= self.basic_lift() * 2: + return 1 + elif self.weight_carried() <= self.basic_lift() * 3: + return 2 + elif self.weight_carried() <= self.basic_lift() * 6: + return 3 + else: + return 4 + + def enc_levels(self): + enc_level = self.enc_level() + dodge = self.details["calc"]["dodge"][0] + basic_move = self.basic_move()["value"] + return [ + { "max_load": round(self.basic_lift()), "move": basic_move, "dodge": dodge, "current": "current" * (enc_level == 0) }, + { "max_load": round(self.basic_lift()) * 2, "move": basic_move -2, "dodge": dodge -1, "current": "current" * (enc_level == 1) }, + { "max_load": round(self.basic_lift()) * 3, "move": basic_move -3, "dodge": dodge -2, "current": "current" * (enc_level == 2) }, + { "max_load": round(self.basic_lift()) * 6, "move": basic_move -4, "dodge": dodge -3, "current": "current" * (enc_level == 3) }, + { "max_load": round(self.basic_lift()) * 10, "move": basic_move -5, "dodge": dodge -4, "current": "current" * (enc_level == 4) }, + ] + + def basic_lift(self): + return float(self.details["calc"]["basic_lift"].split()[0]) + + def weight_unit(self): + return self.details['settings']['default_weight_units'] + + def lift_table(self): + return [ + {"value": round(self.basic_lift()), "label":"Basic Lift"}, + {"value": round(self.basic_lift()) * 2, "label": "One-Handed Lift" }, + {"value": round(self.basic_lift()) * 8, "label":"Two-Handed Lift"}, + {"value": round(self.basic_lift()) * 12, "label":"Shove &ersand; Knock Over"}, + {"value": round(self.basic_lift()) * 24, "label":"Running Shove & Knock Over"}, + {"value": round(self.basic_lift()) * 15, "label":"Carry on Back"}, + {"value": round(self.basic_lift()) * 50, "label":"Shift Slightly"}, + ] + + def reaction_modifiers(self): + modifiers = [] + + for a in self.details.get('advantages',[]): + if "features" in a: + for f in a["features"]: + if f["type"] == "reaction_bonus": + modifiers.append(f) + + return modifiers + def conditional_modifiers(self): + modifiers = [] + + for a in self.details.get('advantages', []): + if "features" in a: + for f in a["features"]: + if f["type"] == "conditional_modifier": + modifiers.append(f) + + return modifiers + + def weapons(self): + return [ w for w in self.details['equipment'] if "weapons" in w] + \ + [ a for a in self.details.get("advantages",[]) if "weapons" in a ] + \ + [ a for a in self.details.get("traits",[]) if "weapons" in a ] + \ + [ s for s in self.details.get("spells", []) if "weapons" in s ] + + def melee_weapons(self): + mw = [] + for item in self.weapons(): + for weapon in item["weapons"]: + if weapon["type"] == "melee_weapon": + if "description" in item: + name = item["description"] + else: + name = item["name"] + mw.append( + { + "name":name, + "usage": weapon["usage"], + "skill_level":weapon["calc"].get("level", 0), + "parry":weapon["calc"].get("parry", "No"), + "block":weapon["calc"].get("block", "No"), + "damage":weapon["calc"]["damage"], + "reach":weapon["calc"].get("reach", ""), + "strength":weapon.get("strength", " ") + } + ) + + return mw + + def ranged_weapons(self): + def muscle_range(wpn_range): + if wpn_range.startswith("x"): + ranges = wpn_range.split("/") + new_ranges = [] + for wpn_range in ranges: + wpn_range = float(wpn_range[1:]) + wpn_range = wpn_range * self.st()["value"] + wpn_range = str(wpn_range) + wpn_range = wpn_range[:wpn_range.index(".")] + new_ranges.append(wpn_range) + + return "/".join(new_ranges) + else: + return wpn_range + + + rw = [] + for item in self.weapons(): + for weapon in item["weapons"]: + if weapon["type"] == "ranged_weapon": + if "description" in item: + name = item["description"] + else: + name = item["name"] + rw.append( + { + "name":name, + "bulk": weapon.get("bulk", " "), + "usage": weapon.get("usage", " "), + "skill_level":weapon["calc"]["level"], + "damage":weapon["calc"]["damage"], + "strength":weapon.get("strength", " "), + "acc":weapon.get("accuracy", 0), + "range": muscle_range(weapon.get("range", " ")), + "rof": weapon.get("rate_of_fire", " "), + "shots": weapon.get("shots", " "), + "recoil": weapon.get("recoil", " ") + } + ) + + return rw + + def traits(self): + traits = [] + for advantage in self.details.get("advantages",[]): + cost = advantage["calc"]["points"] + name = advantage["name"] + + if "categories" in advantage and "Language" in advantage["categories"]: + levels = [ m for m in advantage['modifiers'] if "disabled" not in m ] + + notes = "" + for level in levels: + notes += f"{level['name']}" + if "notes" in level: + notes += f" ({level['notes']}); " + else: + notes += "; " + + notes = notes[:-2] + + elif "notes" in advantage: + notes = advantage["notes"] + elif "modifiers" in advantage: + notes = [ m for m in advantage['modifiers'] if m["cost"] == cost ][0]["name"] + else: + notes = "" + + traits.append({"name":name, "notes":notes, "points":cost, "reference":advantage["reference"]}) + + return traits + + def spells(self): + def get_casting_details(spell): + level = spell['calc']['level'] + + if level < 10: + descr = ( + "Ritual: Need both hands and both feet " + "free, and must speak .Time: 2x." + ) + elif level <15: + descr = ( + "Ritual: Must speak a few quiet words " + "and make a gesture." + ) + elif level < 20: + descr = ( + "Ritual: Must speak a word or two or make " + "a small gesture. May move one yard per second " + "while concentrating. Cost: -1." + ) + elif level < 25: + descr = "Ritual: None. Time: / 2 (round up). Cost: -2." + elif level < 30: + descr = ( + "Ritual: None. Time: / 4 (round up). Cost: -3." + ) + else: + delta = int((level - 25) / 5) + power = 2 + delta + divisor = 2**power + cost = 3 + delta + descr = ( + f"Ritual: None. Time: / {power} round up. Cost: " + f"-{cost}" + ) + + return descr + + + spells = [] + for spell in self.details.get('spells',[]): + notes = ( + f"{get_casting_details(spell)}
Class: {spell['spell_class']}; " + f"Cost: {spell['casting_cost']}; Maintain: {spell['maintenance_cost']}; Time: {spell['casting_time']}; Duration: {spell['duration']}; " + ) + spells.append( + { + 'name': spell["name"], + "college":", ".join(spell["college"]), + "level": spell["calc"]["level"], + "rsl":spell["calc"]["rsl"], + "points":spell["points"], + "reference":spell["reference"], + "notes":notes + } + ) + return spells + + def skills(self): + skills = [] + for skill in self.details.get('skills',[]): + skills.append({'name': skill["name"], "level": skill["calc"]["level"], "rsl":skill["calc"]["rsl"], "points":skill["points"], "reference":skill["reference"] }) + return skills + + def equipment(self): + def get_children(parent, level=1): + children = [] + + for item in parent["children"]: + equipment = { + "name": item["description"], + "uses":"", + "tech_level":item["tech_level"], + "lc":"", + "value":item["value"], + "weight":item["weight"], + "quantity":item.get("quantity",1), + "ref":item["reference"], + "ext_weight": item["calc"]["extended_weight"], + "ext_value": item["calc"]["extended_value"], + "notes": item.get("notes",""), + "equipped": item["equipped"], + "level": level + } + children.append(equipment) + + if "children" in item: + children += get_children(item, level +1) + + return children + equipment = self.details['equipment'] + + equipment_list = [] + for item in equipment: + equipment_list.append( + { + "name": item["description"], + "uses":"", + "tech_level":item["tech_level"], + "lc":"", + "level": 0, + "value":item["value"], + "weight":item["weight"], + "quantity":item.get("quantity",1), + "ref":item.get("reference",""), + "ext_weight": item["calc"]["extended_weight"], + "ext_value": item["calc"]["extended_value"], + "notes": item.get("notes",""), + "equipped": item["equipped"] + } + ) + + if 'children' in item: + equipment_list += get_children(item) + + return equipment_list + + def hit_locations(self): + try: + # v2 + return self.details["settings"]["hit_locations"]["locations"] + except KeyError: + # v4 + return self.details["settings"]["body_type"]["locations"] + diff --git a/gurps_character/templates/characters/details.css b/gurps_character/templates/characters/details.css new file mode 100644 index 0000000..4f981c6 --- /dev/null +++ b/gurps_character/templates/characters/details.css @@ -0,0 +1,1037 @@ + diff --git a/gurps_character/templates/characters/details.html b/gurps_character/templates/characters/details.html new file mode 100644 index 0000000..a8f5b86 --- /dev/null +++ b/gurps_character/templates/characters/details.html @@ -0,0 +1,1626 @@ + + + + + + + {{ name }} + + + + + + + +
+
+
+
+
Portrait
+
+
+
+
Identity
+
+
Name
+
{{ character.details.profile.name }}
+
Title
+
+
Organization
+
+
+
+
+
Miscellaneous
+
+
Created
+
{{ character.details.created_date }}
+
Modified
+
{{ character.details.modified_date }}
+
Player
+
{{ character.details.profile.player_name }}
+
+
+
+
Description
+
+
Gender
+
{{ character.details.profile.gender }}
+
Age
+
{{ character.details.profile.age }}
+
Birthday
+
{{ character.details.profile.birthday }}
+
Religion
+
+
+
+
Height
+
{{ character.details.profile.height }}
+
Weight
+
{{ character.details.profile.weight }}
+
Size
+
??
+
TL
+
{{ character.details.profile.tech_level }}
+
+
+
Hair
+
{{ character.details.profile.hair }}
+
Eyes
+
{{ character.details.profile.eyes }}
+
Skin
+
{{ character.details.profile.skin }}
+
Hand
+
{{ character.details.profile.handedness }}
+
+
+
+
{{ character.details.total_points }} Points
+
+
{{ character.unspent_points }}
+
Unspent
+
{{ character.race_points }}
+
Race
+
{{ character.attr_points }}
+
Attributes
+
{{ character.attr_points }}
+
Advantages
+
{{ character.disadv_points }}
+
Disadvantages
+
{{ character.quirks_points }}
+
Quirks
+
{{ character.skills_points }}
+
Skills
+
{{ character.spells_points }}
+
Spells
+
+
+
+
+
+
+
Primary Attributes
+
+ +
[{{ character.st.points }}]
+
{{ character.st.value }}
+
Strength (ST)
+ +
[{{ character.dx.points }}]
+
{{ character.dx.value }}
+
Dexterity (DX)
+ +
[{{ character.iq.points }}]
+
{{ character.iq.value }}
+
Intelligence (IQ)
+ +
[{{ character.ht.points }}]
+
{{ character.ht.value }}
+
Health (HT)
+ +
+
+
+
Basic Damage
+
+
[20]
+
{{ character.details.calc.thrust }}
+
Basic Thrust
+
[20]
+
{{ character.details.calc.swing }}
+
Basic Swing
+
+
+
+
Secondary Attributes
+
+ +
[{{ character.will.points }}]
+
{{ character.will.value }}
+
Will
+ +
[{{ character.fright_check.points }}]
+
{{ character.fright_check.value }}
+
Fright Check
+ +
[{{ character.per.points }}]
+
{{ character.per.value }}
+
Perception (Per)
+ +
[{{ character.vision.points }}]
+
{{ character.vision.value }}
+
Vision
+ +
[{{ character.hearing.points }}]
+
{{ character.hearing.value }}
+
Hearing
+ +
[{{ character.taste_smell.points }}]
+
{{ character.taste_smell.value }}
+
Taste & Smell
+ +
[{{ character.touch.points }}]
+
{{ character.touch.value }}
+
Touch
+ +
[{{ character.basic_speed.points }}]
+
{{ character.basic_speed.value }}
+
Basic Speed
+ +
[{{ character.basic_move.points }}]
+
{{ character.basic_move.value }}
+
Basic Move
+ +
+
+
+
Point Pools
+
+ +
[{{ character.fp.points }}]
+
{{ character.fp.current }}
+
of
+
{{ character.fp.value }}
+
Fatigue Points (FP)
+ +
[{{ character.hp.points }}]
+
{{ character.hp.current }}
+
of
+
{{ character.hp.value }}
+
Hit Points (HP)
+ +
+
+
+
+
Hit Locations
+
+
Roll
+
Location
+
DR
+ + + {% for location in character.hit_locations %} +
+
{{ location.calc.roll_range }}
+
{{ location.table_name }}
+
{{ location.hit_penalty }}
+
{{ location.calc.dr.all }}
+ {% endfor %} + +
+
+
+
Encumbrance, Move & Dodge
+
Level
+
Max Load
+
Move
+
Dodge
+ + {% for enc_level in character.enc_levels %} +
+ + + + +
+
+
+
{{enc_level.max_load }} {{character.weight_unit }}
+
{{ enc_level.move }}
+
{{ enc_level.dodge }}
+ {% endfor %} + +
+
+
Lifting & Moving Things
+ {% for lift in character.lift_table %} +
{{ lift.value }} {{ character.weight_unit }}
+
{{ lift.label }}
+ {% endfor %} +
+
+
+
+
+
+
±
+
Reaction
+ + {% for r in character.reaction_modifiers %} +
+
{{ r.amount }}
+
{{ r.situation }}
+ {% endfor %} + +
+
+
+
±
+
Condition
+ + {% for r in character.conditional_modifiers %} +
+
{{ r.amount }}
+
{{ r.situation }}
+ {% endfor %} + +
+
+
+
Melee Weapon
+
Usage
+
SL
+
Parry
+
Block
+
Damage
+
Reach
+
ST
+ + {% for w in character.melee_weapons %} +
+
+ {{ w.name }} +
+ +
+
+
{{ w.usage }}
+
{{ w.skill_level }}
+
{{ w.parry }}
+
{{ w.block }}
+
{{ w.damage }} cut
+
{{ w.reach }}*
+
{{ w.strength }}
+ + {% endfor %} +
+
+
+
Ranged Weapon
+
Usage
+
SL
+
Acc
+
Range
+
Damage
+
RoF
+
Shots
+
Bulk
+
Recoil
+
ST
+ + {% for w in character.ranged_weapons %} +
+
+ {{ w.name }} +
+ +
+
+
Thrown
+
{{ w.skill_level }}
+
{{ w.acc }}
+
{{ w.range }}
+
{{ w.damage }}
+
{{ w.rof }}
+
{{ w.shots }}
+
{{ w.bulk }}
+
{{ w.recoil }}
+
{{ w.strength }}
+ {% endfor %} +
+
+
+
Trait
+
Pts
+
+ + + +
+ + {% for trait in character.traits %} +
+
+ {{ trait.name }} +
+ + {{ trait.notes }} +
+
+
{{ trait.points }}
+
{{ trait.reference }}
+ + {% endfor %} +
+
+
+
Skill / Technique
+
SL
+
RSL
+
Pts
+
+ + + +
+ + {% for skill in character.skills %} +
+
+ {{ skill.name }} +
+ + +
+
+
{{ skill.level }}
+
{{ skill.rsl }}
+
{{ skill.points }}
+
{{ skill.reference }}
+ + {% endfor %} + +
+
+
+
Spell
+
College
+
SL
+
RSL
+
Pts
+
+ + + +
+ + {% for spell in character.spells %} +
+
+ {{ spell.name }} +
+ {{ spell.notes | safe }} +
+
+
{{ spell.college }}
+
{{ spell.level }}
+
{{ spell.rsl }}
+
{{ spell.points }}
+
{{ spell.reference }}
+ {% endfor %} + + +
+
+
+
+ + + + +
+
#
+
Carried Equipment (18.75 lb; $485)
+
Uses
+
TL
+
LC
+
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ + + +
+ + {% for item in character.equipment %} + +
+
+ + + + +
+
{{ item.quantity }}
+
+ {{ item.name }} +
+ + {{ item.notes }} +
+
+
0
+
{{ item.tech_level }}
+
+
{{ item.value }}
+
{{ item.weight }}
+
{{ item.ext_value }}
+
{{ item.ext_weight}}
+
{{ item.ref }}
+ + {% endfor %} + +
+
+
+
#
+
Other Equipment ($0)
+
Uses
+
TL
+
LC
+
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ + + +
+ +
+
+
+
Note
+
+ + + +
+ +
+
+ +
+
+ + + diff --git a/gurps_character/templates/characters/embedded.html b/gurps_character/templates/characters/embedded.html new file mode 100644 index 0000000..bcebc2b --- /dev/null +++ b/gurps_character/templates/characters/embedded.html @@ -0,0 +1,1601 @@ +{% extends "base.html" %} +{% block extra_css %} + +{% endblock %} +{% block content %} +
+
+
+
+
Portrait
+
+
+
+
Identity
+
+
Name
+
{{ character.details.profile.name }}
+
Title
+
+
Organization
+
+
+
+
+
Miscellaneous
+
+
Created
+
{{ character.details.created_date }}
+
Modified
+
{{ character.details.modified_date }}
+
Player
+
{{ character.details.profile.player_name }}
+
+
+
+
Description
+
+
Gender
+
{{ character.details.profile.gender }}
+
Age
+
{{ character.details.profile.age }}
+
Birthday
+
{{ character.details.profile.birthday }}
+
Religion
+
+
+
+
Height
+
{{ character.details.profile.height }}
+
Weight
+
{{ character.details.profile.weight }}
+
Size
+
??
+
TL
+
{{ character.details.profile.tech_level }}
+
+
+
Hair
+
{{ character.details.profile.hair }}
+
Eyes
+
{{ character.details.profile.eyes }}
+
Skin
+
{{ character.details.profile.skin }}
+
Hand
+
{{ character.details.profile.handedness }}
+
+
+
+
{{ character.details.total_points }} Points
+
+
{{ character.unspent_points }}
+
Unspent
+
{{ character.race_points }}
+
Race
+
{{ character.attr_points }}
+
Attributes
+
{{ character.attr_points }}
+
Advantages
+
{{ character.disadv_points }}
+
Disadvantages
+
{{ character.quirks_points }}
+
Quirks
+
{{ character.skills_points }}
+
Skills
+
{{ character.spells_points }}
+
Spells
+
+
+
+
+
+
+
Primary Attributes
+
+ +
[{{ character.st.points }}]
+
{{ character.st.value }}
+
Strength (ST)
+ +
[{{ character.dx.points }}]
+
{{ character.dx.value }}
+
Dexterity (DX)
+ +
[{{ character.iq.points }}]
+
{{ character.iq.value }}
+
Intelligence (IQ)
+ +
[{{ character.ht.points }}]
+
{{ character.ht.value }}
+
Health (HT)
+ +
+
+
+
Basic Damage
+
+
[20]
+
{{ character.details.calc.thrust }}
+
Basic Thrust
+
[20]
+
{{ character.details.calc.swing }}
+
Basic Swing
+
+
+
+
Secondary Attributes
+
+ +
[{{ character.will.points }}]
+
{{ character.will.value }}
+
Will
+ +
[{{ character.fright_check.points }}]
+
{{ character.fright_check.value }}
+
Fright Check
+ +
[{{ character.per.points }}]
+
{{ character.per.value }}
+
Perception (Per)
+ +
[{{ character.vision.points }}]
+
{{ character.vision.value }}
+
Vision
+ +
[{{ character.hearing.points }}]
+
{{ character.hearing.value }}
+
Hearing
+ +
[{{ character.taste_smell.points }}]
+
{{ character.taste_smell.value }}
+
Taste & Smell
+ +
[{{ character.touch.points }}]
+
{{ character.touch.value }}
+
Touch
+ +
[{{ character.basic_speed.points }}]
+
{{ character.basic_speed.value }}
+
Basic Speed
+ +
[{{ character.basic_move.points }}]
+
{{ character.basic_move.value }}
+
Basic Move
+ +
+
+
+
Point Pools
+
+ +
[{{ character.fp.points }}]
+
{{ character.fp.current }}
+
of
+
{{ character.fp.value }}
+
Fatigue Points (FP)
+ +
[{{ character.hp.points }}]
+
{{ character.hp.current }}
+
of
+
{{ character.hp.value }}
+
Hit Points (HP)
+ +
+
+
+
+
Hit Locations
+
+
Roll
+
Location
+
DR
+ + + {% for location in character.hit_locations %} +
+
{{ location.calc.roll_range }}
+
{{ location.table_name }}
+
{{ location.hit_penalty }}
+
{{ location.calc.dr.all }}
+ {% endfor %} + +
+
+
+
Encumbrance, Move & Dodge
+
Level
+
Max Load
+
Move
+
Dodge
+ + {% for enc_level in character.enc_levels %} +
+ + + + +
+
+
+
{{enc_level.max_load }} {{character.weight_unit }}
+
{{ enc_level.move }}
+
{{ enc_level.dodge }}
+ {% endfor %} + +
+
+
Lifting & Moving Things
+ {% for lift in character.lift_table %} +
{{ lift.value }} {{ character.weight_unit }}
+
{{ lift.label }}
+ {% endfor %} +
+
+
+
+
+
+
±
+
Reaction
+ + {% for r in character.reaction_modifiers %} +
+
{{ r.amount }}
+
{{ r.situation }}
+ {% endfor %} + +
+
+
+
±
+
Condition
+ + {% for r in character.conditional_modifiers %} +
+
{{ r.amount }}
+
{{ r.situation }}
+ {% endfor %} + +
+
+
+
Melee Weapon
+
Usage
+
SL
+
Parry
+
Block
+
Damage
+
Reach
+
ST
+ + {% for w in character.melee_weapons %} +
+
+ {{ w.name }} +
+ +
+
+
{{ w.usage }}
+
{{ w.skill_level }}
+
{{ w.parry }}
+
{{ w.block }}
+
{{ w.damage }} cut
+
{{ w.reach }}*
+
{{ w.strength }}
+ + {% endfor %} +
+
+
+
Ranged Weapon
+
Usage
+
SL
+
Acc
+
Range
+
Damage
+
RoF
+
Shots
+
Bulk
+
Recoil
+
ST
+ + {% for w in character.ranged_weapons %} +
+
+ {{ w.name }} +
+ +
+
+
Thrown
+
{{ w.skill_level }}
+
{{ w.acc }}
+
{{ w.range }}
+
{{ w.damage }}
+
{{ w.rof }}
+
{{ w.shots }}
+
{{ w.bulk }}
+
{{ w.recoil }}
+
{{ w.strength }}
+ {% endfor %} +
+
+
+
Trait
+
Pts
+
+ + + +
+ + {% for trait in character.traits %} +
+
+ {{ trait.name }} +
+ + {{ trait.notes }} +
+
+
{{ trait.points }}
+
{{ trait.reference }}
+ + {% endfor %} +
+
+
+
Skill / Technique
+
SL
+
RSL
+
Pts
+
+ + + +
+ + {% for skill in character.skills %} +
+
+ {{ skill.name }} +
+ + +
+
+
{{ skill.level }}
+
{{ skill.rsl }}
+
{{ skill.points }}
+
{{ skill.reference }}
+ + {% endfor %} + +
+
+
+
Spell
+
College
+
SL
+
RSL
+
Pts
+
+ + + +
+ + {% for spell in character.spells %} +
+
+ {{ spell.name }} +
+ {{ spell.notes | safe }} +
+
+
{{ spell.college }}
+
{{ spell.level }}
+
{{ spell.rsl }}
+
{{ spell.points }}
+
{{ spell.reference }}
+ {% endfor %} + + +
+
+
+
+ + + + +
+
#
+
Carried Equipment (18.75 lb; $485)
+
Uses
+
TL
+
LC
+
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ + + +
+ + {% for item in character.equipment %} + +
+
+ + + + +
+
{{ item.quantity }}
+
+ {{ item.name }} +
+ + {{ item.notes }} +
+
+
0
+
{{ item.tech_level }}
+
+
{{ item.value }}
+
{{ item.weight }}
+
{{ item.ext_value }}
+
{{ item.ext_weight}}
+
{{ item.ref }}
+ + {% endfor %} + +
+
+
+
#
+
Other Equipment ($0)
+
Uses
+
TL
+
LC
+
+ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ + + + + + + + +
+
+ + + +
+ +
+
+
+
Note
+
+ + + +
+ +
+
+ +
+
+{% endblock %} diff --git a/gurps_character/templates/characters/list.html b/gurps_character/templates/characters/list.html new file mode 100644 index 0000000..e0d6520 --- /dev/null +++ b/gurps_character/templates/characters/list.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% block content %} + + +Upload new character +
+ {% csrf_token %} + {{ form }} + +
+{% endblock %} diff --git a/gurps_character/templates/characters/upload.html b/gurps_character/templates/characters/upload.html new file mode 100644 index 0000000..baafd24 --- /dev/null +++ b/gurps_character/templates/characters/upload.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} +{% block content %} +
+ {% csrf_token %} + {{ form }} +
+{% endblock %} diff --git a/gurps_character/templates/home.html b/gurps_character/templates/home.html new file mode 100644 index 0000000..f10f8d5 --- /dev/null +++ b/gurps_character/templates/home.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% block content %} +

Welcome to the character store

+ + + +

Currently it works with GURPS, specifically characters created by GCS

+{% endblock %} diff --git a/gurps_character/templates/navbar.html b/gurps_character/templates/navbar.html new file mode 100644 index 0000000..3e018b3 --- /dev/null +++ b/gurps_character/templates/navbar.html @@ -0,0 +1,48 @@ + diff --git a/gurps_character/templates/registration/login.html b/gurps_character/templates/registration/login.html new file mode 100644 index 0000000..f542d7d --- /dev/null +++ b/gurps_character/templates/registration/login.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} + +{% block content %} + +{% if form.errors %} +

Your username and password didn't match. Please try again.

+{% endif %} + +{% if next %} + {% if user.is_authenticated %} +

Your account doesn't have access to this page. To proceed, + please login with an account that has access.

+ {% else %} +

Please login to see this page.

+ {% endif %} +{% endif %} + +
+{% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+ +{# Assumes you set up the password_reset view in your URLconf #} +

Lost password?

+ +{% endblock %} diff --git a/gurps_character/tests.py b/gurps_character/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/gurps_character/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/gurps_character/urls.py b/gurps_character/urls.py new file mode 100644 index 0000000..13c2d8f --- /dev/null +++ b/gurps_character/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("", views.index, name="index"), + path("details//", views.details, name="details"), + path("upload", views.upload_file, name="upload"), + path("download//", views.download, name="download"), +] diff --git a/gurps_character/views.py b/gurps_character/views.py new file mode 100644 index 0000000..6b08b8e --- /dev/null +++ b/gurps_character/views.py @@ -0,0 +1,67 @@ +import json + +from django.shortcuts import render +from django.http import HttpResponse, HttpResponseRedirect +from django.urls import reverse + +from .models import GURPSCharacter +from .forms import UploadFileForm + +def index(request): + characters = GURPSCharacter.objects.all() + context = {"characters":characters} + + if request.method == "POST": + form = UploadFileForm(request.POST, request.FILES) + if form.is_valid(): + handle_uploaded_file(request.FILES["file"]) + return HttpResponseRedirect(reverse("index")) + else: + form = UploadFileForm() + + context['form'] = form + return render(request, "characters/list.html", context) + +def details(request, uuid): + character = GURPSCharacter.objects.get(uuid=uuid) + + context = {"character": character} + #import bpdb;bpdb.set_trace() + + return render(request, "characters/embedded.html", context) + + +def upload_file(request): + if request.method == "POST": + form = UploadFileForm(request.POST, request.FILES) + if form.is_valid(): + handle_uploaded_file(request.FILES["file"]) + return HttpResponseRedirect("/success/url/") + else: + form = UploadFileForm() + return render(request, "characters/upload.html", {"form": form}) + +def handle_uploaded_file(f): + import bpdb;bpdb.set_trace() + f.seek(0) # We read the file in the validator + data = json.loads(f.read()) + + uuid = data['id'] + name = data["profile"]["name"] + + + try: + character = GURPSCharacter.objects.get(uuid=uuid) + character.details = data + character.name = name + character.save() + except GURPSCharacter.DoesNotExist: + character = GURPSCharacter(uuid=uuid, name=name, details = data) + character.save() + +def download(irequest, uuid): + mime_type = "application/x-gcs-gcs" + character = GURPSCharacter.objects.get(uuid=uuid) + response = HttpResponse(json.dumps(character.details), content_type=mime_type) + response['Content-Disposition'] = "attachment; filename=%s.gcs" % character.name + return response diff --git a/gurps_vars.sh b/gurps_vars.sh new file mode 100644 index 0000000..1035cf1 --- /dev/null +++ b/gurps_vars.sh @@ -0,0 +1,5 @@ +export GURPS_DATABASE_NAME=neill +export GURPS_DATABASE_USER=neill +export GURPS_DATABASE_PASSWORD=ht6a!nce3216 +export GURPS_DATABASE_HOST=172.23.0.36 +export GURPS_DATABASE_PORT=5432 diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..fed0310 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_gurps.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..ae35a60 --- /dev/null +++ b/notes.txt @@ -0,0 +1,41 @@ +Users + - id + - name + + (part of django auth) + +GMs + - user + - campaign + + # A GM is a user linked to a campaign. They get extra priovs on that campaign + +Characters + - id + - owner (user-id) + - campaing (campaign id) + - game system? + +Campaign + - id + - name + - game system + +Campaign-Players + - campaign id + - user id + +Game System + - id + - name + + +A character is owned by a user and is part of a campaign + +A campaign has one or more gms and zero or more players + +A user may view characters they own, or if they are a gm then characters that are part of one of their campaigns + + +Permissions + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..855636a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +django +tailwind +django_browser_reload +psycopg diff --git a/theme/__init__.py b/theme/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/theme/__pycache__/__init__.cpython-312.pyc b/theme/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aec6c5fa06cbb776ad7ebb35a808eb032f60bc21 GIT binary patch literal 156 zcmX@j%ge>Uz`(F_@6uEd{TM``gU>7s3=Gp5Dj75x{Z=v*F)=VOd=YR8Xv6l98I5svjSpnU`4-AFo$X l`HRCQH$SB`C)KWqm4ShQk%57s7{vI<%*e=C#LU3J000h|Ci(yX literal 0 HcmV?d00001 diff --git a/theme/__pycache__/apps.cpython-312.pyc b/theme/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..917ce77605f05a796a75284e0fedc31f1269a851 GIT binary patch literal 399 zcmXv~F;2rk5S+Cg2yr41;R7^CZgM3JLP8+XMJb?hbFy-WLuC8RIgv<-ln2o90*Z(? z@B%)7EKyO>Aq5&Lw6?Rw-i&r+HPNZA zg=K5TWEgm5Tgog-wUlK?%G9WN!niBt-8@Q~ipTE?Yo73TEG8z^A{(1~F|uZ=$Fo9= zv@J{)B|=T3EH*Np+q@9f5E12hF~}E|kFJsjpx6em#Jj)$aACWf%8>W0Ee0&J`~kJl mXH+%zc#HN)z3ZvnZEi0P0DQYd^nt^lEu#Ko@C%}TrTPay2VVF9 literal 0 HcmV?d00001 diff --git a/theme/apps.py b/theme/apps.py new file mode 100644 index 0000000..bec7464 --- /dev/null +++ b/theme/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ThemeConfig(AppConfig): + name = 'theme' diff --git a/theme/static/css/dist/styles.css b/theme/static/css/dist/styles.css new file mode 100644 index 0000000..7e32723 --- /dev/null +++ b/theme/static/css/dist/styles.css @@ -0,0 +1,841 @@ +/* +! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +[type='text'],input:where(:not([type])),[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + border-radius: 0px; + padding-top: 0.5rem; + padding-right: 0.75rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 1rem; + line-height: 1.5rem; + --tw-shadow: 0 0 #0000; +} + +[type='text']:focus, input:where(:not([type])):focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + border-color: #2563eb; +} + +input::-moz-placeholder, textarea::-moz-placeholder { + color: #6b7280; + opacity: 1; +} + +input::placeholder,textarea::placeholder { + color: #6b7280; + opacity: 1; +} + +::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +::-webkit-date-and-time-value { + min-height: 1.5em; + text-align: inherit; +} + +::-webkit-datetime-edit { + display: inline-flex; +} + +::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { + padding-top: 0; + padding-bottom: 0; +} + +select { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} + +[multiple],[size]:where(select:not([size="1"])) { + background-image: initial; + background-position: initial; + background-repeat: unset; + background-size: initial; + padding-right: 0.75rem; + -webkit-print-color-adjust: unset; + print-color-adjust: unset; +} + +[type='checkbox'],[type='radio'] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + display: inline-block; + vertical-align: middle; + background-origin: border-box; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #2563eb; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + --tw-shadow: 0 0 #0000; +} + +[type='checkbox'] { + border-radius: 0px; +} + +[type='radio'] { + border-radius: 100%; +} + +[type='checkbox']:focus,[type='radio']:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width: 2px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); +} + +[type='checkbox']:checked,[type='radio']:checked { + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +[type='checkbox']:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); +} + +@media (forced-colors: active) { + [type='checkbox']:checked { + -webkit-appearance: auto; + -moz-appearance: auto; + appearance: auto; + } +} + +[type='radio']:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); +} + +@media (forced-colors: active) { + [type='radio']:checked { + -webkit-appearance: auto; + -moz-appearance: auto; + appearance: auto; + } +} + +[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { + border-color: transparent; + background-color: currentColor; +} + +[type='checkbox']:indeterminate { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +@media (forced-colors: active) { + [type='checkbox']:indeterminate { + -webkit-appearance: auto; + -moz-appearance: auto; + appearance: auto; + } +} + +[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { + border-color: transparent; + background-color: currentColor; +} + +[type='file'] { + background: unset; + border-color: inherit; + border-width: 0; + border-radius: 0; + padding: 0; + font-size: unset; + line-height: inherit; +} + +[type='file']:focus { + outline: 1px solid ButtonText; + outline: 1px auto -webkit-focus-ring-color; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +.static { + position: static; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.block { + display: block; +} + +.inline { + display: inline; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.hidden { + display: none; +} + +.h-screen { + height: 100vh; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.border { + border-width: 1px; +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.font-serif { + font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; +} + +.text-5xl { + font-size: 3rem; + line-height: 1; +} + +.leading-normal { + line-height: 1.5; +} + +.tracking-normal { + letter-spacing: 0em; +} diff --git a/theme/static_src/.gitignore b/theme/static_src/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/theme/static_src/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/theme/static_src/package-lock.json b/theme/static_src/package-lock.json new file mode 100644 index 0000000..12c2bcd --- /dev/null +++ b/theme/static_src/package-lock.json @@ -0,0 +1,1527 @@ +{ + "name": "theme", + "version": "3.8.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "theme", + "version": "3.8.0", + "license": "MIT", + "devDependencies": { + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "cross-env": "^7.0.3", + "postcss": "^8.4.32", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-simple-vars": "^7.0.1", + "rimraf": "^5.0.5", + "tailwindcss": "^3.4.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tailwindcss/aspect-ratio": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz", + "integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "dev": true, + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", + "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-simple-vars": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz", + "integrity": "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==", + "dev": true, + "engines": { + "node": ">=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.1" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/theme/static_src/package.json b/theme/static_src/package.json new file mode 100644 index 0000000..a391915 --- /dev/null +++ b/theme/static_src/package.json @@ -0,0 +1,28 @@ +{ + "name": "theme", + "version": "3.8.0", + "description": "", + "scripts": { + "start": "npm run dev", + "build": "npm run build:clean && npm run build:tailwind", + "build:clean": "rimraf ../static/css/dist", + "build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify", + "dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w", + "tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "cross-env": "^7.0.3", + "postcss": "^8.4.32", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-simple-vars": "^7.0.1", + "rimraf": "^5.0.5", + "tailwindcss": "^3.4.0" + } +} diff --git a/theme/static_src/postcss.config.js b/theme/static_src/postcss.config.js new file mode 100644 index 0000000..0b09b34 --- /dev/null +++ b/theme/static_src/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + "postcss-import": {}, + "postcss-simple-vars": {}, + "postcss-nested": {} + }, +} diff --git a/theme/static_src/src/styles.css b/theme/static_src/src/styles.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/theme/static_src/src/styles.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/theme/static_src/tailwind.config.js b/theme/static_src/tailwind.config.js new file mode 100644 index 0000000..9485bc6 --- /dev/null +++ b/theme/static_src/tailwind.config.js @@ -0,0 +1,57 @@ +/** + * This is a minimal config. + * + * If you need the full config, get it from here: + * https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js + */ + +module.exports = { + content: [ + /** + * HTML. Paths to Django template files that will contain Tailwind CSS classes. + */ + + /* Templates within theme app (/templates), e.g. base.html. */ + '../templates/**/*.html', + + /* + * Main templates directory of the project (BASE_DIR/templates). + * Adjust the following line to match your project structure. + */ + '../../templates/**/*.html', + + /* + * Templates in other django apps (BASE_DIR//templates). + * Adjust the following line to match your project structure. + */ + '../../**/templates/**/*.html', + + /** + * JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure + * patterns match your project structure. + */ + /* JS 1: Ignore any JavaScript in node_modules folder. */ + // '!../../**/node_modules', + /* JS 2: Process all JavaScript files in the project. */ + // '../../**/*.js', + + /** + * Python: If you use Tailwind CSS classes in Python, uncomment the following line + * and make sure the pattern below matches your project structure. + */ + // '../../**/*.py' + ], + theme: { + extend: {}, + }, + plugins: [ + /** + * '@tailwindcss/forms' is the forms plugin that provides a minimal styling + * for forms. If you don't like it or have own styling for forms, + * comment the line below to disable '@tailwindcss/forms'. + */ + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + require('@tailwindcss/aspect-ratio'), + ], +} diff --git a/theme/templates/base.html b/theme/templates/base.html new file mode 100644 index 0000000..5dea45e --- /dev/null +++ b/theme/templates/base.html @@ -0,0 +1,27 @@ + + + + Django GURPS + + + + + + +{% block extra_css %}{% endblock %} + + + + + + {% include "navbar.html" %} + +
+
+ {% block content %}{% endblock %} +
+
+ +