| @ -1,24 +0,0 @@ | |||
| # Utilizar una imagen base de Python | |||
| FROM python:3.11-slim | |||
| # Establecer el directorio de trabajo en el contenedor | |||
| WORKDIR /app | |||
| # Copiar el archivo requirements.txt al directorio de trabajo | |||
| COPY requirements.txt . | |||
| # Instalar las dependencias | |||
| RUN pip install --no-cache-dir -r requirements.txt | |||
| # Copiar el resto del código de la aplicación | |||
| COPY . . | |||
| # Exponer el puerto en el que correrá la aplicación | |||
| EXPOSE 8000 | |||
| # Ejecutar las migraciones y colectar archivos estáticos | |||
| RUN python manage.py migrate | |||
| #RUN python manage.py collectstatic --noinput | |||
| # Comando para iniciar el servidor de Django | |||
| CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] | |||
| @ -1,3 +0,0 @@ | |||
| from django.contrib import admin | |||
| # Register your models here. | |||
| @ -1,6 +0,0 @@ | |||
| from django.apps import AppConfig | |||
| class HelloConfig(AppConfig): | |||
| default_auto_field = 'django.db.models.BigAutoField' | |||
| name = 'hello' | |||
| @ -1,3 +0,0 @@ | |||
| from django.db import models | |||
| # Create your models here. | |||
| @ -1,38 +0,0 @@ | |||
| /* hello/static/hello/styles.css */ | |||
| body { | |||
| font-family: Arial, sans-serif; | |||
| background-color: #f0f0f0; | |||
| margin: 0; | |||
| padding: 0; | |||
| } | |||
| header { | |||
| background-color: #afafaf; | |||
| color: white; | |||
| padding: 1em; | |||
| text-align: center; | |||
| } | |||
| nav ul { | |||
| list-style-type: none; | |||
| padding: 0; | |||
| } | |||
| nav li { | |||
| display: inline; | |||
| margin-right: 10px; | |||
| } | |||
| nav a { | |||
| color: white; | |||
| text-decoration: none; | |||
| } | |||
| h1 { | |||
| text-align: center; | |||
| } | |||
| p { | |||
| text-align: center; | |||
| font-size: 1.2em; | |||
| } | |||
| @ -1,21 +0,0 @@ | |||
| {% load static %} | |||
| <!DOCTYPE html> | |||
| <html> | |||
| <head> | |||
| <title>Biblioteca</title> | |||
| <link rel="stylesheet" type="text/css" href="{% static 'hello/styles.css' %}"> | |||
| </head> | |||
| <body> | |||
| <header> | |||
| <nav> | |||
| <ul> | |||
| <li><a href="{% url 'home' %}">Inicio</a></li> | |||
| <!-- Otros enlaces de navegación --> | |||
| </ul> | |||
| </nav> | |||
| </header> | |||
| <h1>¡Hola, mundo!</h1> | |||
| <p>Bienvenido a mi primera aplicación Django con plantillas.</p> | |||
| </body> | |||
| </html> | |||
| @ -1,3 +0,0 @@ | |||
| from django.test import TestCase | |||
| # Create your tests here. | |||
| @ -1,6 +0,0 @@ | |||
| from django.urls import path | |||
| from . import views | |||
| urlpatterns = [ | |||
| path('', views.home, name='home'), | |||
| ] | |||
| @ -1,4 +0,0 @@ | |||
| from django.shortcuts import render | |||
| def home(request): | |||
| return render(request, 'home.html') | |||
| @ -1,22 +0,0 @@ | |||
| #!/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', 'mysite.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() | |||
| @ -1,16 +0,0 @@ | |||
| """ | |||
| ASGI config for mysite 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.1/howto/deployment/asgi/ | |||
| """ | |||
| import os | |||
| from django.core.asgi import get_asgi_application | |||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') | |||
| application = get_asgi_application() | |||
| @ -1,124 +0,0 @@ | |||
| """ | |||
| Django settings for mysite project. | |||
| Generated by 'django-admin startproject' using Django 5.1. | |||
| For more information on this file, see | |||
| https://docs.djangoproject.com/en/5.1/topics/settings/ | |||
| For the full list of settings and their values, see | |||
| https://docs.djangoproject.com/en/5.1/ref/settings/ | |||
| """ | |||
| 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.1/howto/deployment/checklist/ | |||
| # SECURITY WARNING: keep the secret key used in production secret! | |||
| SECRET_KEY = 'django-insecure-=+0f!+$+jw$f1n_qjm&p3_w)t13*66sv_+sq%&&ee_n^s+caq=' | |||
| # SECURITY WARNING: don't run with debug turned on in production! | |||
| DEBUG = True | |||
| ALLOWED_HOSTS = [] | |||
| # Application definition | |||
| INSTALLED_APPS = [ | |||
| 'django.contrib.admin', | |||
| 'django.contrib.auth', | |||
| 'django.contrib.contenttypes', | |||
| 'django.contrib.sessions', | |||
| 'django.contrib.messages', | |||
| 'django.contrib.staticfiles', | |||
| 'hello', | |||
| ] | |||
| 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', | |||
| ] | |||
| ROOT_URLCONF = 'mysite.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 = 'mysite.wsgi.application' | |||
| # Database | |||
| # https://docs.djangoproject.com/en/5.1/ref/settings/#databases | |||
| DATABASES = { | |||
| 'default': { | |||
| 'ENGINE': 'django.db.backends.sqlite3', | |||
| 'NAME': BASE_DIR / 'db.sqlite3', | |||
| } | |||
| } | |||
| # Password validation | |||
| # https://docs.djangoproject.com/en/5.1/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.1/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.1/howto/static-files/ | |||
| STATIC_URL = 'static/' | |||
| # Default primary key field type | |||
| # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field | |||
| DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' | |||
| @ -1,24 +0,0 @@ | |||
| """ | |||
| URL configuration for mysite project. | |||
| The `urlpatterns` list routes URLs to views. For more information please see: | |||
| https://docs.djangoproject.com/en/5.1/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 path, include | |||
| urlpatterns = [ | |||
| path('admin/', admin.site.urls), | |||
| path('', include('hello.urls')), # Incluyendo las URLs de la aplicación | |||
| ] | |||
| @ -1,16 +0,0 @@ | |||
| """ | |||
| WSGI config for mysite 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.1/howto/deployment/wsgi/ | |||
| """ | |||
| import os | |||
| from django.core.wsgi import get_wsgi_application | |||
| os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') | |||
| application = get_wsgi_application() | |||
| @ -1,4 +0,0 @@ | |||
| asgiref==3.8.1 | |||
| Django==5.1 | |||
| sqlparse==0.5.1 | |||
| typing_extensions==4.12.2 | |||
| @ -1,5 +0,0 @@ | |||
| Dockerfile | |||
| Makefile | |||
| volcadossql/ | |||
| venv/ | |||
| migrations/ | |||
| @ -1,73 +0,0 @@ | |||
| # syntax=docker/dockerfile:1 | |||
| ################## | |||
| # BUILDER # | |||
| ################## | |||
| FROM python:3.11.4-slim-buster AS builder | |||
| # set work directory | |||
| WORKDIR /app | |||
| # set environment variables | |||
| ENV PYTHONDONTWRITEBYTECODE=1 | |||
| ENV PYTHONUNBUFFERED=1 | |||
| # install system dependencies | |||
| RUN apt-get update && \ | |||
| apt-get install -y --no-install-recommends gcc | |||
| # lint | |||
| RUN pip install --upgrade pip | |||
| RUN pip install flake8==6.0.0 | |||
| COPY . /app/ | |||
| RUN flake8 --ignore=E501,F401,E126 . | |||
| COPY ./requirements.txt . | |||
| RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt | |||
| ################## | |||
| # FINAL # | |||
| ################## | |||
| FROM python:3.11.4-slim-buster | |||
| # create directory for the app user | |||
| RUN mkdir -p /app | |||
| # create the app user | |||
| #RUN addgroup --system app && adduser --system --group app | |||
| # create the appropriate directories | |||
| ENV APP_HOME=/app | |||
| RUN mkdir -p $APP_HOME | |||
| #RUN mkdir -p $APP_HOME/staticfiles | |||
| #RUN mkdir -p $APP_HOME/mediafiles | |||
| WORKDIR $APP_HOME | |||
| # install system dependencies | |||
| RUN apt-get update && apt-get install -y sqlite3 netcat | |||
| COPY --from=builder /app/wheels /wheels | |||
| COPY --from=builder /app/requirements.txt . | |||
| RUN pip install --upgrade pip | |||
| RUN pip install --no-cache /wheels/* | |||
| # copy entrypoint.sh | |||
| COPY ./entrypoint.sh . | |||
| # copy project | |||
| COPY . $APP_HOME | |||
| # chown all the files to the app user | |||
| #RUN chown -R app:app $APP_HOME | |||
| # change to the app user | |||
| #USER app | |||
| WORKDIR $APP_HOME/finanzas | |||
| # run entrypoint.sh | |||
| ENTRYPOINT ["/app/entrypoint.sh"] | |||
| @ -1,50 +0,0 @@ | |||
| export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':') | |||
| #export REGISTRY=registry.cube.local | |||
| export REGISTRY=registry.reymota.es | |||
| export IMG_VERSION = 0.8 | |||
| export IMG_NGINX_VERSION = 1.0 | |||
| # limpia todo | |||
| all: imagen clean install | |||
| imagen: | |||
| cd ../; make | |||
| install: | |||
| -kubectl create -f namespace.yaml | |||
| -kubectl create -f reg-secret.yaml | |||
| -kubectl create -f env-prod-configmap.yaml | |||
| -kubectl create -f env-prod-db-configmap.yaml | |||
| -kubectl create -f pv-local-finanzas.yaml | |||
| -kubectl create -f finanzas-prod-persistentvolumeclaim.yaml | |||
| -kubectl create -f postgres-data-persistentvolumeclaim.yaml | |||
| -kubectl create -f static-volume-persistentvolumeclaim.yaml | |||
| -kubectl create -f db-deployment.yaml | |||
| -kubectl create -f db-service.yaml | |||
| -envsubst < finanzas-deployment.yaml |kubectl create -f - | |||
| -envsubst < nginx-deployment.yaml |kubectl create -f - | |||
| -kubectl create -f nginx-service.yaml | |||
| clean: | |||
| -envsubst < nginx-deployment.yaml |kubectl delete -f - | |||
| -kubectl delete -f nginx-service.yaml | |||
| -envsubst < finanzas-deployment.yaml |kubectl delete -f - | |||
| -kubectl delete -f db-deployment.yaml | |||
| -kubectl delete -f db-service.yaml | |||
| -kubectl delete -f env-prod-configmap.yaml | |||
| -kubectl delete -f env-prod-db-configmap.yaml | |||
| -kubectl delete -f static-volume-persistentvolumeclaim.yaml | |||
| -kubectl delete -f postgres-data-persistentvolumeclaim.yaml | |||
| -kubectl delete -f finanzas-prod-persistentvolumeclaim.yaml | |||
| -kubectl delete -f pv-local-finanzas.yaml | |||
| -kubectl delete -f reg-secret.yaml | |||
| -kubectl delete -f namespace.yaml | |||
| nginx: | |||
| cd ../nginx; make | |||
| @ -1,52 +0,0 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| name: db | |||
| namespace: finanzas | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| io.kompose.service: db | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| spec: | |||
| containers: | |||
| - env: | |||
| - name: POSTGRES_DB | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_DB | |||
| name: env-prod-db | |||
| - name: POSTGRES_PASSWORD | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_PASSWORD | |||
| name: env-prod-db | |||
| - name: POSTGRES_USER | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_USER | |||
| name: env-prod-db | |||
| image: postgres:15 | |||
| name: db | |||
| volumeMounts: | |||
| - mountPath: /var/lib/postgresql/data | |||
| name: postgres-data | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: postgres-data | |||
| persistentVolumeClaim: | |||
| claimName: postgres-data | |||
| @ -1,17 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| name: db | |||
| namespace: finanzas | |||
| spec: | |||
| ports: | |||
| - name: "5432" | |||
| port: 5432 | |||
| targetPort: 5432 | |||
| selector: | |||
| io.kompose.service: db | |||
| @ -1 +0,0 @@ | |||
| kubectl -n finanzas exec -ti deployment.apps/finanzas -- /bin/bash | |||
| @ -1 +0,0 @@ | |||
| kubectl -n finanzas exec -ti deployment.apps/db -- psql --username=creylopez --dbname=finanzas | |||
| @ -1,19 +0,0 @@ | |||
| apiVersion: v1 | |||
| data: | |||
| DEBUG: "False" | |||
| DJANGO_ALLOWED_HOSTS: "finanzas.reymota.es k8s-server localhost 127.0.0.1 [::1]" | |||
| CSRF_TRUSTED_ORIGINS: "https://finanzas.reymota.es" | |||
| SECRET_KEY: change_me | |||
| SQL_DATABASE: finanzas | |||
| SQL_ENGINE: django.db.backends.postgresql | |||
| SQL_HOST: db | |||
| SQL_PASSWORD: Dsa-0213 | |||
| SQL_PORT: "5432" | |||
| SQL_USER: creylopez | |||
| DATABASE: postgres | |||
| kind: ConfigMap | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: web-env-prod | |||
| name: env-prod | |||
| namespace: finanzas | |||
| @ -1,11 +0,0 @@ | |||
| apiVersion: v1 | |||
| data: | |||
| POSTGRES_DB: finanzas | |||
| POSTGRES_PASSWORD: Dsa-0213 | |||
| POSTGRES_USER: creylopez | |||
| kind: ConfigMap | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: db-env-prod-db | |||
| name: env-prod-db | |||
| namespace: finanzas | |||
| @ -1,129 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| name: finanzas | |||
| namespace: finanzas | |||
| spec: | |||
| ports: | |||
| - name: "8000" | |||
| port: 8000 | |||
| targetPort: 8000 | |||
| selector: | |||
| app: finanzas | |||
| --- | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| name: finanzas | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: finanzas | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| containers: | |||
| - args: | |||
| - gunicorn | |||
| - finanzas.wsgi:application | |||
| - --bind | |||
| - 0.0.0.0:8000 | |||
| name: finanzas | |||
| image: $REGISTRY/finanzas-$ARQUITECTURA:$IMG_VERSION | |||
| env: | |||
| - name: VERSION | |||
| value: "$IMG_VERSION" | |||
| - name: ENVIRONMENT | |||
| value: "Producción" | |||
| - name: DEBUG | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DEBUG | |||
| name: env-prod | |||
| - name: DJANGO_ALLOWED_HOSTS | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DJANGO_ALLOWED_HOSTS | |||
| name: env-prod | |||
| - name: CSRF_TRUSTED_ORIGINS | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: CSRF_TRUSTED_ORIGINS | |||
| name: env-prod | |||
| - name: SECRET_KEY | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SECRET_KEY | |||
| name: env-prod | |||
| - name: DATABASE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DATABASE | |||
| name: env-prod | |||
| - name: SQL_HOST | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_HOST | |||
| name: env-prod | |||
| - name: SQL_PORT | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_PORT | |||
| name: env-prod | |||
| - name: SQL_ENGINE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_ENGINE | |||
| name: env-prod | |||
| - name: SQL_DATABASE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_DATABASE | |||
| name: env-prod | |||
| - name: SQL_USER | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_USER | |||
| name: env-prod | |||
| - name: SQL_PASSWORD | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_PASSWORD | |||
| name: env-prod | |||
| ports: | |||
| - containerPort: 8000 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - mountPath: /app/finanzas/mediafiles | |||
| name: finanzas-media | |||
| - mountPath: /app/finanzas/apuntes/migrations | |||
| name: apuntes-migrations | |||
| - mountPath: /app/finanzas/reymotausers/migrations | |||
| name: reymotausers-migrations | |||
| - mountPath: /app/finanzas/staticfiles | |||
| name: static-volume | |||
| imagePullSecrets: | |||
| - name: myregistrykey | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: finanzas-media | |||
| persistentVolumeClaim: | |||
| claimName: finanzas-media | |||
| - name: apuntes-migrations | |||
| persistentVolumeClaim: | |||
| claimName: apuntes-migrations | |||
| - name: reymotausers-migrations | |||
| persistentVolumeClaim: | |||
| claimName: reymotausers-migrations | |||
| - name: static-volume | |||
| persistentVolumeClaim: | |||
| claimName: static-volume | |||
| status: {} | |||
| @ -1,47 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: finanzas-media | |||
| name: finanzas-media | |||
| namespace: finanzas | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 100Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: apuntes-migrations | |||
| name: apuntes-migrations | |||
| namespace: finanzas | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 50Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymotausers-migrations | |||
| name: reymotausers-migrations | |||
| namespace: finanzas | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 50Mi | |||
| status: {} | |||
| @ -1,7 +0,0 @@ | |||
| ################################################### | |||
| # Namespace Vehículos | |||
| ################################################### | |||
| apiVersion: v1 | |||
| kind: Namespace | |||
| metadata: | |||
| name: finanzas | |||
| @ -1,46 +0,0 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| name: nginx | |||
| namespace: finanzas | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| io.kompose.service: nginx | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| spec: | |||
| containers: | |||
| - image: $REGISTRY/nginx-finanzas-$ARQUITECTURA:$IMG_NGINX_VERSION | |||
| name: nginx | |||
| ports: | |||
| - containerPort: 80 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - mountPath: /app/finanzas/staticfiles | |||
| name: static-volume | |||
| - mountPath: /app/finanzas/mediafiles | |||
| name: finanzas-media | |||
| imagePullSecrets: | |||
| - name: myregistrykey | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: static-volume | |||
| persistentVolumeClaim: | |||
| claimName: static-volume | |||
| - name: finanzas-media | |||
| persistentVolumeClaim: | |||
| claimName: finanzas-media | |||
| @ -1,20 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| name: nginx | |||
| namespace: finanzas | |||
| spec: | |||
| type: NodePort | |||
| ports: | |||
| - name: "1337" | |||
| port: 1337 | |||
| nodePort: 30344 | |||
| targetPort: 80 | |||
| selector: | |||
| io.kompose.service: nginx | |||
| @ -1,13 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: postgres-data | |||
| name: postgres-data | |||
| namespace: finanzas | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 100Mi | |||
| @ -1,74 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: finanzas-media-folder | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| capacity: | |||
| storage: 100Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/finanzas/media" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: apuntes-migrations-folder | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| capacity: | |||
| storage: 50Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/finanzas/migrations/apuntes" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymotausers-migrations-folder | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| capacity: | |||
| storage: 50Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/finanzas/migrations/reymotausers" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: finanzas-static-folder | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| capacity: | |||
| storage: 70Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/finanzas/static" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: finanzas-pg-folder | |||
| namespace: finanzas | |||
| labels: | |||
| app: finanzas | |||
| spec: | |||
| capacity: | |||
| storage: 200Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/finanzas/pg" | |||
| @ -1,8 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: Secret | |||
| metadata: | |||
| name: myregistrykey | |||
| namespace: finanzas | |||
| data: | |||
| .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5yZXltb3RhLmVzIjogewoJCQkiYXV0aCI6ICJZM0psZVd4dmNHVjZPbEpsZVMweE1UYzIiCgkJfQoJfQp9 | |||
| type: kubernetes.io/dockerconfigjson | |||
| @ -1,13 +0,0 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: static-volume | |||
| name: static-volume | |||
| namespace: finanzas | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 70Mi | |||
| @ -1 +0,0 @@ | |||
| docker run -it registry.reymota.es/finanzas-x86_64:0.2 bash | |||
| @ -1,8 +0,0 @@ | |||
| install: | |||
| echo "Creando imagen con version '${IMG_VERSION}' para la arquitectura '${ARQUITECTURA}' en el registry '${REGISTRY}'" | |||
| docker build --no-cache -t ${REGISTRY}/finanzas-${ARQUITECTURA}:${IMG_VERSION} . | |||
| docker push ${REGISTRY}/finanzas-${ARQUITECTURA}:${IMG_VERSION} | |||
| @ -1,44 +0,0 @@ | |||
| # Instalación | |||
| Desde el directorio K8S ejecutar make (esto hace todo: la imagen, para los pods y los lanza otra vez) | |||
| La primera vez, hay que entrar en el pod de vehículos con 'entra.sh' y | |||
| python manage.py createsuperuser | |||
| python manage.py makemigrations | |||
| python manage.py migrate | |||
| ## Comprobar la base de datos | |||
| Con la shell entraPsql.sh: | |||
| \l para listar las BD | |||
| \c finanzas para usar nuestra db | |||
| \dt para ver las tablas | |||
| # De dónde cogí ideas | |||
| https://learndjango.com/tutorials/django-login-and-logout-tutorial | |||
| Username: {{ user.username }} | |||
| User Full name: {{ user.get_full_name }} | |||
| User Group: {{ user.groups.all.0 }} | |||
| Email: {{ user.email }} | |||
| Session Started at: {{ user.last_login }} | |||
| ## Para funcionar con gunicorn y nginx | |||
| https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/ | |||
| ## Para incluir gŕaficos | |||
| https://studygyaan.com/django/creating-charts-in-django-web-app | |||
| @ -1,20 +0,0 @@ | |||
| #!/bin/bash | |||
| if [ "$DATABASE" = "postgres" ] | |||
| then | |||
| echo "Waiting for postgres..." | |||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||
| sleep 0.1 | |||
| done | |||
| echo "PostgreSQL started" | |||
| else | |||
| echo "la base de datos no es postgres: '$DATABASE'" | |||
| fi | |||
| python manage.py collectstatic --noinput | |||
| #python manage.py flush --no-input | |||
| #python manage.py migrate | |||
| exec "$@" | |||
| @ -1 +0,0 @@ | |||
| db.sqlite3 | |||
| @ -1 +0,0 @@ | |||
| db.sqlite3 | |||
| @ -1 +0,0 @@ | |||
| migrations/ | |||
| @ -1,3 +0,0 @@ | |||
| from django.contrib import admin | |||
| # Register your models here. | |||
| @ -1,6 +0,0 @@ | |||
| from django.apps import AppConfig | |||
| class AccountsConfig(AppConfig): | |||
| default_auto_field = 'django.db.models.BigAutoField' | |||
| name = 'accounts' | |||
| @ -1,3 +0,0 @@ | |||
| from django.db import models | |||
| # Create your models here. | |||
| @ -1,3 +0,0 @@ | |||
| from django.test import TestCase | |||
| # Create your tests here. | |||
| @ -1,8 +0,0 @@ | |||
| # accounts/urls.py | |||
| from django.urls import path | |||
| from django.contrib.auth import views as auth_views | |||
| urlpatterns = [ | |||
| path('login/', auth_views.LoginView.as_view(), name='login'), | |||
| path('logout/', auth_views.LogoutView.as_view(), name='logout'), | |||
| ] | |||
| @ -1 +0,0 @@ | |||
| from django.shortcuts import render | |||
| @ -1 +0,0 @@ | |||
| migrations/ | |||
| @ -1,10 +0,0 @@ | |||
| from django.contrib import admin | |||
| from django.contrib.auth.admin import UserAdmin | |||
| # Register your models here. | |||
| from .models import Apunte, Cuenta, Tipo | |||
| admin.site.register(Apunte) | |||
| admin.site.register(Cuenta) | |||
| admin.site.register(Tipo) | |||
| @ -1,6 +0,0 @@ | |||
| from django.apps import AppConfig | |||
| class ApuntesConfig(AppConfig): | |||
| default_auto_field = 'django.db.models.BigAutoField' | |||
| name = 'apuntes' | |||
| @ -1,40 +0,0 @@ | |||
| from django import forms | |||
| from .models import Cuenta, Apunte, Tipo | |||
| class CuentaForm(forms.ModelForm): | |||
| class Meta: | |||
| model = Cuenta | |||
| fields = ['nombre', 'saldo_inicial', 'tipo'] | |||
| nombre = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| saldo_inicial = forms.DecimalField( | |||
| widget=forms.NumberInput(attrs={'class': 'form-control'})) | |||
| tipo = forms.ModelChoiceField( | |||
| queryset=Tipo.objects.all(), | |||
| widget=forms.Select(attrs={'class': 'form-control'})) | |||
| class ApunteForm(forms.ModelForm): | |||
| class Meta: | |||
| model = Apunte | |||
| fields = ['fecha', 'concepto', 'cta_origen', 'cta_destino', 'importe'] | |||
| fecha = forms.DateField( | |||
| widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'})) | |||
| concepto = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| cta_origen = forms.ModelChoiceField( | |||
| queryset=Cuenta.objects.all(), | |||
| widget=forms.Select(attrs={'class': 'form-control'})) | |||
| cta_destino = forms.ModelChoiceField( | |||
| queryset=Cuenta.objects.all(), | |||
| widget=forms.Select(attrs={'class': 'form-control'})) | |||
| importe = forms.DecimalField( | |||
| widget=forms.NumberInput(attrs={'class': 'form-control'})) | |||
| @ -1,29 +0,0 @@ | |||
| from django.db import models | |||
| class Tipo(models.Model): | |||
| tipo = models.TextField(max_length=10) | |||
| def __str__(self): | |||
| return self.tipo | |||
| class Cuenta(models.Model): | |||
| nombre = models.TextField(max_length=20) | |||
| saldo_inicial = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) | |||
| saldo_actual = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) | |||
| tipo = models.ForeignKey(Tipo, on_delete=models.CASCADE) | |||
| def __str__(self): | |||
| return self.nombre | |||
| class Apunte(models.Model): | |||
| fecha = models.DateField() | |||
| cta_origen = models.ForeignKey(Cuenta, on_delete=models.CASCADE, related_name='origen') | |||
| cta_destino = models.ForeignKey(Cuenta, on_delete=models.CASCADE, related_name='destino') | |||
| importe = models.DecimalField(max_digits=10, decimal_places=2) | |||
| concepto = models.TextField(max_length=30) | |||
| def __str__(self): | |||
| return self.fecha | |||
| @ -1,21 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <svg width="215px" height="215px" viewBox="0 0 215 215" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||
| <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch --> | |||
| <title>portal-logo</title> | |||
| <desc>Created with Sketch.</desc> | |||
| <defs> | |||
| <path d="M51.165,8.742 C54.505,12.619 56.876,17.365 57.892,22.588 C60.148,17.225 65.452,13.46 71.636,13.46 C79.867,13.46 86.541,20.134 86.541,28.365 C86.541,36.597 79.867,43.269 71.636,43.269 C63.404,43.269 56.728,36.597 56.728,28.365 C56.728,12.7 44.03,0 28.365,0 C12.7,0 0,12.7 0,28.365 C0,44.031 12.7,56.731 28.365,56.731 C36.419,56.731 43.695,53.393 48.858,48.003 C45.501,44.117 43.128,39.383 42.108,34.14 C39.852,39.504 34.548,43.269 28.365,43.269 C20.133,43.269 13.46,36.597 13.46,28.365 C13.46,20.134 20.133,13.46 28.365,13.46 C36.966,13.46 43.27,20.577 43.27,28.365 C43.27,44.031 55.97,56.731 71.636,56.731 C87.3,56.731 100,44.031 100,28.365 C100,12.7 87.3,0 71.636,0 C63.589,0 56.327,3.358 51.165,8.742 Z" id="path-1"></path> | |||
| </defs> | |||
| <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||
| <g id="portal-logo"> | |||
| <circle id="Oval" fill="#51B37F" fill-rule="nonzero" cx="107.5" cy="107.5" r="107.5"></circle> | |||
| <g id="logo" transform="translate(58.000000, 79.000000)"> | |||
| <mask id="mask-2" fill="white"> | |||
| <use xlink:href="#path-1"></use> | |||
| </mask> | |||
| <g id="Clip-2"></g> | |||
| <polygon id="Fill-1" fill="#FFFFFE" mask="url(#mask-2)" points="-5 61.73 105 61.73 105 -5 -5 -5"></polygon> | |||
| </g> | |||
| </g> | |||
| </g> | |||
| </svg> | |||
| @ -1,21 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <svg width="215px" height="215px" viewBox="0 0 215 215" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |||
| <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch --> | |||
| <title>portal-logo</title> | |||
| <desc>Created with Sketch.</desc> | |||
| <defs> | |||
| <path d="M51.165,8.742 C54.505,12.619 56.876,17.365 57.892,22.588 C60.148,17.225 65.452,13.46 71.636,13.46 C79.867,13.46 86.541,20.134 86.541,28.365 C86.541,36.597 79.867,43.269 71.636,43.269 C63.404,43.269 56.728,36.597 56.728,28.365 C56.728,12.7 44.03,0 28.365,0 C12.7,0 0,12.7 0,28.365 C0,44.031 12.7,56.731 28.365,56.731 C36.419,56.731 43.695,53.393 48.858,48.003 C45.501,44.117 43.128,39.383 42.108,34.14 C39.852,39.504 34.548,43.269 28.365,43.269 C20.133,43.269 13.46,36.597 13.46,28.365 C13.46,20.134 20.133,13.46 28.365,13.46 C36.966,13.46 43.27,20.577 43.27,28.365 C43.27,44.031 55.97,56.731 71.636,56.731 C87.3,56.731 100,44.031 100,28.365 C100,12.7 87.3,0 71.636,0 C63.589,0 56.327,3.358 51.165,8.742 Z" id="path-1"></path> | |||
| </defs> | |||
| <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | |||
| <g id="portal-logo"> | |||
| <circle id="Oval" fill="#09B6CA" fill-rule="nonzero" cx="107.5" cy="107.5" r="107.5"></circle> | |||
| <g id="logo" transform="translate(58.000000, 79.000000)"> | |||
| <mask id="mask-2" fill="white"> | |||
| <use xlink:href="#path-1"></use> | |||
| </mask> | |||
| <g id="Clip-2"></g> | |||
| <polygon id="Fill-1" fill="#FFFFFE" mask="url(#mask-2)" points="-5 61.73 105 61.73 105 -5 -5 -5"></polygon> | |||
| </g> | |||
| </g> | |||
| </g> | |||
| </svg> | |||
| @ -1,18 +0,0 @@ | |||
| <svg width="400" height="400" xmlns="http://www.w3.org/2000/svg"> | |||
| <!-- Fondo --> | |||
| <rect width="400" height="400" fill="#ffffff" /> | |||
| <!-- Corona --> | |||
| <g transform="translate(100, 100) scale(2)"> | |||
| <polygon points="50,150 75,50 100,150" fill="#FFD700" /> | |||
| <polygon points="0,150 50,0 100,150" fill="#FFD700" /> | |||
| <polygon points="100,150 125,50 150,150" fill="#FFD700" /> | |||
| </g> | |||
| <!-- Letra R --> | |||
| <!-- | |||
| <text x="100" y="360" font-family="Arial, sans-serif" font-size="400" fill="#000000" font-weight="bold">R</text> | |||
| --> | |||
| <text x="100" y="360" font-family="Open Sans" font-size="400" fill="#000000" font-weight="bold">R</text> | |||
| </svg> | |||
| @ -1,96 +0,0 @@ | |||
| 'use strict'; | |||
| /* ===== Enable Bootstrap Popover (on element ====== */ | |||
| const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]') | |||
| const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)) | |||
| /* ==== Enable Bootstrap Alert ====== */ | |||
| //var alertList = document.querySelectorAll('.alert') | |||
| //alertList.forEach(function (alert) { | |||
| // new bootstrap.Alert(alert) | |||
| //}); | |||
| const alertList = document.querySelectorAll('.alert') | |||
| const alerts = [...alertList].map(element => new bootstrap.Alert(element)) | |||
| /* ===== Responsive Sidepanel ====== */ | |||
| const sidePanelToggler = document.getElementById('sidepanel-toggler'); | |||
| const sidePanel = document.getElementById('app-sidepanel'); | |||
| const sidePanelDrop = document.getElementById('sidepanel-drop'); | |||
| const sidePanelClose = document.getElementById('sidepanel-close'); | |||
| window.addEventListener('load', function(){ | |||
| responsiveSidePanel(); | |||
| }); | |||
| window.addEventListener('resize', function(){ | |||
| responsiveSidePanel(); | |||
| }); | |||
| function responsiveSidePanel() { | |||
| let w = window.innerWidth; | |||
| if(w >= 1200) { | |||
| // if larger | |||
| //console.log('larger'); | |||
| sidePanel.classList.remove('sidepanel-hidden'); | |||
| sidePanel.classList.add('sidepanel-visible'); | |||
| } else { | |||
| // if smaller | |||
| //console.log('smaller'); | |||
| sidePanel.classList.remove('sidepanel-visible'); | |||
| sidePanel.classList.add('sidepanel-hidden'); | |||
| } | |||
| }; | |||
| sidePanelToggler.addEventListener('click', () => { | |||
| if (sidePanel.classList.contains('sidepanel-visible')) { | |||
| console.log('visible'); | |||
| sidePanel.classList.remove('sidepanel-visible'); | |||
| sidePanel.classList.add('sidepanel-hidden'); | |||
| } else { | |||
| console.log('hidden'); | |||
| sidePanel.classList.remove('sidepanel-hidden'); | |||
| sidePanel.classList.add('sidepanel-visible'); | |||
| } | |||
| }); | |||
| sidePanelClose.addEventListener('click', (e) => { | |||
| e.preventDefault(); | |||
| sidePanelToggler.click(); | |||
| }); | |||
| sidePanelDrop.addEventListener('click', (e) => { | |||
| sidePanelToggler.click(); | |||
| }); | |||
| /* ====== Mobile search ======= */ | |||
| const searchMobileTrigger = document.querySelector('.search-mobile-trigger'); | |||
| const searchBox = document.querySelector('.app-search-box'); | |||
| searchMobileTrigger.addEventListener('click', () => { | |||
| searchBox.classList.toggle('is-visible'); | |||
| let searchMobileTriggerIcon = document.querySelector('.search-mobile-trigger-icon'); | |||
| if(searchMobileTriggerIcon.classList.contains('fa-magnifying-glass')) { | |||
| searchMobileTriggerIcon.classList.remove('fa-magnifying-glass'); | |||
| searchMobileTriggerIcon.classList.add('fa-xmark'); | |||
| } else { | |||
| searchMobileTriggerIcon.classList.remove('fa-xmark'); | |||
| searchMobileTriggerIcon.classList.add('fa-magnifying-glass'); | |||
| } | |||
| }); | |||
| @ -1,366 +0,0 @@ | |||
| 'use strict'; | |||
| /* Chart.js docs: https://www.chartjs.org/ */ | |||
| window.chartColors = { | |||
| green: '#75c181', // rgba(117,193,129, 1) | |||
| blue: '#5b99ea', // rgba(91,153,234, 1) | |||
| gray: '#a9b5c9', | |||
| text: '#252930', | |||
| border: '#e7e9ed' | |||
| }; | |||
| /* Random number generator for demo purpose */ | |||
| var randomDataPoint = function(){ return Math.round(Math.random()*100)}; | |||
| //Area line Chart Demo | |||
| var lineChartConfig = { | |||
| type: 'line', | |||
| data: { | |||
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'], | |||
| datasets: [{ | |||
| label: 'Dataset', | |||
| backgroundColor: "rgba(117,193,129,0.2)", | |||
| borderColor: "rgba(117,193,129, 0.8)", | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint() | |||
| ], | |||
| }] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| legend: { | |||
| display: true, | |||
| position: 'bottom', | |||
| align: 'end', | |||
| }, | |||
| tooltips: { | |||
| mode: 'index', | |||
| intersect: false, | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| callbacks: { | |||
| label: function(tooltipItem, data) { | |||
| return tooltipItem.value + '%'; | |||
| } | |||
| }, | |||
| }, | |||
| hover: { | |||
| mode: 'nearest', | |||
| intersect: true | |||
| }, | |||
| scales: { | |||
| xAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| scaleLabel: { | |||
| display: false, | |||
| } | |||
| }], | |||
| yAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| scaleLabel: { | |||
| display: false, | |||
| }, | |||
| ticks: { | |||
| beginAtZero: true, | |||
| userCallback: function(value, index, values) { | |||
| return value.toLocaleString() + '%'; | |||
| } | |||
| }, | |||
| }] | |||
| } | |||
| } | |||
| }; | |||
| //Bar Chart Demo | |||
| var barChartConfig = { | |||
| type: 'bar', | |||
| data: { | |||
| labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'], | |||
| datasets: [{ | |||
| label: 'Dataset 1', | |||
| backgroundColor: "rgba(117,193,129,0.8)", | |||
| hoverBackgroundColor: "rgba(117,193,129,1)", | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint() | |||
| ] | |||
| }, | |||
| { | |||
| label: 'Dataset 2', | |||
| backgroundColor: "rgba(91,153,234,0.8)", | |||
| hoverBackgroundColor: "rgba(91,153,234,1)", | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint() | |||
| ] | |||
| } | |||
| ] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| legend: { | |||
| position: 'bottom', | |||
| align: 'end', | |||
| }, | |||
| tooltips: { | |||
| mode: 'index', | |||
| intersect: false, | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| callbacks: { | |||
| label: function(tooltipItem, data) { | |||
| return tooltipItem.value + '%'; | |||
| } | |||
| }, | |||
| }, | |||
| scales: { | |||
| xAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| }], | |||
| yAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.borders, | |||
| }, | |||
| ticks: { | |||
| beginAtZero: true, | |||
| userCallback: function(value, index, values) { | |||
| return value + '%'; | |||
| } | |||
| }, | |||
| }] | |||
| } | |||
| } | |||
| } | |||
| // Pie Chart Demo | |||
| var pieChartConfig = { | |||
| type: 'pie', | |||
| data: { | |||
| datasets: [{ | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| ], | |||
| backgroundColor: [ | |||
| window.chartColors.green, | |||
| window.chartColors.blue, | |||
| window.chartColors.gray, | |||
| ], | |||
| label: 'Dataset 1' | |||
| }], | |||
| labels: [ | |||
| 'Green', | |||
| 'Blue', | |||
| 'Gray', | |||
| ] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| legend: { | |||
| display: true, | |||
| position: 'bottom', | |||
| align: 'center', | |||
| }, | |||
| tooltips: { | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| /* Display % in tooltip - https://stackoverflow.com/questions/37257034/chart-js-2-0-doughnut-tooltip-percentages */ | |||
| callbacks: { | |||
| label: function(tooltipItem, data) { | |||
| //get the concerned dataset | |||
| var dataset = data.datasets[tooltipItem.datasetIndex]; | |||
| //calculate the total of this data set | |||
| var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) { | |||
| return previousValue + currentValue; | |||
| }); | |||
| //get the current items value | |||
| var currentValue = dataset.data[tooltipItem.index]; | |||
| //calculate the precentage based on the total and current item, also this does a rough rounding to give a whole number | |||
| var percentage = Math.floor(((currentValue/total) * 100)+0.5); | |||
| return percentage + "%"; | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| }; | |||
| // Doughnut Chart Demo | |||
| var doughnutChartConfig = { | |||
| type: 'doughnut', | |||
| data: { | |||
| datasets: [{ | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| ], | |||
| backgroundColor: [ | |||
| window.chartColors.green, | |||
| window.chartColors.blue, | |||
| window.chartColors.gray, | |||
| ], | |||
| label: 'Dataset 1' | |||
| }], | |||
| labels: [ | |||
| 'Green', | |||
| 'Blue', | |||
| 'Gray', | |||
| ] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| legend: { | |||
| display: true, | |||
| position: 'bottom', | |||
| align: 'center', | |||
| }, | |||
| tooltips: { | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| animation: { | |||
| animateScale: true, | |||
| animateRotate: true | |||
| }, | |||
| /* Display % in tooltip - https://stackoverflow.com/questions/37257034/chart-js-2-0-doughnut-tooltip-percentages */ | |||
| callbacks: { | |||
| label: function(tooltipItem, data) { | |||
| //get the concerned dataset | |||
| var dataset = data.datasets[tooltipItem.datasetIndex]; | |||
| //calculate the total of this data set | |||
| var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) { | |||
| return previousValue + currentValue; | |||
| }); | |||
| //get the current items value | |||
| var currentValue = dataset.data[tooltipItem.index]; | |||
| //calculate the precentage based on the total and current item, also this does a rough rounding to give a whole number | |||
| var percentage = Math.floor(((currentValue/total) * 100)+0.5); | |||
| return percentage + "%"; | |||
| }, | |||
| }, | |||
| }, | |||
| } | |||
| }; | |||
| // Generate charts on load | |||
| window.addEventListener('load', function(){ | |||
| var lineChart = document.getElementById('chart-line').getContext('2d'); | |||
| window.myLine = new Chart(lineChart, lineChartConfig); | |||
| var barChart = document.getElementById('chart-bar').getContext('2d'); | |||
| window.myBar = new Chart(barChart, barChartConfig); | |||
| var pieChart = document.getElementById('chart-pie').getContext('2d'); | |||
| window.myPie = new Chart(pieChart, pieChartConfig); | |||
| var doughnutChart = document.getElementById('chart-doughnut').getContext('2d'); | |||
| window.myDoughnut = new Chart(doughnutChart, doughnutChartConfig); | |||
| }); | |||
| @ -1,224 +0,0 @@ | |||
| 'use strict'; | |||
| /* Chart.js docs: https://www.chartjs.org/ */ | |||
| window.chartColors = { | |||
| green: '#75c181', | |||
| gray: '#a9b5c9', | |||
| text: '#252930', | |||
| border: '#e7e9ed' | |||
| }; | |||
| /* Random number generator for demo purpose */ | |||
| var randomDataPoint = function(){ return Math.round(Math.random()*10000)}; | |||
| //Chart.js Line Chart Example | |||
| var lineChartConfig = { | |||
| type: 'line', | |||
| data: { | |||
| labels: ['Day 1', 'Day 2', 'Day 3', 'Day 4', 'Day 5', 'Day 6', 'Day 7'], | |||
| datasets: [{ | |||
| label: 'Current week', | |||
| fill: false, | |||
| backgroundColor: window.chartColors.green, | |||
| borderColor: window.chartColors.green, | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint() | |||
| ], | |||
| }, { | |||
| label: 'Previous week', | |||
| borderDash: [3, 5], | |||
| backgroundColor: window.chartColors.gray, | |||
| borderColor: window.chartColors.gray, | |||
| data: [ | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint(), | |||
| randomDataPoint() | |||
| ], | |||
| fill: false, | |||
| }] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| aspectRatio: 1.5, | |||
| legend: { | |||
| display: true, | |||
| position: 'bottom', | |||
| align: 'end', | |||
| }, | |||
| title: { | |||
| display: true, | |||
| text: 'Chart.js Line Chart Example', | |||
| }, | |||
| tooltips: { | |||
| mode: 'index', | |||
| intersect: false, | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| callbacks: { | |||
| //Ref: https://stackoverflow.com/questions/38800226/chart-js-add-commas-to-tooltip-and-y-axis | |||
| label: function(tooltipItem, data) { | |||
| if (parseInt(tooltipItem.value) >= 1000) { | |||
| return "$" + tooltipItem.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |||
| } else { | |||
| return '$' + tooltipItem.value; | |||
| } | |||
| } | |||
| }, | |||
| }, | |||
| hover: { | |||
| mode: 'nearest', | |||
| intersect: true | |||
| }, | |||
| scales: { | |||
| xAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| scaleLabel: { | |||
| display: false, | |||
| } | |||
| }], | |||
| yAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| scaleLabel: { | |||
| display: false, | |||
| }, | |||
| ticks: { | |||
| beginAtZero: true, | |||
| userCallback: function(value, index, values) { | |||
| return '$' + value.toLocaleString(); //Ref: https://stackoverflow.com/questions/38800226/chart-js-add-commas-to-tooltip-and-y-axis | |||
| } | |||
| }, | |||
| }] | |||
| } | |||
| } | |||
| }; | |||
| // Chart.js Bar Chart Example | |||
| var barChartConfig = { | |||
| type: 'bar', | |||
| data: { | |||
| labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||
| datasets: [{ | |||
| label: 'Orders', | |||
| backgroundColor: window.chartColors.green, | |||
| borderColor: window.chartColors.green, | |||
| borderWidth: 1, | |||
| maxBarThickness: 16, | |||
| data: [ | |||
| 23, | |||
| 45, | |||
| 76, | |||
| 75, | |||
| 62, | |||
| 37, | |||
| 83 | |||
| ] | |||
| }] | |||
| }, | |||
| options: { | |||
| responsive: true, | |||
| aspectRatio: 1.5, | |||
| legend: { | |||
| position: 'bottom', | |||
| align: 'end', | |||
| }, | |||
| title: { | |||
| display: true, | |||
| text: 'Chart.js Bar Chart Example' | |||
| }, | |||
| tooltips: { | |||
| mode: 'index', | |||
| intersect: false, | |||
| titleMarginBottom: 10, | |||
| bodySpacing: 10, | |||
| xPadding: 16, | |||
| yPadding: 16, | |||
| borderColor: window.chartColors.border, | |||
| borderWidth: 1, | |||
| backgroundColor: '#fff', | |||
| bodyFontColor: window.chartColors.text, | |||
| titleFontColor: window.chartColors.text, | |||
| }, | |||
| scales: { | |||
| xAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.border, | |||
| }, | |||
| }], | |||
| yAxes: [{ | |||
| display: true, | |||
| gridLines: { | |||
| drawBorder: false, | |||
| color: window.chartColors.borders, | |||
| }, | |||
| }] | |||
| } | |||
| } | |||
| } | |||
| // Generate charts on load | |||
| window.addEventListener('load', function(){ | |||
| var lineChart = document.getElementById('canvas-linechart').getContext('2d'); | |||
| window.myLine = new Chart(lineChart, lineChartConfig); | |||
| var barChart = document.getElementById('canvas-barchart').getContext('2d'); | |||
| window.myBar = new Chart(barChart, barChartConfig); | |||
| }); | |||
| @ -1,593 +0,0 @@ | |||
| /*! | |||
| * Bootstrap Reboot v5.3.0 (https://getbootstrap.com/) | |||
| * Copyright 2011-2023 The Bootstrap Authors | |||
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) | |||
| */ | |||
| :root, | |||
| [data-bs-theme=light] { | |||
| --bs-blue: #0d6efd; | |||
| --bs-indigo: #6610f2; | |||
| --bs-purple: #6f42c1; | |||
| --bs-pink: #d63384; | |||
| --bs-red: #dc3545; | |||
| --bs-orange: #fd7e14; | |||
| --bs-yellow: #ffc107; | |||
| --bs-green: #198754; | |||
| --bs-teal: #20c997; | |||
| --bs-cyan: #0dcaf0; | |||
| --bs-black: #000; | |||
| --bs-white: #fff; | |||
| --bs-gray: #6c757d; | |||
| --bs-gray-dark: #343a40; | |||
| --bs-gray-100: #f8f9fa; | |||
| --bs-gray-200: #e9ecef; | |||
| --bs-gray-300: #dee2e6; | |||
| --bs-gray-400: #ced4da; | |||
| --bs-gray-500: #adb5bd; | |||
| --bs-gray-600: #6c757d; | |||
| --bs-gray-700: #495057; | |||
| --bs-gray-800: #343a40; | |||
| --bs-gray-900: #212529; | |||
| --bs-primary: #0d6efd; | |||
| --bs-secondary: #6c757d; | |||
| --bs-success: #198754; | |||
| --bs-info: #0dcaf0; | |||
| --bs-warning: #ffc107; | |||
| --bs-danger: #dc3545; | |||
| --bs-light: #f8f9fa; | |||
| --bs-dark: #212529; | |||
| --bs-primary-rgb: 13, 110, 253; | |||
| --bs-secondary-rgb: 108, 117, 125; | |||
| --bs-success-rgb: 25, 135, 84; | |||
| --bs-info-rgb: 13, 202, 240; | |||
| --bs-warning-rgb: 255, 193, 7; | |||
| --bs-danger-rgb: 220, 53, 69; | |||
| --bs-light-rgb: 248, 249, 250; | |||
| --bs-dark-rgb: 33, 37, 41; | |||
| --bs-primary-text-emphasis: #052c65; | |||
| --bs-secondary-text-emphasis: #2b2f32; | |||
| --bs-success-text-emphasis: #0a3622; | |||
| --bs-info-text-emphasis: #055160; | |||
| --bs-warning-text-emphasis: #664d03; | |||
| --bs-danger-text-emphasis: #58151c; | |||
| --bs-light-text-emphasis: #495057; | |||
| --bs-dark-text-emphasis: #495057; | |||
| --bs-primary-bg-subtle: #cfe2ff; | |||
| --bs-secondary-bg-subtle: #e2e3e5; | |||
| --bs-success-bg-subtle: #d1e7dd; | |||
| --bs-info-bg-subtle: #cff4fc; | |||
| --bs-warning-bg-subtle: #fff3cd; | |||
| --bs-danger-bg-subtle: #f8d7da; | |||
| --bs-light-bg-subtle: #fcfcfd; | |||
| --bs-dark-bg-subtle: #ced4da; | |||
| --bs-primary-border-subtle: #9ec5fe; | |||
| --bs-secondary-border-subtle: #c4c8cb; | |||
| --bs-success-border-subtle: #a3cfbb; | |||
| --bs-info-border-subtle: #9eeaf9; | |||
| --bs-warning-border-subtle: #ffe69c; | |||
| --bs-danger-border-subtle: #f1aeb5; | |||
| --bs-light-border-subtle: #e9ecef; | |||
| --bs-dark-border-subtle: #adb5bd; | |||
| --bs-white-rgb: 255, 255, 255; | |||
| --bs-black-rgb: 0, 0, 0; | |||
| --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | |||
| --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | |||
| --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); | |||
| --bs-body-font-family: var(--bs-font-sans-serif); | |||
| --bs-body-font-size: 1rem; | |||
| --bs-body-font-weight: 400; | |||
| --bs-body-line-height: 1.5; | |||
| --bs-body-color: #212529; | |||
| --bs-body-color-rgb: 33, 37, 41; | |||
| --bs-body-bg: #fff; | |||
| --bs-body-bg-rgb: 255, 255, 255; | |||
| --bs-emphasis-color: #000; | |||
| --bs-emphasis-color-rgb: 0, 0, 0; | |||
| --bs-secondary-color: rgba(33, 37, 41, 0.75); | |||
| --bs-secondary-color-rgb: 33, 37, 41; | |||
| --bs-secondary-bg: #e9ecef; | |||
| --bs-secondary-bg-rgb: 233, 236, 239; | |||
| --bs-tertiary-color: rgba(33, 37, 41, 0.5); | |||
| --bs-tertiary-color-rgb: 33, 37, 41; | |||
| --bs-tertiary-bg: #f8f9fa; | |||
| --bs-tertiary-bg-rgb: 248, 249, 250; | |||
| --bs-heading-color: inherit; | |||
| --bs-link-color: #0d6efd; | |||
| --bs-link-color-rgb: 13, 110, 253; | |||
| --bs-link-decoration: underline; | |||
| --bs-link-hover-color: #0a58ca; | |||
| --bs-link-hover-color-rgb: 10, 88, 202; | |||
| --bs-code-color: #d63384; | |||
| --bs-highlight-bg: #fff3cd; | |||
| --bs-border-width: 1px; | |||
| --bs-border-style: solid; | |||
| --bs-border-color: #dee2e6; | |||
| --bs-border-color-translucent: rgba(0, 0, 0, 0.175); | |||
| --bs-border-radius: 0.375rem; | |||
| --bs-border-radius-sm: 0.25rem; | |||
| --bs-border-radius-lg: 0.5rem; | |||
| --bs-border-radius-xl: 1rem; | |||
| --bs-border-radius-xxl: 2rem; | |||
| --bs-border-radius-2xl: var(--bs-border-radius-xxl); | |||
| --bs-border-radius-pill: 50rem; | |||
| --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); | |||
| --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); | |||
| --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); | |||
| --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); | |||
| --bs-focus-ring-width: 0.25rem; | |||
| --bs-focus-ring-opacity: 0.25; | |||
| --bs-focus-ring-color: rgba(13, 110, 253, 0.25); | |||
| --bs-form-valid-color: #198754; | |||
| --bs-form-valid-border-color: #198754; | |||
| --bs-form-invalid-color: #dc3545; | |||
| --bs-form-invalid-border-color: #dc3545; | |||
| } | |||
| [data-bs-theme=dark] { | |||
| color-scheme: dark; | |||
| --bs-body-color: #adb5bd; | |||
| --bs-body-color-rgb: 173, 181, 189; | |||
| --bs-body-bg: #212529; | |||
| --bs-body-bg-rgb: 33, 37, 41; | |||
| --bs-emphasis-color: #fff; | |||
| --bs-emphasis-color-rgb: 255, 255, 255; | |||
| --bs-secondary-color: rgba(173, 181, 189, 0.75); | |||
| --bs-secondary-color-rgb: 173, 181, 189; | |||
| --bs-secondary-bg: #343a40; | |||
| --bs-secondary-bg-rgb: 52, 58, 64; | |||
| --bs-tertiary-color: rgba(173, 181, 189, 0.5); | |||
| --bs-tertiary-color-rgb: 173, 181, 189; | |||
| --bs-tertiary-bg: #2b3035; | |||
| --bs-tertiary-bg-rgb: 43, 48, 53; | |||
| --bs-primary-text-emphasis: #6ea8fe; | |||
| --bs-secondary-text-emphasis: #a7acb1; | |||
| --bs-success-text-emphasis: #75b798; | |||
| --bs-info-text-emphasis: #6edff6; | |||
| --bs-warning-text-emphasis: #ffda6a; | |||
| --bs-danger-text-emphasis: #ea868f; | |||
| --bs-light-text-emphasis: #f8f9fa; | |||
| --bs-dark-text-emphasis: #dee2e6; | |||
| --bs-primary-bg-subtle: #031633; | |||
| --bs-secondary-bg-subtle: #161719; | |||
| --bs-success-bg-subtle: #051b11; | |||
| --bs-info-bg-subtle: #032830; | |||
| --bs-warning-bg-subtle: #332701; | |||
| --bs-danger-bg-subtle: #2c0b0e; | |||
| --bs-light-bg-subtle: #343a40; | |||
| --bs-dark-bg-subtle: #1a1d20; | |||
| --bs-primary-border-subtle: #084298; | |||
| --bs-secondary-border-subtle: #41464b; | |||
| --bs-success-border-subtle: #0f5132; | |||
| --bs-info-border-subtle: #087990; | |||
| --bs-warning-border-subtle: #997404; | |||
| --bs-danger-border-subtle: #842029; | |||
| --bs-light-border-subtle: #495057; | |||
| --bs-dark-border-subtle: #343a40; | |||
| --bs-heading-color: inherit; | |||
| --bs-link-color: #6ea8fe; | |||
| --bs-link-hover-color: #8bb9fe; | |||
| --bs-link-color-rgb: 110, 168, 254; | |||
| --bs-link-hover-color-rgb: 139, 185, 254; | |||
| --bs-code-color: #e685b5; | |||
| --bs-border-color: #495057; | |||
| --bs-border-color-translucent: rgba(255, 255, 255, 0.15); | |||
| --bs-form-valid-color: #75b798; | |||
| --bs-form-valid-border-color: #75b798; | |||
| --bs-form-invalid-color: #ea868f; | |||
| --bs-form-invalid-border-color: #ea868f; | |||
| } | |||
| *, | |||
| *::before, | |||
| *::after { | |||
| box-sizing: border-box; | |||
| } | |||
| @media (prefers-reduced-motion: no-preference) { | |||
| :root { | |||
| scroll-behavior: smooth; | |||
| } | |||
| } | |||
| body { | |||
| margin: 0; | |||
| font-family: var(--bs-body-font-family); | |||
| font-size: var(--bs-body-font-size); | |||
| font-weight: var(--bs-body-font-weight); | |||
| line-height: var(--bs-body-line-height); | |||
| color: var(--bs-body-color); | |||
| text-align: var(--bs-body-text-align); | |||
| background-color: var(--bs-body-bg); | |||
| -webkit-text-size-adjust: 100%; | |||
| -webkit-tap-highlight-color: rgba(0, 0, 0, 0); | |||
| } | |||
| hr { | |||
| margin: 1rem 0; | |||
| color: inherit; | |||
| border: 0; | |||
| border-top: var(--bs-border-width) solid; | |||
| opacity: 0.25; | |||
| } | |||
| h6, h5, h4, h3, h2, h1 { | |||
| margin-top: 0; | |||
| margin-bottom: 0.5rem; | |||
| font-weight: 500; | |||
| line-height: 1.2; | |||
| color: var(--bs-heading-color); | |||
| } | |||
| h1 { | |||
| font-size: calc(1.375rem + 1.5vw); | |||
| } | |||
| @media (min-width: 1200px) { | |||
| h1 { | |||
| font-size: 2.5rem; | |||
| } | |||
| } | |||
| h2 { | |||
| font-size: calc(1.325rem + 0.9vw); | |||
| } | |||
| @media (min-width: 1200px) { | |||
| h2 { | |||
| font-size: 2rem; | |||
| } | |||
| } | |||
| h3 { | |||
| font-size: calc(1.3rem + 0.6vw); | |||
| } | |||
| @media (min-width: 1200px) { | |||
| h3 { | |||
| font-size: 1.75rem; | |||
| } | |||
| } | |||
| h4 { | |||
| font-size: calc(1.275rem + 0.3vw); | |||
| } | |||
| @media (min-width: 1200px) { | |||
| h4 { | |||
| font-size: 1.5rem; | |||
| } | |||
| } | |||
| h5 { | |||
| font-size: 1.25rem; | |||
| } | |||
| h6 { | |||
| font-size: 1rem; | |||
| } | |||
| p { | |||
| margin-top: 0; | |||
| margin-bottom: 1rem; | |||
| } | |||
| abbr[title] { | |||
| -webkit-text-decoration: underline dotted; | |||
| text-decoration: underline dotted; | |||
| cursor: help; | |||
| -webkit-text-decoration-skip-ink: none; | |||
| text-decoration-skip-ink: none; | |||
| } | |||
| address { | |||
| margin-bottom: 1rem; | |||
| font-style: normal; | |||
| line-height: inherit; | |||
| } | |||
| ol, | |||
| ul { | |||
| padding-left: 2rem; | |||
| } | |||
| ol, | |||
| ul, | |||
| dl { | |||
| margin-top: 0; | |||
| margin-bottom: 1rem; | |||
| } | |||
| ol ol, | |||
| ul ul, | |||
| ol ul, | |||
| ul ol { | |||
| margin-bottom: 0; | |||
| } | |||
| dt { | |||
| font-weight: 700; | |||
| } | |||
| dd { | |||
| margin-bottom: 0.5rem; | |||
| margin-left: 0; | |||
| } | |||
| blockquote { | |||
| margin: 0 0 1rem; | |||
| } | |||
| b, | |||
| strong { | |||
| font-weight: bolder; | |||
| } | |||
| small { | |||
| font-size: 0.875em; | |||
| } | |||
| mark { | |||
| padding: 0.1875em; | |||
| background-color: var(--bs-highlight-bg); | |||
| } | |||
| sub, | |||
| sup { | |||
| position: relative; | |||
| font-size: 0.75em; | |||
| line-height: 0; | |||
| vertical-align: baseline; | |||
| } | |||
| sub { | |||
| bottom: -0.25em; | |||
| } | |||
| sup { | |||
| top: -0.5em; | |||
| } | |||
| a { | |||
| color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); | |||
| text-decoration: underline; | |||
| } | |||
| a:hover { | |||
| --bs-link-color-rgb: var(--bs-link-hover-color-rgb); | |||
| } | |||
| a:not([href]):not([class]), a:not([href]):not([class]):hover { | |||
| color: inherit; | |||
| text-decoration: none; | |||
| } | |||
| pre, | |||
| code, | |||
| kbd, | |||
| samp { | |||
| font-family: var(--bs-font-monospace); | |||
| font-size: 1em; | |||
| } | |||
| pre { | |||
| display: block; | |||
| margin-top: 0; | |||
| margin-bottom: 1rem; | |||
| overflow: auto; | |||
| font-size: 0.875em; | |||
| } | |||
| pre code { | |||
| font-size: inherit; | |||
| color: inherit; | |||
| word-break: normal; | |||
| } | |||
| code { | |||
| font-size: 0.875em; | |||
| color: var(--bs-code-color); | |||
| word-wrap: break-word; | |||
| } | |||
| a > code { | |||
| color: inherit; | |||
| } | |||
| kbd { | |||
| padding: 0.1875rem 0.375rem; | |||
| font-size: 0.875em; | |||
| color: var(--bs-body-bg); | |||
| background-color: var(--bs-body-color); | |||
| border-radius: 0.25rem; | |||
| } | |||
| kbd kbd { | |||
| padding: 0; | |||
| font-size: 1em; | |||
| } | |||
| figure { | |||
| margin: 0 0 1rem; | |||
| } | |||
| img, | |||
| svg { | |||
| vertical-align: middle; | |||
| } | |||
| table { | |||
| caption-side: bottom; | |||
| border-collapse: collapse; | |||
| } | |||
| caption { | |||
| padding-top: 0.5rem; | |||
| padding-bottom: 0.5rem; | |||
| color: var(--bs-secondary-color); | |||
| text-align: left; | |||
| } | |||
| th { | |||
| text-align: inherit; | |||
| text-align: -webkit-match-parent; | |||
| } | |||
| thead, | |||
| tbody, | |||
| tfoot, | |||
| tr, | |||
| td, | |||
| th { | |||
| border-color: inherit; | |||
| border-style: solid; | |||
| border-width: 0; | |||
| } | |||
| label { | |||
| display: inline-block; | |||
| } | |||
| button { | |||
| border-radius: 0; | |||
| } | |||
| button:focus:not(:focus-visible) { | |||
| outline: 0; | |||
| } | |||
| input, | |||
| button, | |||
| select, | |||
| optgroup, | |||
| textarea { | |||
| margin: 0; | |||
| font-family: inherit; | |||
| font-size: inherit; | |||
| line-height: inherit; | |||
| } | |||
| button, | |||
| select { | |||
| text-transform: none; | |||
| } | |||
| [role=button] { | |||
| cursor: pointer; | |||
| } | |||
| select { | |||
| word-wrap: normal; | |||
| } | |||
| select:disabled { | |||
| opacity: 1; | |||
| } | |||
| [list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { | |||
| display: none !important; | |||
| } | |||
| button, | |||
| [type=button], | |||
| [type=reset], | |||
| [type=submit] { | |||
| -webkit-appearance: button; | |||
| } | |||
| button:not(:disabled), | |||
| [type=button]:not(:disabled), | |||
| [type=reset]:not(:disabled), | |||
| [type=submit]:not(:disabled) { | |||
| cursor: pointer; | |||
| } | |||
| ::-moz-focus-inner { | |||
| padding: 0; | |||
| border-style: none; | |||
| } | |||
| textarea { | |||
| resize: vertical; | |||
| } | |||
| fieldset { | |||
| min-width: 0; | |||
| padding: 0; | |||
| margin: 0; | |||
| border: 0; | |||
| } | |||
| legend { | |||
| float: left; | |||
| width: 100%; | |||
| padding: 0; | |||
| margin-bottom: 0.5rem; | |||
| font-size: calc(1.275rem + 0.3vw); | |||
| line-height: inherit; | |||
| } | |||
| @media (min-width: 1200px) { | |||
| legend { | |||
| font-size: 1.5rem; | |||
| } | |||
| } | |||
| legend + * { | |||
| clear: left; | |||
| } | |||
| ::-webkit-datetime-edit-fields-wrapper, | |||
| ::-webkit-datetime-edit-text, | |||
| ::-webkit-datetime-edit-minute, | |||
| ::-webkit-datetime-edit-hour-field, | |||
| ::-webkit-datetime-edit-day-field, | |||
| ::-webkit-datetime-edit-month-field, | |||
| ::-webkit-datetime-edit-year-field { | |||
| padding: 0; | |||
| } | |||
| ::-webkit-inner-spin-button { | |||
| height: auto; | |||
| } | |||
| [type=search] { | |||
| outline-offset: -2px; | |||
| -webkit-appearance: textfield; | |||
| } | |||
| /* rtl:raw: | |||
| [type="tel"], | |||
| [type="url"], | |||
| [type="email"], | |||
| [type="number"] { | |||
| direction: ltr; | |||
| } | |||
| */ | |||
| ::-webkit-search-decoration { | |||
| -webkit-appearance: none; | |||
| } | |||
| ::-webkit-color-swatch-wrapper { | |||
| padding: 0; | |||
| } | |||
| ::-webkit-file-upload-button { | |||
| font: inherit; | |||
| -webkit-appearance: button; | |||
| } | |||
| ::file-selector-button { | |||
| font: inherit; | |||
| -webkit-appearance: button; | |||
| } | |||
| output { | |||
| display: inline-block; | |||
| } | |||
| iframe { | |||
| border: 0; | |||
| } | |||
| summary { | |||
| display: list-item; | |||
| cursor: pointer; | |||
| } | |||
| progress { | |||
| vertical-align: baseline; | |||
| } | |||
| [hidden] { | |||
| display: none !important; | |||
| } | |||
| /*# sourceMappingURL=bootstrap-reboot.css.map */ | |||