├── .circleci └── config.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── assets ├── django-bulma-logo.png └── django-bulma-logo.svg ├── bulma ├── __init__.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── bulma.py │ │ └── copy_bulma_static_into_project.py ├── static │ └── bulma │ │ ├── css │ │ ├── style.css │ │ ├── style.css.map │ │ └── style.min.css │ │ └── sass │ │ ├── .gitignore │ │ ├── package-lock.json │ │ ├── package.json │ │ └── style.sass ├── templates │ ├── _layouts │ │ └── one-column-center.html │ ├── base.html │ ├── bulma │ │ ├── base.html │ │ └── forms │ │ │ ├── field.html │ │ │ ├── form.html │ │ │ └── formset.html │ ├── pagination.html │ └── registration │ │ ├── base.html │ │ ├── logged_out.html │ │ ├── login.html │ │ ├── password_change_done.html │ │ ├── password_change_form.html │ │ ├── password_reset_complete.html │ │ ├── password_reset_confirm.html │ │ ├── password_reset_done.html │ │ ├── password_reset_email.html │ │ └── password_reset_form.html ├── templatetags │ ├── __init__.py │ └── bulma_tags.py └── tests │ ├── __init__.py │ ├── conftest.py │ ├── forms.py │ ├── test_commands.py │ ├── test_inputs.py │ ├── test_templates.py │ └── utils.py ├── poetry.lock ├── pyproject.toml ├── showcase ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20180226_1645.py │ └── __init__.py ├── models.py ├── templates │ └── showcase │ │ ├── form.html │ │ └── paginated_list.html ├── urls.py └── views.py ├── test_project ├── __init__.py ├── manage.py ├── settings.py ├── templates │ ├── base.html │ └── home.html ├── urls.py └── wsgi.py └── tox.ini /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Python CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-python/ for more details 4 | # 5 | version: 2 6 | 7 | shared: &shared 8 | steps: 9 | - checkout 10 | 11 | - run: 12 | name: install node & npm 13 | command: | 14 | sudo apt-get -yqq --allow-releaseinfo-change update && sudo apt-get install -yqq nodejs npm 15 | 16 | # Download and cache dependencies 17 | - restore_cache: 18 | keys: 19 | - v1-dependencies-{{ checksum "poetry.lock" }} 20 | # fallback to using the latest cache if no exact match is found 21 | - v1-dependencies- 22 | 23 | - run: 24 | name: install dependencies 25 | command: | 26 | poetry install 27 | 28 | - save_cache: 29 | key: deps-{{ checksum "poetry.lock" }} 30 | paths: 31 | - /home/circleci/.cache/pypoetry/virtualenvs 32 | 33 | - run: 34 | name: run tests 35 | command: | 36 | poetry run tox 37 | 38 | - store_artifacts: 39 | path: test-reports 40 | destination: test-reports 41 | 42 | jobs: 43 | "python-3.7": 44 | <<: *shared 45 | docker: 46 | # specify the version you desire here 47 | # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` 48 | # check all Python images here: https://circleci.com/docs/2.0/circleci-images/#python 49 | - image: circleci/python:3.7.12-buster 50 | "python-3.8": 51 | <<: *shared 52 | docker: 53 | # specify the version you desire here 54 | # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` 55 | # check all Python images here: https://circleci.com/docs/2.0/circleci-images/#python 56 | - image: circleci/python:3.8.9-buster 57 | "python-3.9": 58 | <<: *shared 59 | docker: 60 | # specify the version you desire here 61 | # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` 62 | # check all Python images here: https://circleci.com/docs/2.0/circleci-images/#python 63 | - image: circleci/python:3.9.7-buster 64 | 65 | workflows: 66 | version: 2 67 | build: 68 | jobs: 69 | - "python-3.7" 70 | - "python-3.8" 71 | - "python-3.9" 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python ### 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # End of https://www.gitignore.io/api/python 102 | 103 | # Created by https://www.gitignore.io/api/pycharm 104 | 105 | ### PyCharm ### 106 | .idea 107 | 108 | # Created by https://www.gitignore.io/api/macos 109 | 110 | ### macOS ### 111 | *.DS_Store 112 | .AppleDouble 113 | .LSOverride 114 | 115 | # Icon must end with two \r 116 | Icon 117 | 118 | # Thumbnails 119 | ._* 120 | 121 | # Files that might appear in the root of a volume 122 | .DocumentRevisions-V100 123 | .fseventsd 124 | .Spotlight-V100 125 | .TemporaryItems 126 | .Trashes 127 | .VolumeIcon.icns 128 | .com.apple.timemachine.donotpresent 129 | 130 | # Directories potentially created on remote AFP share 131 | .AppleDB 132 | .AppleDesktop 133 | Network Trash Folder 134 | Temporary Items 135 | .apdisk 136 | 137 | # End of https://www.gitignore.io/api/macos 138 | 139 | # Example project 140 | demo/static/bulma 141 | bulma/tests/static 142 | demo/memory 143 | 144 | node_modules 145 | 146 | # version file is generated by setuptools_scm 147 | bulma/version.py 148 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Tim Kamanin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | update_bulma: 2 | cd ./bulma/static/bulma/sass && rm -f package-lock.json && npm i && npm run build && rm -rf ./node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Bulma Theme for Django Projects 2 | 3 | ![Django Bulma](https://raw.githubusercontent.com/timonweb/django-bulma/master/assets/django-bulma-logo.png) 4 | 5 | A Django base theme based on Bulma ([bulma.io](https://bulma.io/)). Bulma is a modern CSS framework based on Flexbox. 6 | 7 | *** work in progress *** 8 | 9 | ## Installation 10 | 11 | 1. Install the python package django-bulma from pip 12 | 13 | ``pip install django-bulma`` 14 | 15 | Alternatively, you can install download or clone this repo and call ``pip install -e .``. 16 | 17 | 2. Add to INSTALLED_APPS in your **settings.py**: 18 | 19 | `'bulma',` 20 | 21 | 3. If you want to use the provided base template, extend from **bulma/base.html**: 22 | 23 | ``` 24 | {% extends 'bulma/base.html' %} 25 | 26 | {% block title %}Bulma Site{% endblock %} 27 | 28 | {% block content %} 29 | Content goes here... 30 | {% endblock content %} 31 | 32 | ``` 33 | 34 | 4. If you want to customize bulma sass and your own components: 35 | 36 | 4.1 Copy bulma static files into your project's **STATIC_ROOT**: 37 | 38 | ``` 39 | python manage.py copy_bulma_static_into_project 40 | ``` 41 | You should see **bulma** dir appeared in your **STATIC_ROOT**. It contains 42 | two dirs: 43 | * **sass** - this is the place where you can put your own sass code and customize 44 | bulma variables 45 | * **css** - this is where compiled sass output goes, you should link this file 46 | in your base.html 47 | 48 | 4.2 Install npm packages for sass compilation to work: 49 | 50 | ``` 51 | python manage.py bulma install 52 | ``` 53 | 54 | 4.3 Start sass watch mode: 55 | ``` 56 | python manage.py bulma start 57 | ``` 58 | 59 | 5. For forms, in your templates, load the `bulma_tags` library and use the `|bulma` filters: 60 | 61 | ##### Example template 62 | 63 | ```django 64 | 65 | {% load bulma_tags %} 66 | 67 | {# Display a form #} 68 | 69 |
70 | {% csrf_token %} 71 | {{ form|bulma }} 72 |
73 | 74 |
75 | 76 |
77 | ``` 78 | 79 | ## Included templates 80 | 81 | **django-bulma** comes with: 82 | * a base template, 83 | * django core registration templates, 84 | 85 | ## Bugs and suggestions 86 | 87 | If you have found a bug or if you have a request for additional functionality, please use the issue tracker on GitHub. 88 | 89 | [https://github.com/timonweb/django-bulma/issues](https://github.com/timonweb/django-bulma/issues) 90 | -------------------------------------------------------------------------------- /assets/django-bulma-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/assets/django-bulma-logo.png -------------------------------------------------------------------------------- /assets/django-bulma-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Logo 5 | Created with Sketch. 6 | 7 | 8 | 24 | 25 | -------------------------------------------------------------------------------- /bulma/__init__.py: -------------------------------------------------------------------------------- 1 | from pkg_resources import get_distribution, DistributionNotFound 2 | try: 3 | __version__ = get_distribution('django-bulma').version 4 | except DistributionNotFound: 5 | # package is not installed 6 | pass 7 | -------------------------------------------------------------------------------- /bulma/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BulmaConfig(AppConfig): 5 | name = 'bulma' 6 | -------------------------------------------------------------------------------- /bulma/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/bulma/management/__init__.py -------------------------------------------------------------------------------- /bulma/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/bulma/management/commands/__init__.py -------------------------------------------------------------------------------- /bulma/management/commands/bulma.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | from django.conf import settings 4 | from django.core.management import CommandError 5 | from django.core.management.base import LabelCommand 6 | 7 | 8 | class Command(LabelCommand): 9 | 10 | help = 'Runs bulma commands' 11 | missing_args_message = """ 12 | Command argument is missing, please add one of the following: 13 | install - to install npm packages necessary to build bulma sass 14 | build - to compile bulma sass into production css 15 | start - to start watching sass changes for dev 16 | Usage example: 17 | python manage.py bulma start 18 | """ 19 | label = 'command' 20 | static_root_bulma_dir = None 21 | 22 | def __init__(self, *args, **kwargs): 23 | super(Command, self).__init__(*args, **kwargs) 24 | self.bulma_dir = None 25 | 26 | def add_arguments(self, parser): 27 | parser.add_argument('args', metavar=self.label, help='Delete poll instead of closing it', nargs=1) 28 | 29 | def handle_label(self, label, **options): 30 | self.validate(label) 31 | getattr(self, 'handle_' + label)(**options) 32 | 33 | def validate(self, label): 34 | 35 | if len(settings.STATICFILES_DIRS) == 0: 36 | raise CommandError( 37 | "STATICFILES_DIRS in your settings is empty. " 38 | "STATICFILES_DIRS should have at least one directory. " 39 | "Bulma static files will be put into first directory listed in STATICFILES_DIRS " 40 | "It's a good idea to set first item of STATICFILES_DIRS to os.path.join(BASE_DIR, \"static\")" 41 | ) 42 | 43 | self.bulma_dir = os.path.join(settings.STATICFILES_DIRS[0], 'bulma', 'sass') 44 | 45 | if not os.path.exists(os.path.join(self.bulma_dir, 'package.json')): 46 | raise CommandError( 47 | "It looks like you haven't copied bulma static files into your " 48 | "first STATICFILES_DIRS directory yet. " 49 | "Please run 'python manage.py copy_bulma_static_into_project' to copy bulma static files" 50 | "and then comeback.") 51 | 52 | if label not in ['install', 'build', 'start']: 53 | raise CommandError("Subcommand doesn't exist") 54 | 55 | def handle_install(self, **options): 56 | self.npm_run(['install']) 57 | 58 | def handle_build(self, **options): 59 | self.npm_run(['run', 'build']) 60 | 61 | def handle_start(self, **options): 62 | self.npm_run(['run', 'start']) 63 | 64 | def npm_run(self, commands): 65 | try: 66 | subprocess.run(['npm'] + commands, cwd=self.bulma_dir) 67 | except KeyboardInterrupt: 68 | pass -------------------------------------------------------------------------------- /bulma/management/commands/copy_bulma_static_into_project.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | from django.conf import settings 4 | from django.core.management import BaseCommand, CommandError 5 | 6 | 7 | class Command(BaseCommand): 8 | 9 | help = 'Copies bulma static files into project\'s main static dir' 10 | static_root_bulma_dir = None 11 | 12 | def __init__(self, *args, **kwargs): 13 | super(Command, self).__init__(*args, **kwargs) 14 | 15 | def handle(self, *args, **options): 16 | self.validate() 17 | self.copy_bulma_files() 18 | 19 | def validate(self): 20 | 21 | if len(settings.STATICFILES_DIRS) == 0: 22 | raise CommandError( 23 | "STATICFILES_DIRS in your settings is empty. " 24 | "STATICFILES_DIRS should have at least one directory. " 25 | "Bulma static files will be put into first directory listed in STATICFILES_DIRS " 26 | "It's a good idea to set first item of STATICFILES_DIRS to os.path.join(BASE_DIR, \"static\")" 27 | ) 28 | 29 | self.static_root_bulma_dir = os.path.join(settings.STATICFILES_DIRS[0], 'bulma') 30 | 31 | if os.path.exists(self.static_root_bulma_dir): 32 | result = input("'bulma' dir already exists in your first STATICFILES_DIRS directory, " 33 | "do you want to overwrite its contents and continue? y/N: ") 34 | if result.lower() != 'y': 35 | raise CommandError('Command aborted') 36 | shutil.rmtree(self.static_root_bulma_dir) 37 | 38 | def copy_bulma_files(self): 39 | """ 40 | Copies Bulma static files from package's static/bulma into project's 41 | STATIC_ROOT/bulma 42 | """ 43 | original_bulma_dir = os.path.join( 44 | os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 45 | 'static', 46 | 'bulma' 47 | ) 48 | shutil.copytree(original_bulma_dir, self.static_root_bulma_dir) -------------------------------------------------------------------------------- /bulma/static/bulma/sass/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /bulma/static/bulma/sass/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "django_bulma", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "django_bulma", 8 | "license": "MIT", 9 | "dependencies": { 10 | "bulma": "^1.0.0" 11 | }, 12 | "devDependencies": { 13 | "autoprefixer": "^10.4.19", 14 | "clean-css-cli": "^5.6.3", 15 | "postcss-cli": "^11.0.0", 16 | "rimraf": "^5.0.7", 17 | "sass": "^1.77.1" 18 | } 19 | }, 20 | "node_modules/@isaacs/cliui": { 21 | "version": "8.0.2", 22 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 23 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 24 | "dev": true, 25 | "dependencies": { 26 | "string-width": "^5.1.2", 27 | "string-width-cjs": "npm:string-width@^4.2.0", 28 | "strip-ansi": "^7.0.1", 29 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 30 | "wrap-ansi": "^8.1.0", 31 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 32 | }, 33 | "engines": { 34 | "node": ">=12" 35 | } 36 | }, 37 | "node_modules/@isaacs/cliui/node_modules/ansi-regex": { 38 | "version": "6.0.1", 39 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", 40 | "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", 41 | "dev": true, 42 | "engines": { 43 | "node": ">=12" 44 | }, 45 | "funding": { 46 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 47 | } 48 | }, 49 | "node_modules/@isaacs/cliui/node_modules/ansi-styles": { 50 | "version": "6.2.1", 51 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 52 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 53 | "dev": true, 54 | "engines": { 55 | "node": ">=12" 56 | }, 57 | "funding": { 58 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 59 | } 60 | }, 61 | "node_modules/@isaacs/cliui/node_modules/emoji-regex": { 62 | "version": "9.2.2", 63 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 64 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 65 | "dev": true 66 | }, 67 | "node_modules/@isaacs/cliui/node_modules/string-width": { 68 | "version": "5.1.2", 69 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 70 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 71 | "dev": true, 72 | "dependencies": { 73 | "eastasianwidth": "^0.2.0", 74 | "emoji-regex": "^9.2.2", 75 | "strip-ansi": "^7.0.1" 76 | }, 77 | "engines": { 78 | "node": ">=12" 79 | }, 80 | "funding": { 81 | "url": "https://github.com/sponsors/sindresorhus" 82 | } 83 | }, 84 | "node_modules/@isaacs/cliui/node_modules/strip-ansi": { 85 | "version": "7.1.0", 86 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 87 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 88 | "dev": true, 89 | "dependencies": { 90 | "ansi-regex": "^6.0.1" 91 | }, 92 | "engines": { 93 | "node": ">=12" 94 | }, 95 | "funding": { 96 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 97 | } 98 | }, 99 | "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { 100 | "version": "8.1.0", 101 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 102 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 103 | "dev": true, 104 | "dependencies": { 105 | "ansi-styles": "^6.1.0", 106 | "string-width": "^5.0.1", 107 | "strip-ansi": "^7.0.1" 108 | }, 109 | "engines": { 110 | "node": ">=12" 111 | }, 112 | "funding": { 113 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 114 | } 115 | }, 116 | "node_modules/@nodelib/fs.scandir": { 117 | "version": "2.1.5", 118 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 119 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 120 | "dev": true, 121 | "dependencies": { 122 | "@nodelib/fs.stat": "2.0.5", 123 | "run-parallel": "^1.1.9" 124 | }, 125 | "engines": { 126 | "node": ">= 8" 127 | } 128 | }, 129 | "node_modules/@nodelib/fs.stat": { 130 | "version": "2.0.5", 131 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 132 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 133 | "dev": true, 134 | "engines": { 135 | "node": ">= 8" 136 | } 137 | }, 138 | "node_modules/@nodelib/fs.walk": { 139 | "version": "1.2.8", 140 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 141 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 142 | "dev": true, 143 | "dependencies": { 144 | "@nodelib/fs.scandir": "2.1.5", 145 | "fastq": "^1.6.0" 146 | }, 147 | "engines": { 148 | "node": ">= 8" 149 | } 150 | }, 151 | "node_modules/@pkgjs/parseargs": { 152 | "version": "0.11.0", 153 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 154 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 155 | "dev": true, 156 | "optional": true, 157 | "engines": { 158 | "node": ">=14" 159 | } 160 | }, 161 | "node_modules/@sindresorhus/merge-streams": { 162 | "version": "2.3.0", 163 | "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", 164 | "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", 165 | "dev": true, 166 | "engines": { 167 | "node": ">=18" 168 | }, 169 | "funding": { 170 | "url": "https://github.com/sponsors/sindresorhus" 171 | } 172 | }, 173 | "node_modules/ansi-regex": { 174 | "version": "5.0.1", 175 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 176 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 177 | "dev": true, 178 | "engines": { 179 | "node": ">=8" 180 | } 181 | }, 182 | "node_modules/ansi-styles": { 183 | "version": "4.3.0", 184 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 185 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 186 | "dev": true, 187 | "dependencies": { 188 | "color-convert": "^2.0.1" 189 | }, 190 | "engines": { 191 | "node": ">=8" 192 | }, 193 | "funding": { 194 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 195 | } 196 | }, 197 | "node_modules/anymatch": { 198 | "version": "3.1.3", 199 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 200 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 201 | "dependencies": { 202 | "normalize-path": "^3.0.0", 203 | "picomatch": "^2.0.4" 204 | }, 205 | "engines": { 206 | "node": ">= 8" 207 | } 208 | }, 209 | "node_modules/autoprefixer": { 210 | "version": "10.4.19", 211 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", 212 | "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", 213 | "dev": true, 214 | "funding": [ 215 | { 216 | "type": "opencollective", 217 | "url": "https://opencollective.com/postcss/" 218 | }, 219 | { 220 | "type": "tidelift", 221 | "url": "https://tidelift.com/funding/github/npm/autoprefixer" 222 | }, 223 | { 224 | "type": "github", 225 | "url": "https://github.com/sponsors/ai" 226 | } 227 | ], 228 | "dependencies": { 229 | "browserslist": "^4.23.0", 230 | "caniuse-lite": "^1.0.30001599", 231 | "fraction.js": "^4.3.7", 232 | "normalize-range": "^0.1.2", 233 | "picocolors": "^1.0.0", 234 | "postcss-value-parser": "^4.2.0" 235 | }, 236 | "bin": { 237 | "autoprefixer": "bin/autoprefixer" 238 | }, 239 | "engines": { 240 | "node": "^10 || ^12 || >=14" 241 | }, 242 | "peerDependencies": { 243 | "postcss": "^8.1.0" 244 | } 245 | }, 246 | "node_modules/balanced-match": { 247 | "version": "1.0.2", 248 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 249 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 250 | "dev": true 251 | }, 252 | "node_modules/binary-extensions": { 253 | "version": "2.3.0", 254 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 255 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 256 | "engines": { 257 | "node": ">=8" 258 | }, 259 | "funding": { 260 | "url": "https://github.com/sponsors/sindresorhus" 261 | } 262 | }, 263 | "node_modules/brace-expansion": { 264 | "version": "1.1.11", 265 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 266 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 267 | "dev": true, 268 | "dependencies": { 269 | "balanced-match": "^1.0.0", 270 | "concat-map": "0.0.1" 271 | } 272 | }, 273 | "node_modules/braces": { 274 | "version": "3.0.2", 275 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 276 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 277 | "dependencies": { 278 | "fill-range": "^7.0.1" 279 | }, 280 | "engines": { 281 | "node": ">=8" 282 | } 283 | }, 284 | "node_modules/browserslist": { 285 | "version": "4.23.0", 286 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", 287 | "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", 288 | "dev": true, 289 | "funding": [ 290 | { 291 | "type": "opencollective", 292 | "url": "https://opencollective.com/browserslist" 293 | }, 294 | { 295 | "type": "tidelift", 296 | "url": "https://tidelift.com/funding/github/npm/browserslist" 297 | }, 298 | { 299 | "type": "github", 300 | "url": "https://github.com/sponsors/ai" 301 | } 302 | ], 303 | "dependencies": { 304 | "caniuse-lite": "^1.0.30001587", 305 | "electron-to-chromium": "^1.4.668", 306 | "node-releases": "^2.0.14", 307 | "update-browserslist-db": "^1.0.13" 308 | }, 309 | "bin": { 310 | "browserslist": "cli.js" 311 | }, 312 | "engines": { 313 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 314 | } 315 | }, 316 | "node_modules/bulma": { 317 | "version": "1.0.0", 318 | "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.0.tgz", 319 | "integrity": "sha512-7n49v/gdHXaHcU9fVobqGXO2OguiCoMh6CLbeX7jq00XrZ5vOSE4LNS0S/0Q6rlBbckY6kk6W7LwqxS0nu4bug==", 320 | "dependencies": { 321 | "sass": "^1.71.1" 322 | } 323 | }, 324 | "node_modules/caniuse-lite": { 325 | "version": "1.0.30001618", 326 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001618.tgz", 327 | "integrity": "sha512-p407+D1tIkDvsEAPS22lJxLQQaG8OTBEqo0KhzfABGk0TU4juBNDSfH0hyAp/HRyx+M8L17z/ltyhxh27FTfQg==", 328 | "dev": true, 329 | "funding": [ 330 | { 331 | "type": "opencollective", 332 | "url": "https://opencollective.com/browserslist" 333 | }, 334 | { 335 | "type": "tidelift", 336 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 337 | }, 338 | { 339 | "type": "github", 340 | "url": "https://github.com/sponsors/ai" 341 | } 342 | ] 343 | }, 344 | "node_modules/chokidar": { 345 | "version": "3.6.0", 346 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 347 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 348 | "dependencies": { 349 | "anymatch": "~3.1.2", 350 | "braces": "~3.0.2", 351 | "glob-parent": "~5.1.2", 352 | "is-binary-path": "~2.1.0", 353 | "is-glob": "~4.0.1", 354 | "normalize-path": "~3.0.0", 355 | "readdirp": "~3.6.0" 356 | }, 357 | "engines": { 358 | "node": ">= 8.10.0" 359 | }, 360 | "funding": { 361 | "url": "https://paulmillr.com/funding/" 362 | }, 363 | "optionalDependencies": { 364 | "fsevents": "~2.3.2" 365 | } 366 | }, 367 | "node_modules/clean-css": { 368 | "version": "5.3.3", 369 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", 370 | "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", 371 | "dev": true, 372 | "dependencies": { 373 | "source-map": "~0.6.0" 374 | }, 375 | "engines": { 376 | "node": ">= 10.0" 377 | } 378 | }, 379 | "node_modules/clean-css-cli": { 380 | "version": "5.6.3", 381 | "resolved": "https://registry.npmjs.org/clean-css-cli/-/clean-css-cli-5.6.3.tgz", 382 | "integrity": "sha512-MUAta8pEqA/d2DKQwtZU5nm0Og8TCyAglOx3GlWwjhGdKBwY4kVF6E5M6LU/jmmuswv+HbYqG/dKKkq5p1dD0A==", 383 | "dev": true, 384 | "dependencies": { 385 | "chokidar": "^3.5.2", 386 | "clean-css": "^5.3.3", 387 | "commander": "7.x", 388 | "glob": "^7.1.6" 389 | }, 390 | "bin": { 391 | "cleancss": "bin/cleancss" 392 | }, 393 | "engines": { 394 | "node": ">= 10.12.0" 395 | } 396 | }, 397 | "node_modules/cliui": { 398 | "version": "8.0.1", 399 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 400 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 401 | "dev": true, 402 | "dependencies": { 403 | "string-width": "^4.2.0", 404 | "strip-ansi": "^6.0.1", 405 | "wrap-ansi": "^7.0.0" 406 | }, 407 | "engines": { 408 | "node": ">=12" 409 | } 410 | }, 411 | "node_modules/color-convert": { 412 | "version": "2.0.1", 413 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 414 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 415 | "dev": true, 416 | "dependencies": { 417 | "color-name": "~1.1.4" 418 | }, 419 | "engines": { 420 | "node": ">=7.0.0" 421 | } 422 | }, 423 | "node_modules/color-name": { 424 | "version": "1.1.4", 425 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 426 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 427 | "dev": true 428 | }, 429 | "node_modules/commander": { 430 | "version": "7.2.0", 431 | "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", 432 | "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", 433 | "dev": true, 434 | "engines": { 435 | "node": ">= 10" 436 | } 437 | }, 438 | "node_modules/concat-map": { 439 | "version": "0.0.1", 440 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 441 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 442 | "dev": true 443 | }, 444 | "node_modules/cross-spawn": { 445 | "version": "7.0.3", 446 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 447 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 448 | "dev": true, 449 | "dependencies": { 450 | "path-key": "^3.1.0", 451 | "shebang-command": "^2.0.0", 452 | "which": "^2.0.1" 453 | }, 454 | "engines": { 455 | "node": ">= 8" 456 | } 457 | }, 458 | "node_modules/dependency-graph": { 459 | "version": "0.11.0", 460 | "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", 461 | "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", 462 | "dev": true, 463 | "engines": { 464 | "node": ">= 0.6.0" 465 | } 466 | }, 467 | "node_modules/eastasianwidth": { 468 | "version": "0.2.0", 469 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 470 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 471 | "dev": true 472 | }, 473 | "node_modules/electron-to-chromium": { 474 | "version": "1.4.769", 475 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.769.tgz", 476 | "integrity": "sha512-bZu7p623NEA2rHTc9K1vykl57ektSPQYFFqQir8BOYf6EKOB+yIsbFB9Kpm7Cgt6tsLr9sRkqfqSZUw7LP1XxQ==", 477 | "dev": true 478 | }, 479 | "node_modules/emoji-regex": { 480 | "version": "8.0.0", 481 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 482 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 483 | "dev": true 484 | }, 485 | "node_modules/escalade": { 486 | "version": "3.1.2", 487 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", 488 | "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", 489 | "dev": true, 490 | "engines": { 491 | "node": ">=6" 492 | } 493 | }, 494 | "node_modules/fast-glob": { 495 | "version": "3.3.2", 496 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", 497 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", 498 | "dev": true, 499 | "dependencies": { 500 | "@nodelib/fs.stat": "^2.0.2", 501 | "@nodelib/fs.walk": "^1.2.3", 502 | "glob-parent": "^5.1.2", 503 | "merge2": "^1.3.0", 504 | "micromatch": "^4.0.4" 505 | }, 506 | "engines": { 507 | "node": ">=8.6.0" 508 | } 509 | }, 510 | "node_modules/fastq": { 511 | "version": "1.17.1", 512 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", 513 | "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", 514 | "dev": true, 515 | "dependencies": { 516 | "reusify": "^1.0.4" 517 | } 518 | }, 519 | "node_modules/fill-range": { 520 | "version": "7.0.1", 521 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 522 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 523 | "dependencies": { 524 | "to-regex-range": "^5.0.1" 525 | }, 526 | "engines": { 527 | "node": ">=8" 528 | } 529 | }, 530 | "node_modules/foreground-child": { 531 | "version": "3.1.1", 532 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", 533 | "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", 534 | "dev": true, 535 | "dependencies": { 536 | "cross-spawn": "^7.0.0", 537 | "signal-exit": "^4.0.1" 538 | }, 539 | "engines": { 540 | "node": ">=14" 541 | }, 542 | "funding": { 543 | "url": "https://github.com/sponsors/isaacs" 544 | } 545 | }, 546 | "node_modules/fraction.js": { 547 | "version": "4.3.7", 548 | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", 549 | "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", 550 | "dev": true, 551 | "engines": { 552 | "node": "*" 553 | }, 554 | "funding": { 555 | "type": "patreon", 556 | "url": "https://github.com/sponsors/rawify" 557 | } 558 | }, 559 | "node_modules/fs-extra": { 560 | "version": "11.2.0", 561 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", 562 | "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", 563 | "dev": true, 564 | "dependencies": { 565 | "graceful-fs": "^4.2.0", 566 | "jsonfile": "^6.0.1", 567 | "universalify": "^2.0.0" 568 | }, 569 | "engines": { 570 | "node": ">=14.14" 571 | } 572 | }, 573 | "node_modules/fs.realpath": { 574 | "version": "1.0.0", 575 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 576 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 577 | "dev": true 578 | }, 579 | "node_modules/fsevents": { 580 | "version": "2.3.3", 581 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 582 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 583 | "hasInstallScript": true, 584 | "optional": true, 585 | "os": [ 586 | "darwin" 587 | ], 588 | "engines": { 589 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 590 | } 591 | }, 592 | "node_modules/get-caller-file": { 593 | "version": "2.0.5", 594 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 595 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 596 | "dev": true, 597 | "engines": { 598 | "node": "6.* || 8.* || >= 10.*" 599 | } 600 | }, 601 | "node_modules/get-stdin": { 602 | "version": "9.0.0", 603 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", 604 | "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", 605 | "dev": true, 606 | "engines": { 607 | "node": ">=12" 608 | }, 609 | "funding": { 610 | "url": "https://github.com/sponsors/sindresorhus" 611 | } 612 | }, 613 | "node_modules/glob": { 614 | "version": "7.2.3", 615 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 616 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 617 | "dev": true, 618 | "dependencies": { 619 | "fs.realpath": "^1.0.0", 620 | "inflight": "^1.0.4", 621 | "inherits": "2", 622 | "minimatch": "^3.1.1", 623 | "once": "^1.3.0", 624 | "path-is-absolute": "^1.0.0" 625 | }, 626 | "engines": { 627 | "node": "*" 628 | }, 629 | "funding": { 630 | "url": "https://github.com/sponsors/isaacs" 631 | } 632 | }, 633 | "node_modules/glob-parent": { 634 | "version": "5.1.2", 635 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 636 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 637 | "dependencies": { 638 | "is-glob": "^4.0.1" 639 | }, 640 | "engines": { 641 | "node": ">= 6" 642 | } 643 | }, 644 | "node_modules/globby": { 645 | "version": "14.0.1", 646 | "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", 647 | "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", 648 | "dev": true, 649 | "dependencies": { 650 | "@sindresorhus/merge-streams": "^2.1.0", 651 | "fast-glob": "^3.3.2", 652 | "ignore": "^5.2.4", 653 | "path-type": "^5.0.0", 654 | "slash": "^5.1.0", 655 | "unicorn-magic": "^0.1.0" 656 | }, 657 | "engines": { 658 | "node": ">=18" 659 | }, 660 | "funding": { 661 | "url": "https://github.com/sponsors/sindresorhus" 662 | } 663 | }, 664 | "node_modules/graceful-fs": { 665 | "version": "4.2.11", 666 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 667 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 668 | "dev": true 669 | }, 670 | "node_modules/ignore": { 671 | "version": "5.3.1", 672 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", 673 | "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", 674 | "dev": true, 675 | "engines": { 676 | "node": ">= 4" 677 | } 678 | }, 679 | "node_modules/immutable": { 680 | "version": "4.3.6", 681 | "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", 682 | "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" 683 | }, 684 | "node_modules/inflight": { 685 | "version": "1.0.6", 686 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 687 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 688 | "dev": true, 689 | "dependencies": { 690 | "once": "^1.3.0", 691 | "wrappy": "1" 692 | } 693 | }, 694 | "node_modules/inherits": { 695 | "version": "2.0.4", 696 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 697 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 698 | "dev": true 699 | }, 700 | "node_modules/is-binary-path": { 701 | "version": "2.1.0", 702 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 703 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 704 | "dependencies": { 705 | "binary-extensions": "^2.0.0" 706 | }, 707 | "engines": { 708 | "node": ">=8" 709 | } 710 | }, 711 | "node_modules/is-extglob": { 712 | "version": "2.1.1", 713 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 714 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 715 | "engines": { 716 | "node": ">=0.10.0" 717 | } 718 | }, 719 | "node_modules/is-fullwidth-code-point": { 720 | "version": "3.0.0", 721 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 722 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 723 | "dev": true, 724 | "engines": { 725 | "node": ">=8" 726 | } 727 | }, 728 | "node_modules/is-glob": { 729 | "version": "4.0.3", 730 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 731 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 732 | "dependencies": { 733 | "is-extglob": "^2.1.1" 734 | }, 735 | "engines": { 736 | "node": ">=0.10.0" 737 | } 738 | }, 739 | "node_modules/is-number": { 740 | "version": "7.0.0", 741 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 742 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 743 | "engines": { 744 | "node": ">=0.12.0" 745 | } 746 | }, 747 | "node_modules/isexe": { 748 | "version": "2.0.0", 749 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 750 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 751 | "dev": true 752 | }, 753 | "node_modules/jackspeak": { 754 | "version": "2.3.6", 755 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", 756 | "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", 757 | "dev": true, 758 | "dependencies": { 759 | "@isaacs/cliui": "^8.0.2" 760 | }, 761 | "engines": { 762 | "node": ">=14" 763 | }, 764 | "funding": { 765 | "url": "https://github.com/sponsors/isaacs" 766 | }, 767 | "optionalDependencies": { 768 | "@pkgjs/parseargs": "^0.11.0" 769 | } 770 | }, 771 | "node_modules/jsonfile": { 772 | "version": "6.1.0", 773 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 774 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 775 | "dev": true, 776 | "dependencies": { 777 | "universalify": "^2.0.0" 778 | }, 779 | "optionalDependencies": { 780 | "graceful-fs": "^4.1.6" 781 | } 782 | }, 783 | "node_modules/lilconfig": { 784 | "version": "3.1.1", 785 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", 786 | "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", 787 | "dev": true, 788 | "engines": { 789 | "node": ">=14" 790 | }, 791 | "funding": { 792 | "url": "https://github.com/sponsors/antonk52" 793 | } 794 | }, 795 | "node_modules/lru-cache": { 796 | "version": "10.2.2", 797 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", 798 | "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", 799 | "dev": true, 800 | "engines": { 801 | "node": "14 || >=16.14" 802 | } 803 | }, 804 | "node_modules/merge2": { 805 | "version": "1.4.1", 806 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 807 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 808 | "dev": true, 809 | "engines": { 810 | "node": ">= 8" 811 | } 812 | }, 813 | "node_modules/micromatch": { 814 | "version": "4.0.5", 815 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 816 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 817 | "dev": true, 818 | "dependencies": { 819 | "braces": "^3.0.2", 820 | "picomatch": "^2.3.1" 821 | }, 822 | "engines": { 823 | "node": ">=8.6" 824 | } 825 | }, 826 | "node_modules/minimatch": { 827 | "version": "3.1.2", 828 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 829 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 830 | "dev": true, 831 | "dependencies": { 832 | "brace-expansion": "^1.1.7" 833 | }, 834 | "engines": { 835 | "node": "*" 836 | } 837 | }, 838 | "node_modules/minipass": { 839 | "version": "7.1.1", 840 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", 841 | "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", 842 | "dev": true, 843 | "engines": { 844 | "node": ">=16 || 14 >=14.17" 845 | } 846 | }, 847 | "node_modules/nanoid": { 848 | "version": "3.3.7", 849 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 850 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 851 | "dev": true, 852 | "funding": [ 853 | { 854 | "type": "github", 855 | "url": "https://github.com/sponsors/ai" 856 | } 857 | ], 858 | "peer": true, 859 | "bin": { 860 | "nanoid": "bin/nanoid.cjs" 861 | }, 862 | "engines": { 863 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 864 | } 865 | }, 866 | "node_modules/node-releases": { 867 | "version": "2.0.14", 868 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", 869 | "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", 870 | "dev": true 871 | }, 872 | "node_modules/normalize-path": { 873 | "version": "3.0.0", 874 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 875 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 876 | "engines": { 877 | "node": ">=0.10.0" 878 | } 879 | }, 880 | "node_modules/normalize-range": { 881 | "version": "0.1.2", 882 | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", 883 | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", 884 | "dev": true, 885 | "engines": { 886 | "node": ">=0.10.0" 887 | } 888 | }, 889 | "node_modules/once": { 890 | "version": "1.4.0", 891 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 892 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 893 | "dev": true, 894 | "dependencies": { 895 | "wrappy": "1" 896 | } 897 | }, 898 | "node_modules/path-is-absolute": { 899 | "version": "1.0.1", 900 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 901 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 902 | "dev": true, 903 | "engines": { 904 | "node": ">=0.10.0" 905 | } 906 | }, 907 | "node_modules/path-key": { 908 | "version": "3.1.1", 909 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 910 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 911 | "dev": true, 912 | "engines": { 913 | "node": ">=8" 914 | } 915 | }, 916 | "node_modules/path-scurry": { 917 | "version": "1.11.1", 918 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 919 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 920 | "dev": true, 921 | "dependencies": { 922 | "lru-cache": "^10.2.0", 923 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 924 | }, 925 | "engines": { 926 | "node": ">=16 || 14 >=14.18" 927 | }, 928 | "funding": { 929 | "url": "https://github.com/sponsors/isaacs" 930 | } 931 | }, 932 | "node_modules/path-type": { 933 | "version": "5.0.0", 934 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", 935 | "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", 936 | "dev": true, 937 | "engines": { 938 | "node": ">=12" 939 | }, 940 | "funding": { 941 | "url": "https://github.com/sponsors/sindresorhus" 942 | } 943 | }, 944 | "node_modules/picocolors": { 945 | "version": "1.0.1", 946 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", 947 | "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", 948 | "dev": true 949 | }, 950 | "node_modules/picomatch": { 951 | "version": "2.3.1", 952 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 953 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 954 | "engines": { 955 | "node": ">=8.6" 956 | }, 957 | "funding": { 958 | "url": "https://github.com/sponsors/jonschlinkert" 959 | } 960 | }, 961 | "node_modules/pify": { 962 | "version": "2.3.0", 963 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 964 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 965 | "dev": true, 966 | "engines": { 967 | "node": ">=0.10.0" 968 | } 969 | }, 970 | "node_modules/postcss": { 971 | "version": "8.4.38", 972 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", 973 | "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", 974 | "dev": true, 975 | "funding": [ 976 | { 977 | "type": "opencollective", 978 | "url": "https://opencollective.com/postcss/" 979 | }, 980 | { 981 | "type": "tidelift", 982 | "url": "https://tidelift.com/funding/github/npm/postcss" 983 | }, 984 | { 985 | "type": "github", 986 | "url": "https://github.com/sponsors/ai" 987 | } 988 | ], 989 | "peer": true, 990 | "dependencies": { 991 | "nanoid": "^3.3.7", 992 | "picocolors": "^1.0.0", 993 | "source-map-js": "^1.2.0" 994 | }, 995 | "engines": { 996 | "node": "^10 || ^12 || >=14" 997 | } 998 | }, 999 | "node_modules/postcss-cli": { 1000 | "version": "11.0.0", 1001 | "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", 1002 | "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", 1003 | "dev": true, 1004 | "dependencies": { 1005 | "chokidar": "^3.3.0", 1006 | "dependency-graph": "^0.11.0", 1007 | "fs-extra": "^11.0.0", 1008 | "get-stdin": "^9.0.0", 1009 | "globby": "^14.0.0", 1010 | "picocolors": "^1.0.0", 1011 | "postcss-load-config": "^5.0.0", 1012 | "postcss-reporter": "^7.0.0", 1013 | "pretty-hrtime": "^1.0.3", 1014 | "read-cache": "^1.0.0", 1015 | "slash": "^5.0.0", 1016 | "yargs": "^17.0.0" 1017 | }, 1018 | "bin": { 1019 | "postcss": "index.js" 1020 | }, 1021 | "engines": { 1022 | "node": ">=18" 1023 | }, 1024 | "peerDependencies": { 1025 | "postcss": "^8.0.0" 1026 | } 1027 | }, 1028 | "node_modules/postcss-load-config": { 1029 | "version": "5.1.0", 1030 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", 1031 | "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", 1032 | "dev": true, 1033 | "funding": [ 1034 | { 1035 | "type": "opencollective", 1036 | "url": "https://opencollective.com/postcss/" 1037 | }, 1038 | { 1039 | "type": "github", 1040 | "url": "https://github.com/sponsors/ai" 1041 | } 1042 | ], 1043 | "dependencies": { 1044 | "lilconfig": "^3.1.1", 1045 | "yaml": "^2.4.2" 1046 | }, 1047 | "engines": { 1048 | "node": ">= 18" 1049 | }, 1050 | "peerDependencies": { 1051 | "jiti": ">=1.21.0", 1052 | "postcss": ">=8.0.9", 1053 | "tsx": "^4.8.1" 1054 | }, 1055 | "peerDependenciesMeta": { 1056 | "jiti": { 1057 | "optional": true 1058 | }, 1059 | "postcss": { 1060 | "optional": true 1061 | }, 1062 | "tsx": { 1063 | "optional": true 1064 | } 1065 | } 1066 | }, 1067 | "node_modules/postcss-reporter": { 1068 | "version": "7.1.0", 1069 | "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", 1070 | "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", 1071 | "dev": true, 1072 | "funding": [ 1073 | { 1074 | "type": "opencollective", 1075 | "url": "https://opencollective.com/postcss/" 1076 | }, 1077 | { 1078 | "type": "github", 1079 | "url": "https://github.com/sponsors/ai" 1080 | } 1081 | ], 1082 | "dependencies": { 1083 | "picocolors": "^1.0.0", 1084 | "thenby": "^1.3.4" 1085 | }, 1086 | "engines": { 1087 | "node": ">=10" 1088 | }, 1089 | "peerDependencies": { 1090 | "postcss": "^8.1.0" 1091 | } 1092 | }, 1093 | "node_modules/postcss-value-parser": { 1094 | "version": "4.2.0", 1095 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 1096 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 1097 | "dev": true 1098 | }, 1099 | "node_modules/pretty-hrtime": { 1100 | "version": "1.0.3", 1101 | "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", 1102 | "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", 1103 | "dev": true, 1104 | "engines": { 1105 | "node": ">= 0.8" 1106 | } 1107 | }, 1108 | "node_modules/queue-microtask": { 1109 | "version": "1.2.3", 1110 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1111 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1112 | "dev": true, 1113 | "funding": [ 1114 | { 1115 | "type": "github", 1116 | "url": "https://github.com/sponsors/feross" 1117 | }, 1118 | { 1119 | "type": "patreon", 1120 | "url": "https://www.patreon.com/feross" 1121 | }, 1122 | { 1123 | "type": "consulting", 1124 | "url": "https://feross.org/support" 1125 | } 1126 | ] 1127 | }, 1128 | "node_modules/read-cache": { 1129 | "version": "1.0.0", 1130 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 1131 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 1132 | "dev": true, 1133 | "dependencies": { 1134 | "pify": "^2.3.0" 1135 | } 1136 | }, 1137 | "node_modules/readdirp": { 1138 | "version": "3.6.0", 1139 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1140 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1141 | "dependencies": { 1142 | "picomatch": "^2.2.1" 1143 | }, 1144 | "engines": { 1145 | "node": ">=8.10.0" 1146 | } 1147 | }, 1148 | "node_modules/require-directory": { 1149 | "version": "2.1.1", 1150 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1151 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1152 | "dev": true, 1153 | "engines": { 1154 | "node": ">=0.10.0" 1155 | } 1156 | }, 1157 | "node_modules/reusify": { 1158 | "version": "1.0.4", 1159 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1160 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1161 | "dev": true, 1162 | "engines": { 1163 | "iojs": ">=1.0.0", 1164 | "node": ">=0.10.0" 1165 | } 1166 | }, 1167 | "node_modules/rimraf": { 1168 | "version": "5.0.7", 1169 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", 1170 | "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", 1171 | "dev": true, 1172 | "dependencies": { 1173 | "glob": "^10.3.7" 1174 | }, 1175 | "bin": { 1176 | "rimraf": "dist/esm/bin.mjs" 1177 | }, 1178 | "engines": { 1179 | "node": ">=14.18" 1180 | }, 1181 | "funding": { 1182 | "url": "https://github.com/sponsors/isaacs" 1183 | } 1184 | }, 1185 | "node_modules/rimraf/node_modules/brace-expansion": { 1186 | "version": "2.0.1", 1187 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1188 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1189 | "dev": true, 1190 | "dependencies": { 1191 | "balanced-match": "^1.0.0" 1192 | } 1193 | }, 1194 | "node_modules/rimraf/node_modules/glob": { 1195 | "version": "10.3.15", 1196 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", 1197 | "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", 1198 | "dev": true, 1199 | "dependencies": { 1200 | "foreground-child": "^3.1.0", 1201 | "jackspeak": "^2.3.6", 1202 | "minimatch": "^9.0.1", 1203 | "minipass": "^7.0.4", 1204 | "path-scurry": "^1.11.0" 1205 | }, 1206 | "bin": { 1207 | "glob": "dist/esm/bin.mjs" 1208 | }, 1209 | "engines": { 1210 | "node": ">=16 || 14 >=14.18" 1211 | }, 1212 | "funding": { 1213 | "url": "https://github.com/sponsors/isaacs" 1214 | } 1215 | }, 1216 | "node_modules/rimraf/node_modules/minimatch": { 1217 | "version": "9.0.4", 1218 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", 1219 | "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", 1220 | "dev": true, 1221 | "dependencies": { 1222 | "brace-expansion": "^2.0.1" 1223 | }, 1224 | "engines": { 1225 | "node": ">=16 || 14 >=14.17" 1226 | }, 1227 | "funding": { 1228 | "url": "https://github.com/sponsors/isaacs" 1229 | } 1230 | }, 1231 | "node_modules/run-parallel": { 1232 | "version": "1.2.0", 1233 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1234 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1235 | "dev": true, 1236 | "funding": [ 1237 | { 1238 | "type": "github", 1239 | "url": "https://github.com/sponsors/feross" 1240 | }, 1241 | { 1242 | "type": "patreon", 1243 | "url": "https://www.patreon.com/feross" 1244 | }, 1245 | { 1246 | "type": "consulting", 1247 | "url": "https://feross.org/support" 1248 | } 1249 | ], 1250 | "dependencies": { 1251 | "queue-microtask": "^1.2.2" 1252 | } 1253 | }, 1254 | "node_modules/sass": { 1255 | "version": "1.77.1", 1256 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.1.tgz", 1257 | "integrity": "sha512-OMEyfirt9XEfyvocduUIOlUSkWOXS/LAt6oblR/ISXCTukyavjex+zQNm51pPCOiFKY1QpWvEH1EeCkgyV3I6w==", 1258 | "dependencies": { 1259 | "chokidar": ">=3.0.0 <4.0.0", 1260 | "immutable": "^4.0.0", 1261 | "source-map-js": ">=0.6.2 <2.0.0" 1262 | }, 1263 | "bin": { 1264 | "sass": "sass.js" 1265 | }, 1266 | "engines": { 1267 | "node": ">=14.0.0" 1268 | } 1269 | }, 1270 | "node_modules/shebang-command": { 1271 | "version": "2.0.0", 1272 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1273 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1274 | "dev": true, 1275 | "dependencies": { 1276 | "shebang-regex": "^3.0.0" 1277 | }, 1278 | "engines": { 1279 | "node": ">=8" 1280 | } 1281 | }, 1282 | "node_modules/shebang-regex": { 1283 | "version": "3.0.0", 1284 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1285 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1286 | "dev": true, 1287 | "engines": { 1288 | "node": ">=8" 1289 | } 1290 | }, 1291 | "node_modules/signal-exit": { 1292 | "version": "4.1.0", 1293 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 1294 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 1295 | "dev": true, 1296 | "engines": { 1297 | "node": ">=14" 1298 | }, 1299 | "funding": { 1300 | "url": "https://github.com/sponsors/isaacs" 1301 | } 1302 | }, 1303 | "node_modules/slash": { 1304 | "version": "5.1.0", 1305 | "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", 1306 | "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", 1307 | "dev": true, 1308 | "engines": { 1309 | "node": ">=14.16" 1310 | }, 1311 | "funding": { 1312 | "url": "https://github.com/sponsors/sindresorhus" 1313 | } 1314 | }, 1315 | "node_modules/source-map": { 1316 | "version": "0.6.1", 1317 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1318 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1319 | "dev": true, 1320 | "engines": { 1321 | "node": ">=0.10.0" 1322 | } 1323 | }, 1324 | "node_modules/source-map-js": { 1325 | "version": "1.2.0", 1326 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", 1327 | "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", 1328 | "engines": { 1329 | "node": ">=0.10.0" 1330 | } 1331 | }, 1332 | "node_modules/string-width": { 1333 | "version": "4.2.3", 1334 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1335 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1336 | "dev": true, 1337 | "dependencies": { 1338 | "emoji-regex": "^8.0.0", 1339 | "is-fullwidth-code-point": "^3.0.0", 1340 | "strip-ansi": "^6.0.1" 1341 | }, 1342 | "engines": { 1343 | "node": ">=8" 1344 | } 1345 | }, 1346 | "node_modules/string-width-cjs": { 1347 | "name": "string-width", 1348 | "version": "4.2.3", 1349 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1350 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1351 | "dev": true, 1352 | "dependencies": { 1353 | "emoji-regex": "^8.0.0", 1354 | "is-fullwidth-code-point": "^3.0.0", 1355 | "strip-ansi": "^6.0.1" 1356 | }, 1357 | "engines": { 1358 | "node": ">=8" 1359 | } 1360 | }, 1361 | "node_modules/strip-ansi": { 1362 | "version": "6.0.1", 1363 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1364 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1365 | "dev": true, 1366 | "dependencies": { 1367 | "ansi-regex": "^5.0.1" 1368 | }, 1369 | "engines": { 1370 | "node": ">=8" 1371 | } 1372 | }, 1373 | "node_modules/strip-ansi-cjs": { 1374 | "name": "strip-ansi", 1375 | "version": "6.0.1", 1376 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1377 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1378 | "dev": true, 1379 | "dependencies": { 1380 | "ansi-regex": "^5.0.1" 1381 | }, 1382 | "engines": { 1383 | "node": ">=8" 1384 | } 1385 | }, 1386 | "node_modules/thenby": { 1387 | "version": "1.3.4", 1388 | "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", 1389 | "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", 1390 | "dev": true 1391 | }, 1392 | "node_modules/to-regex-range": { 1393 | "version": "5.0.1", 1394 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1395 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1396 | "dependencies": { 1397 | "is-number": "^7.0.0" 1398 | }, 1399 | "engines": { 1400 | "node": ">=8.0" 1401 | } 1402 | }, 1403 | "node_modules/unicorn-magic": { 1404 | "version": "0.1.0", 1405 | "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", 1406 | "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", 1407 | "dev": true, 1408 | "engines": { 1409 | "node": ">=18" 1410 | }, 1411 | "funding": { 1412 | "url": "https://github.com/sponsors/sindresorhus" 1413 | } 1414 | }, 1415 | "node_modules/universalify": { 1416 | "version": "2.0.1", 1417 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 1418 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 1419 | "dev": true, 1420 | "engines": { 1421 | "node": ">= 10.0.0" 1422 | } 1423 | }, 1424 | "node_modules/update-browserslist-db": { 1425 | "version": "1.0.16", 1426 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", 1427 | "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", 1428 | "dev": true, 1429 | "funding": [ 1430 | { 1431 | "type": "opencollective", 1432 | "url": "https://opencollective.com/browserslist" 1433 | }, 1434 | { 1435 | "type": "tidelift", 1436 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1437 | }, 1438 | { 1439 | "type": "github", 1440 | "url": "https://github.com/sponsors/ai" 1441 | } 1442 | ], 1443 | "dependencies": { 1444 | "escalade": "^3.1.2", 1445 | "picocolors": "^1.0.1" 1446 | }, 1447 | "bin": { 1448 | "update-browserslist-db": "cli.js" 1449 | }, 1450 | "peerDependencies": { 1451 | "browserslist": ">= 4.21.0" 1452 | } 1453 | }, 1454 | "node_modules/which": { 1455 | "version": "2.0.2", 1456 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1457 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1458 | "dev": true, 1459 | "dependencies": { 1460 | "isexe": "^2.0.0" 1461 | }, 1462 | "bin": { 1463 | "node-which": "bin/node-which" 1464 | }, 1465 | "engines": { 1466 | "node": ">= 8" 1467 | } 1468 | }, 1469 | "node_modules/wrap-ansi": { 1470 | "version": "7.0.0", 1471 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1472 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1473 | "dev": true, 1474 | "dependencies": { 1475 | "ansi-styles": "^4.0.0", 1476 | "string-width": "^4.1.0", 1477 | "strip-ansi": "^6.0.0" 1478 | }, 1479 | "engines": { 1480 | "node": ">=10" 1481 | }, 1482 | "funding": { 1483 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1484 | } 1485 | }, 1486 | "node_modules/wrap-ansi-cjs": { 1487 | "name": "wrap-ansi", 1488 | "version": "7.0.0", 1489 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1490 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1491 | "dev": true, 1492 | "dependencies": { 1493 | "ansi-styles": "^4.0.0", 1494 | "string-width": "^4.1.0", 1495 | "strip-ansi": "^6.0.0" 1496 | }, 1497 | "engines": { 1498 | "node": ">=10" 1499 | }, 1500 | "funding": { 1501 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1502 | } 1503 | }, 1504 | "node_modules/wrappy": { 1505 | "version": "1.0.2", 1506 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1507 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1508 | "dev": true 1509 | }, 1510 | "node_modules/y18n": { 1511 | "version": "5.0.8", 1512 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1513 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1514 | "dev": true, 1515 | "engines": { 1516 | "node": ">=10" 1517 | } 1518 | }, 1519 | "node_modules/yaml": { 1520 | "version": "2.4.2", 1521 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", 1522 | "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", 1523 | "dev": true, 1524 | "bin": { 1525 | "yaml": "bin.mjs" 1526 | }, 1527 | "engines": { 1528 | "node": ">= 14" 1529 | } 1530 | }, 1531 | "node_modules/yargs": { 1532 | "version": "17.7.2", 1533 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1534 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1535 | "dev": true, 1536 | "dependencies": { 1537 | "cliui": "^8.0.1", 1538 | "escalade": "^3.1.1", 1539 | "get-caller-file": "^2.0.5", 1540 | "require-directory": "^2.1.1", 1541 | "string-width": "^4.2.3", 1542 | "y18n": "^5.0.5", 1543 | "yargs-parser": "^21.1.1" 1544 | }, 1545 | "engines": { 1546 | "node": ">=12" 1547 | } 1548 | }, 1549 | "node_modules/yargs-parser": { 1550 | "version": "21.1.1", 1551 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1552 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1553 | "dev": true, 1554 | "engines": { 1555 | "node": ">=12" 1556 | } 1557 | } 1558 | } 1559 | } 1560 | -------------------------------------------------------------------------------- /bulma/static/bulma/sass/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Tim Kamanin", 4 | "email": "tim@timonweb.com", 5 | "url": "https://timonweb.com" 6 | }, 7 | "description": "Bulma for Django", 8 | "dependencies": { 9 | "bulma": "^1.0.0" 10 | }, 11 | "devDependencies": { 12 | "autoprefixer": "^10.4.19", 13 | "clean-css-cli": "^5.6.3", 14 | "sass": "^1.77.1", 15 | "postcss-cli": "^11.0.0", 16 | "rimraf": "^5.0.7" 17 | }, 18 | "license": "MIT", 19 | "main": "style.sass", 20 | "style": "../css/style.min.css", 21 | "name": "django_bulma", 22 | "scripts": { 23 | "build": "npm run build-clean && npm run build-sass && npm run build-autoprefix && npm run build-cleancss", 24 | "build-autoprefix": "postcss --use autoprefixer --map false --output ../css/style.css ../css/style.css", 25 | "build-cleancss": "cleancss -o ../css/style.min.css ../css/style.css", 26 | "build-clean": "rimraf css", 27 | "build-sass": "sass --style expanded style.sass ../css/style.css", 28 | "deploy": "npm run build", 29 | "start": "npm run build-sass -- --watch" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bulma/static/bulma/sass/style.sass: -------------------------------------------------------------------------------- 1 | // 1. Import the initial variables 2 | @import "./node_modules/bulma/sass/utilities/initial-variables" 3 | 4 | // 2. Set your own initial variables 5 | 6 | // 3. Import the rest of Bulma 7 | @import "./node_modules/bulma/bulma" 8 | 9 | // 4. Import your stuff here -------------------------------------------------------------------------------- /bulma/templates/_layouts/one-column-center.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content_area %} 3 |
4 |
5 | {% block content_title %}{% endblock content_title %} 6 | {% block content %}{% endblock content %} 7 |
8 |
9 | {% endblock content_area %} -------------------------------------------------------------------------------- /bulma/templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'bulma/base.html' %} -------------------------------------------------------------------------------- /bulma/templates/bulma/base.html: -------------------------------------------------------------------------------- 1 | {% load static bulma_tags %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}{% endblock title %} 8 | {% block css %} 9 | {% font_awesome %} 10 | 11 | {% block extra_css %}{% endblock extra_css %} 12 | {% endblock css %} 13 | 14 | 15 | 16 | {% block header %} 17 |
18 | 113 |
114 | {% endblock header %} 115 | 116 | {% block hero %}{% endblock hero %} 117 | 118 |
119 |
120 | {% block messages %} 121 | {% if messages %} 122 |
123 |
124 | {% for message in messages %} 125 |
126 |
{{ message }}
127 |
128 | {% endfor %} 129 |
130 |
131 | {% endif %} 132 | {% endblock messages %} 133 | 134 | {% block content_area %} 135 | {% block content_title %}{% endblock content_title %} 136 | {% block content %}{% endblock content %} 137 | {% endblock content_area %} 138 |
139 |
140 | 141 | {% block modal %}{% endblock modal %} 142 | 143 | {% block footer %} 144 | 160 | {% endblock footer %} 161 | 162 | {% block javascript %} 163 | {% block extra_javascript %}{% endblock extra_javascript %} 164 | {% endblock javascript %} 165 | 166 | -------------------------------------------------------------------------------- /bulma/templates/bulma/forms/field.html: -------------------------------------------------------------------------------- 1 | {% load bulma_tags %} 2 |
3 | {% if field|is_checkbox %} 4 | 5 |
6 | {% if field.auto_id %} 7 | 11 | {% endif %} 12 | {% for error in field.errors %} 13 | {{ error }} 14 | {% endfor %} 15 | 16 | {% if field.help_text %} 17 |

18 | {{ field.help_text|safe }} 19 |

20 | {% endif %} 21 |
22 | 23 | {% elif field|is_radio %} 24 | 25 | {% if field.auto_id %} 26 | 28 | {% endif %} 29 |
30 | {% for choice in field %} 31 | 35 | {% endfor %} 36 | 37 | {% for error in field.errors %} 38 | {{ error }} 39 | {% endfor %} 40 | 41 | {% if field.help_text %} 42 |

43 | {{ field.help_text|safe }} 44 |

45 | {% endif %} 46 |
47 | 48 | {% elif field|is_input %} 49 | 50 | 52 |
53 | {{ field|addclass:'input' }} 54 | {% for error in field.errors %} 55 | {{ error }} 56 | {% endfor %} 57 | {% if field.help_text %} 58 |

59 | {{ field.help_text|safe }} 60 |

61 | {% endif %} 62 |
63 | 64 | {% elif field|is_textarea %} 65 | 66 | 68 |
69 | {{ field|addclass:'textarea' }} 70 | {% for error in field.errors %} 71 | {{ error }} 72 | {% endfor %} 73 | {% if field.help_text %} 74 |

75 | {{ field.help_text|safe }} 76 |

77 | {% endif %} 78 |
79 | 80 | {% elif field|is_select %} 81 | 82 | 84 |
85 | 86 | {{ field }} 87 | 88 | {% for error in field.errors %} 89 | {{ error }} 90 | {% endfor %} 91 | {% if field.help_text %} 92 |

93 | {{ field.help_text|safe }} 94 |

95 | {% endif %} 96 |
97 | 98 | {% elif field|is_file %} 99 | 100 | 102 |
103 | 104 | 115 | 116 | {% for error in field.errors %} 117 | {{ error }} 118 | {% endfor %} 119 | {% if field.help_text %} 120 |

121 | {{ field.help_text|safe }} 122 |

123 | {% endif %} 124 |
125 | 126 | {% else %} 127 | 128 | {% if field.auto_id %} 129 | 131 | {% endif %} 132 | 133 |
134 | {{ field }} 135 | 136 | {% for error in field.errors %} 137 | {{ error }} 138 | {% endfor %} 139 | 140 | {% if field.help_text %} 141 |

142 | {{ field.help_text|safe }} 143 |

144 | {% endif %} 145 |
146 | 147 | {% endif %} 148 |
-------------------------------------------------------------------------------- /bulma/templates/bulma/forms/form.html: -------------------------------------------------------------------------------- 1 | {% if form.non_field_errors %} 2 |
3 |
4 | 5 |
6 |
7 | {% for non_field_error in form.non_field_errors %} 8 | {{ non_field_error }} 9 | {% endfor %} 10 |
11 |
12 | {% endif %} 13 | 14 | {% for field in form.hidden_fields %} 15 | {{ field }} 16 | {% endfor %} 17 | 18 | {% for field in form.visible_fields %} 19 | {% include 'bulma/forms/field.html' %} 20 | {% endfor %} 21 | -------------------------------------------------------------------------------- /bulma/templates/bulma/forms/formset.html: -------------------------------------------------------------------------------- 1 | {{ formset.management_form }} 2 | {% for form in formset %} 3 | {% include "bulma/forms/form.html" with form=form %} 4 | {% endfor %} 5 | -------------------------------------------------------------------------------- /bulma/templates/pagination.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | {% if is_paginated %} 4 | 26 | {% endif %} -------------------------------------------------------------------------------- /bulma/templates/registration/base.html: -------------------------------------------------------------------------------- 1 | {% extends '_layouts/one-column-center.html' %} -------------------------------------------------------------------------------- /bulma/templates/registration/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |

{% trans "Thanks for spending some quality time with the Web site today." %}

6 |

{% trans 'Log in again' %}

7 | {% endblock %} -------------------------------------------------------------------------------- /bulma/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load bulma_tags i18n %} 3 | 4 | {% block content %} 5 | 6 | {% if form.errors %} 7 |

{% trans "Your username and password didn't match. Please try again." %}

8 | {% endif %} 9 | 10 |
11 | {% csrf_token %} 12 | {{ form|bulma }} 13 |
14 | 15 |
16 | 17 |
18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /bulma/templates/registration/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block content_title %}

{{ title }}

{% endblock %} 6 | {% block content %} 7 |

{% trans 'Your password was changed.' %}

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /bulma/templates/registration/password_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n static bulma_tags %} 3 | {% block title %}{{ title }}{% endblock %} 4 | {% block content_title %}

{{ title }}

{% endblock %} 5 | 6 | {% block content %} 7 | 8 |
9 | {% csrf_token %} 10 |
11 | {% if form.errors %} 12 |

13 | {% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %} 14 | {% trans "Please correct the errors below." %}{% endif %} 15 |

16 | {% endif %} 17 | 18 |

{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}

19 | 20 | {{ form|bulma }} 21 | 22 | 23 |
24 |
25 | 26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /bulma/templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block content_title %}

{{ title }}

{% endblock %} 6 | 7 | {% block content %} 8 | 9 |

{% trans "Your password has been set. You may go ahead and log in now." %}

10 | 11 |

{% trans 'Log in' %}

12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /bulma/templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n static bulma_tags %} 3 | 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block content_title %}

{{ title }}

{% endblock %} 6 | {% block content %} 7 | 8 | {% if validlink %} 9 |

{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}

10 |
{% csrf_token %} 11 | {{ form|bulma }} 12 | 13 |
14 | {% else %} 15 |

{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

16 | {% endif %} 17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /bulma/templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block content_title %}

{{ title }}

{% endblock %} 6 | {% block content %} 7 |
8 |

{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}

9 |

{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}

10 |
11 | {% endblock %} -------------------------------------------------------------------------------- /bulma/templates/registration/password_reset_email.html: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% autoescape off %} 2 | {% blocktrans %}You're receiving this email because you requested a password reset for your user account at 3 | {{ site_name }}.{% endblocktrans %} 4 | 5 | {% trans "Please go to the following page and choose a new password:" %} 6 | {% block reset_link %} 7 | {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} 8 | {% endblock %} 9 | {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} 10 | 11 | {% trans "Thanks for using our site!" %} 12 | 13 | {% blocktrans %}The {{ site_name }} team{% endblocktrans %} 14 | 15 | {% endautoescape %} 16 | -------------------------------------------------------------------------------- /bulma/templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | {% load i18n static bulma_tags %} 3 | 4 | {% block title %}{{ title }}{% endblock %} 5 | {% block content_title %}

{{ title }}

{% endblock %} 6 | {% block content %} 7 |

{% trans "Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one." %}

8 |
{% csrf_token %} 9 | {{ form|bulma }} 10 | 11 |
12 | {% endblock %} -------------------------------------------------------------------------------- /bulma/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/bulma/templatetags/__init__.py -------------------------------------------------------------------------------- /bulma/templatetags/bulma_tags.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django import template 3 | from django.forms import BoundField 4 | from django.template.loader import get_template 5 | from django.utils.safestring import mark_safe 6 | 7 | register = template.Library() 8 | 9 | BULMA_COLUMN_COUNT = 1 10 | 11 | 12 | @register.simple_tag 13 | def font_awesome(): 14 | """ 15 | The latest FontAwesome CDN link. 16 | """ 17 | cdn_link = ( 18 | '' 22 | ) 23 | return mark_safe(cdn_link) 24 | 25 | 26 | @register.filter 27 | def bulma(element): 28 | markup_classes = {'label': '', 'value': '', 'single_value': ''} 29 | return render(element, markup_classes) 30 | 31 | 32 | @register.filter 33 | def bulma_inline(element): 34 | markup_classes = {'label': 'sr-only', 'value': '', 'single_value': ''} 35 | return render(element, markup_classes) 36 | 37 | 38 | @register.filter 39 | def bulma_horizontal(element, label_cols='is-2'): 40 | markup_classes = {'label': label_cols, 'value': '', 'single_value': ''} 41 | 42 | for cl in label_cols.split(' '): 43 | splitted_class = cl.split('-') 44 | 45 | try: 46 | value_nb_cols = int(splitted_class[-1]) 47 | except ValueError: 48 | value_nb_cols = BULMA_COLUMN_COUNT 49 | 50 | if value_nb_cols >= BULMA_COLUMN_COUNT: 51 | splitted_class[-1] = str(BULMA_COLUMN_COUNT) 52 | else: 53 | offset_class = cl.split('-') 54 | offset_class[-1] = 'offset-' + str(value_nb_cols) 55 | splitted_class[-1] = str(BULMA_COLUMN_COUNT - value_nb_cols) 56 | markup_classes['single_value'] += ' ' + '-'.join(offset_class) 57 | markup_classes['single_value'] += ' ' + '-'.join(splitted_class) 58 | 59 | markup_classes['value'] += ' ' + '-'.join(splitted_class) 60 | 61 | return render(element, markup_classes) 62 | 63 | 64 | @register.filter 65 | def add_input_classes(field): 66 | if not is_checkbox(field) and not is_multiple_checkbox(field) \ 67 | and not is_radio(field) and not is_file(field): 68 | field_classes = field.field.widget.attrs.get('class', '') 69 | field_classes += ' control' 70 | field.field.widget.attrs['class'] = field_classes 71 | 72 | 73 | def render(element, markup_classes): 74 | if isinstance(element, BoundField): 75 | add_input_classes(element) 76 | template = get_template("bulma/forms/field.html") 77 | context = {'field': element, 78 | 'classes': markup_classes, 'form': element.form} 79 | else: 80 | has_management = getattr(element, 'management_form', None) 81 | if has_management: 82 | for form in element.forms: 83 | for field in form.visible_fields(): 84 | add_input_classes(field) 85 | 86 | template = get_template("bulma/forms/formset.html") 87 | context = {'formset': element, 'classes': markup_classes} 88 | else: 89 | for field in element.visible_fields(): 90 | add_input_classes(field) 91 | 92 | template = get_template("bulma/forms/form.html") 93 | context = {'form': element, 'classes': markup_classes} 94 | 95 | return template.render(context) 96 | 97 | 98 | @register.filter 99 | def widget_type(field): 100 | return field.field.widget 101 | 102 | 103 | @register.filter 104 | def is_select(field): 105 | return isinstance(field.field.widget, forms.Select) 106 | 107 | 108 | @register.filter 109 | def is_multiple_select(field): 110 | return isinstance(field.field.widget, forms.SelectMultiple) 111 | 112 | 113 | @register.filter 114 | def is_textarea(field): 115 | return isinstance(field.field.widget, forms.Textarea) 116 | 117 | 118 | @register.filter 119 | def is_input(field): 120 | return isinstance(field.field.widget, ( 121 | forms.TextInput, 122 | forms.NumberInput, 123 | forms.EmailInput, 124 | forms.PasswordInput, 125 | forms.URLInput 126 | )) 127 | 128 | 129 | @register.filter 130 | def is_checkbox(field): 131 | return isinstance(field.field.widget, forms.CheckboxInput) 132 | 133 | 134 | @register.filter 135 | def is_multiple_checkbox(field): 136 | return isinstance(field.field.widget, forms.CheckboxSelectMultiple) 137 | 138 | 139 | @register.filter 140 | def is_radio(field): 141 | return isinstance(field.field.widget, forms.RadioSelect) 142 | 143 | 144 | @register.filter 145 | def is_file(field): 146 | return isinstance(field.field.widget, forms.FileInput) 147 | 148 | 149 | @register.filter 150 | def addclass(field, css_class): 151 | if len(field.errors) > 0: 152 | css_class += ' is-danger' 153 | field_classes = field.field.widget.attrs.get('class', '') 154 | field_classes += f' {css_class}' 155 | return field.as_widget(attrs={"class": field_classes}) 156 | 157 | 158 | 159 | @register.filter 160 | def bulma_message_tag(tag): 161 | return { 162 | 'error': 'danger' 163 | }.get(tag, tag) 164 | -------------------------------------------------------------------------------- /bulma/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/bulma/tests/__init__.py -------------------------------------------------------------------------------- /bulma/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | import shutil 4 | from django.conf import settings 5 | 6 | 7 | @pytest.yield_fixture 8 | def cleanup_static_files(): 9 | static_files_dir = settings.STATICFILES_DIRS[0] 10 | if os.path.isdir(static_files_dir): 11 | shutil.rmtree(static_files_dir) 12 | yield 13 | if os.path.isdir(static_files_dir): 14 | shutil.rmtree(static_files_dir) 15 | -------------------------------------------------------------------------------- /bulma/tests/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | COLOR_CHOICES = ( 4 | ('red', 'Red'), 5 | ('green', 'Green'), 6 | ('blue', 'Blue') 7 | ) 8 | 9 | 10 | class FormExample(forms.Form): 11 | text = forms.CharField() 12 | email = forms.EmailField() 13 | number = forms.CharField(widget=forms.NumberInput()) 14 | url = forms.CharField(widget=forms.URLInput()) 15 | password = forms.CharField(widget=forms.PasswordInput()) 16 | select = forms.ChoiceField(choices=COLOR_CHOICES) 17 | multi_select = forms.MultipleChoiceField(choices=COLOR_CHOICES) 18 | textarea = forms.CharField(widget=forms.Textarea()) 19 | checkbox = forms.BooleanField() 20 | checkboxes = forms.MultipleChoiceField( 21 | choices=COLOR_CHOICES, 22 | widget=forms.CheckboxSelectMultiple() 23 | ) 24 | radios = forms.ChoiceField( 25 | choices=COLOR_CHOICES, 26 | widget=forms.RadioSelect() 27 | ) 28 | file = forms.FileField(required=True) 29 | -------------------------------------------------------------------------------- /bulma/tests/test_commands.py: -------------------------------------------------------------------------------- 1 | import os 2 | from io import StringIO 3 | 4 | import pytest 5 | from django.core.management import call_command, CommandError 6 | 7 | from django.conf import settings 8 | 9 | BULMA_STATIC_DIR = os.path.join(settings.STATICFILES_DIRS[0], 'bulma') 10 | 11 | 12 | def test_bulma_command_without_second_argument_displays_command_error_message(): 13 | out = StringIO() 14 | with pytest.raises(CommandError) as err: 15 | call_command('bulma', stdout=out) 16 | 17 | assert 'Command argument is missing, please add one of the following' in str(err.value) 18 | 19 | 20 | def test_copy_static_content(cleanup_static_files): 21 | style_css = os.path.join(BULMA_STATIC_DIR, 'css', 'style.css') 22 | style_sass = os.path.join(BULMA_STATIC_DIR, 'sass', 'style.sass') 23 | package_json = os.path.join(BULMA_STATIC_DIR, 'sass', 'package.json') 24 | 25 | out = StringIO() 26 | call_command('copy_bulma_static_into_project', stdout=out) 27 | 28 | assert os.path.isfile(style_css), f'{str(style_css)} has been created' 29 | assert os.path.isfile(style_sass), f'{str(style_sass)} has been created' 30 | assert os.path.isfile(package_json), f'{str(package_json)} has been created' 31 | 32 | 33 | def test_bulma_install_command(cleanup_static_files): 34 | call_command('copy_bulma_static_into_project') 35 | 36 | out = StringIO() 37 | call_command('bulma', 'install', stdout=out) 38 | 39 | assert os.path.isdir(os.path.join(BULMA_STATIC_DIR, 'sass', 'node_modules')), "node_modules have been created" 40 | assert os.path.isfile( 41 | os.path.join(BULMA_STATIC_DIR, 'sass', 'package-lock.json')), "package-lock.json has been created" 42 | 43 | 44 | def test_bulma_build_command(cleanup_static_files): 45 | style_css = os.path.join(BULMA_STATIC_DIR, 'css', 'style.css') 46 | style_min_css = os.path.join(BULMA_STATIC_DIR, 'css', 'style.min.css') 47 | 48 | call_command('copy_bulma_static_into_project') 49 | 50 | # Delete preinstalled files 51 | os.remove(style_css) 52 | os.remove(style_min_css) 53 | 54 | call_command('bulma', 'install') 55 | 56 | out = StringIO() 57 | call_command('bulma', 'build', stdout=out) 58 | 59 | # Ensure new file have been generated 60 | assert os.path.isfile(style_css), f'{str(style_css)} has been created' 61 | assert os.path.isfile(style_min_css), f'{str(style_min_css)} has been created' 62 | -------------------------------------------------------------------------------- /bulma/tests/test_inputs.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django import forms 3 | 4 | from .utils import render_form, get_dom, element_has_all_attributes 5 | 6 | COLOR_CHOICES = ( 7 | ('red', 'Red'), 8 | ('green', 'Green'), 9 | ('blue', 'Blue') 10 | ) 11 | 12 | 13 | @pytest.mark.parametrize("field,label,tag,attributes", [ 14 | (forms.CharField(), "Name", 'input', { 15 | 'name': 'input', 16 | 'class': ['control', 'input'], 17 | 'type': 'text' 18 | }), 19 | (forms.EmailField(), "Email", 'input', { 20 | 'name': 'input', 21 | 'class': ['control', 'input'], 22 | 'type': 'email' 23 | }), 24 | (forms.CharField(widget=forms.NumberInput()), "Email", 'input', { 25 | 'name': 'input', 26 | 'class': ['control', 'input'], 27 | 'type': 'number' 28 | }), 29 | (forms.CharField(widget=forms.URLInput()), "Url", 'input', { 30 | 'name': 'input', 31 | 'class': ['control', 'input'], 32 | 'type': 'url' 33 | }), 34 | (forms.CharField(widget=forms.PasswordInput()), "Password", 'input', { 35 | 'name': 'input', 36 | 'class': ['control', 'input'], 37 | 'type': 'password' 38 | }), 39 | (forms.ChoiceField(choices=[]), "Select", 'select', { 40 | 'name': 'input', 41 | 'class': ['control'] 42 | }), 43 | (forms.MultipleChoiceField(choices=[]), "Multi select", 'select', { 44 | 'name': 'input', 45 | 'class': ['control'], 46 | 'multiple': "" 47 | }), 48 | (forms.CharField(widget=forms.Textarea()), "Textarea", 'textarea', { 49 | 'name': 'input', 50 | 'class': ['control', 'textarea'] 51 | }), 52 | (forms.BooleanField(), "Checkbox", 'input', { 53 | 'name': 'input', 54 | 'type': 'checkbox' 55 | }), 56 | (forms.MultipleChoiceField( 57 | choices=COLOR_CHOICES, 58 | widget=forms.CheckboxSelectMultiple() 59 | ), "Checkboxes", 'input', { 60 | 'name': 'input', 61 | 'type': 'checkbox', 62 | 'value': 'red' 63 | }), 64 | (forms.ChoiceField( 65 | choices=COLOR_CHOICES, 66 | widget=forms.RadioSelect() 67 | ), "Radios", 'input', { 68 | 'name': 'input', 69 | 'type': 'radio', 70 | 'value': 'red' 71 | }), 72 | (forms.FileField(), "File input", 'input', { 73 | 'name': 'input', 74 | 'type': 'file', 75 | 'class': ['file-input'] 76 | }) 77 | ]) 78 | def test_input_rendering(field, tag, label, attributes): 79 | class TestForm(forms.Form): 80 | input = field 81 | 82 | def __init__(self, *args, **kwargs): 83 | super().__init__(*args, **kwargs) 84 | self.fields['input'].label = label 85 | 86 | output = render_form(TestForm()) 87 | dom = get_dom(output) 88 | 89 | element_has_all_attributes(dom.find(tag), attributes), f"{label} has attributes {str(attributes)}" 90 | assert dom.find('label').text.strip() == label, f"Field has label {label}" 91 | -------------------------------------------------------------------------------- /bulma/tests/test_templates.py: -------------------------------------------------------------------------------- 1 | from bulma.tests.forms import FormExample 2 | from bulma.tests.utils import render_template 3 | 4 | 5 | def test_bulma_base_template(): 6 | output = render_template( 7 | """ 8 | {% extends 'bulma/base.html' %} 9 | {% block content %} 10 | test_bulma_content 11 | {% endblock content %} 12 | """ 13 | ) 14 | 15 | assert "test_bulma_content" in output, "Content is in template" 16 | 17 | 18 | def test_style_css_is_in_template(): 19 | output = render_template( 20 | """ 21 | {% extends 'bulma/base.html' %} 22 | """ 23 | ) 24 | assert '' in output 25 | 26 | 27 | def test_bulma_form_tag(): 28 | output = render_template( 29 | """ 30 | {% extends 'bulma/base.html' %} 31 | {% load bulma_tags %} 32 | {% block content %} 33 |
{{ form|bulma }}
34 | {% endblock content %} 35 | """, context={ 36 | 'form': FormExample() 37 | } 38 | ) 39 | 40 | assert '
23 | {% csrf_token %} 24 | {{ form|bulma }} 25 | 26 | 27 | {% endblock %} 28 | """, context={ 29 | 'form': form 30 | } 31 | ) 32 | 33 | 34 | def get_dom(html): 35 | return BeautifulSoup(html, 'html.parser') 36 | 37 | 38 | def element_has_all_attributes(element, attributes): 39 | for attribute_name, attribute_value in attributes.items(): 40 | assert element.has_attr(attribute_name) is True 41 | print(element.get(attribute_name)) 42 | assert element.get(attribute_name) == attribute_value, f'Element {element} has attribute "{attribute_name}" with value {attribute_value}' 43 | #return False 44 | #return True 45 | 46 | 47 | def element_has_attribute(element, attribute_name, attribute_value): 48 | return element.has_attr(attribute_name) and element.get(attribute_name) == attribute_value 49 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "asgiref" 5 | version = "3.7.2" 6 | description = "ASGI specs, helper code, and adapters" 7 | optional = false 8 | python-versions = ">=3.7" 9 | files = [ 10 | {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, 11 | {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, 12 | ] 13 | 14 | [package.dependencies] 15 | typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} 16 | 17 | [package.extras] 18 | tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] 19 | 20 | [[package]] 21 | name = "atomicwrites" 22 | version = "1.4.1" 23 | description = "Atomic file writes." 24 | optional = false 25 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 26 | files = [ 27 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, 28 | ] 29 | 30 | [[package]] 31 | name = "attrs" 32 | version = "23.2.0" 33 | description = "Classes Without Boilerplate" 34 | optional = false 35 | python-versions = ">=3.7" 36 | files = [ 37 | {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, 38 | {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, 39 | ] 40 | 41 | [package.dependencies] 42 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 43 | 44 | [package.extras] 45 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 46 | dev = ["attrs[tests]", "pre-commit"] 47 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 48 | tests = ["attrs[tests-no-zope]", "zope-interface"] 49 | tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] 50 | tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] 51 | 52 | [[package]] 53 | name = "beautifulsoup4" 54 | version = "4.12.3" 55 | description = "Screen-scraping library" 56 | optional = false 57 | python-versions = ">=3.6.0" 58 | files = [ 59 | {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, 60 | {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, 61 | ] 62 | 63 | [package.dependencies] 64 | soupsieve = ">1.2" 65 | 66 | [package.extras] 67 | cchardet = ["cchardet"] 68 | chardet = ["chardet"] 69 | charset-normalizer = ["charset-normalizer"] 70 | html5lib = ["html5lib"] 71 | lxml = ["lxml"] 72 | 73 | [[package]] 74 | name = "colorama" 75 | version = "0.4.6" 76 | description = "Cross-platform colored terminal text." 77 | optional = false 78 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 79 | files = [ 80 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 81 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 82 | ] 83 | 84 | [[package]] 85 | name = "distlib" 86 | version = "0.3.8" 87 | description = "Distribution utilities" 88 | optional = false 89 | python-versions = "*" 90 | files = [ 91 | {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, 92 | {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, 93 | ] 94 | 95 | [[package]] 96 | name = "django" 97 | version = "3.2.25" 98 | description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." 99 | optional = false 100 | python-versions = ">=3.6" 101 | files = [ 102 | {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, 103 | {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, 104 | ] 105 | 106 | [package.dependencies] 107 | asgiref = ">=3.3.2,<4" 108 | pytz = "*" 109 | sqlparse = ">=0.2.2" 110 | 111 | [package.extras] 112 | argon2 = ["argon2-cffi (>=19.1.0)"] 113 | bcrypt = ["bcrypt"] 114 | 115 | [[package]] 116 | name = "filelock" 117 | version = "3.12.2" 118 | description = "A platform independent file lock." 119 | optional = false 120 | python-versions = ">=3.7" 121 | files = [ 122 | {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, 123 | {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, 124 | ] 125 | 126 | [package.extras] 127 | docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] 128 | testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] 129 | 130 | [[package]] 131 | name = "importlib-metadata" 132 | version = "6.7.0" 133 | description = "Read metadata from Python packages" 134 | optional = false 135 | python-versions = ">=3.7" 136 | files = [ 137 | {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, 138 | {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, 139 | ] 140 | 141 | [package.dependencies] 142 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 143 | zipp = ">=0.5" 144 | 145 | [package.extras] 146 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 147 | perf = ["ipython"] 148 | testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] 149 | 150 | [[package]] 151 | name = "more-itertools" 152 | version = "9.1.0" 153 | description = "More routines for operating on iterables, beyond itertools" 154 | optional = false 155 | python-versions = ">=3.7" 156 | files = [ 157 | {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"}, 158 | {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, 159 | ] 160 | 161 | [[package]] 162 | name = "packaging" 163 | version = "24.0" 164 | description = "Core utilities for Python packages" 165 | optional = false 166 | python-versions = ">=3.7" 167 | files = [ 168 | {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, 169 | {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, 170 | ] 171 | 172 | [[package]] 173 | name = "platformdirs" 174 | version = "4.0.0" 175 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 176 | optional = false 177 | python-versions = ">=3.7" 178 | files = [ 179 | {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, 180 | {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, 181 | ] 182 | 183 | [package.dependencies] 184 | typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} 185 | 186 | [package.extras] 187 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] 188 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] 189 | 190 | [[package]] 191 | name = "pluggy" 192 | version = "0.13.1" 193 | description = "plugin and hook calling mechanisms for python" 194 | optional = false 195 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 196 | files = [ 197 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 198 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 199 | ] 200 | 201 | [package.dependencies] 202 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 203 | 204 | [package.extras] 205 | dev = ["pre-commit", "tox"] 206 | 207 | [[package]] 208 | name = "py" 209 | version = "1.11.0" 210 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 211 | optional = false 212 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 213 | files = [ 214 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 215 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 216 | ] 217 | 218 | [[package]] 219 | name = "pytest" 220 | version = "5.4.3" 221 | description = "pytest: simple powerful testing with Python" 222 | optional = false 223 | python-versions = ">=3.5" 224 | files = [ 225 | {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, 226 | {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, 227 | ] 228 | 229 | [package.dependencies] 230 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 231 | attrs = ">=17.4.0" 232 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 233 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 234 | more-itertools = ">=4.0.0" 235 | packaging = "*" 236 | pluggy = ">=0.12,<1.0" 237 | py = ">=1.5.0" 238 | wcwidth = "*" 239 | 240 | [package.extras] 241 | checkqa-mypy = ["mypy (==v0.761)"] 242 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 243 | 244 | [[package]] 245 | name = "pytest-django" 246 | version = "3.10.0" 247 | description = "A Django plugin for pytest." 248 | optional = false 249 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 250 | files = [ 251 | {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"}, 252 | {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"}, 253 | ] 254 | 255 | [package.dependencies] 256 | pytest = ">=3.6" 257 | 258 | [package.extras] 259 | docs = ["sphinx", "sphinx-rtd-theme"] 260 | testing = ["Django", "django-configurations (>=2.0)", "six"] 261 | 262 | [[package]] 263 | name = "pytz" 264 | version = "2024.1" 265 | description = "World timezone definitions, modern and historical" 266 | optional = false 267 | python-versions = "*" 268 | files = [ 269 | {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, 270 | {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, 271 | ] 272 | 273 | [[package]] 274 | name = "six" 275 | version = "1.16.0" 276 | description = "Python 2 and 3 compatibility utilities" 277 | optional = false 278 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 279 | files = [ 280 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 281 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 282 | ] 283 | 284 | [[package]] 285 | name = "soupsieve" 286 | version = "2.4.1" 287 | description = "A modern CSS selector implementation for Beautiful Soup." 288 | optional = false 289 | python-versions = ">=3.7" 290 | files = [ 291 | {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, 292 | {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, 293 | ] 294 | 295 | [[package]] 296 | name = "sqlparse" 297 | version = "0.4.4" 298 | description = "A non-validating SQL parser." 299 | optional = false 300 | python-versions = ">=3.5" 301 | files = [ 302 | {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, 303 | {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, 304 | ] 305 | 306 | [package.extras] 307 | dev = ["build", "flake8"] 308 | doc = ["sphinx"] 309 | test = ["pytest", "pytest-cov"] 310 | 311 | [[package]] 312 | name = "tomli" 313 | version = "2.0.1" 314 | description = "A lil' TOML parser" 315 | optional = false 316 | python-versions = ">=3.7" 317 | files = [ 318 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 319 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 320 | ] 321 | 322 | [[package]] 323 | name = "tox" 324 | version = "3.28.0" 325 | description = "tox is a generic virtualenv management and test command line tool" 326 | optional = false 327 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 328 | files = [ 329 | {file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"}, 330 | {file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"}, 331 | ] 332 | 333 | [package.dependencies] 334 | colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} 335 | filelock = ">=3.0.0" 336 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 337 | packaging = ">=14" 338 | pluggy = ">=0.12.0" 339 | py = ">=1.4.17" 340 | six = ">=1.14.0" 341 | tomli = {version = ">=2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} 342 | virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" 343 | 344 | [package.extras] 345 | docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] 346 | testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"] 347 | 348 | [[package]] 349 | name = "typing-extensions" 350 | version = "4.7.1" 351 | description = "Backported and Experimental Type Hints for Python 3.7+" 352 | optional = false 353 | python-versions = ">=3.7" 354 | files = [ 355 | {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, 356 | {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, 357 | ] 358 | 359 | [[package]] 360 | name = "virtualenv" 361 | version = "20.26.2" 362 | description = "Virtual Python Environment builder" 363 | optional = false 364 | python-versions = ">=3.7" 365 | files = [ 366 | {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, 367 | {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, 368 | ] 369 | 370 | [package.dependencies] 371 | distlib = ">=0.3.7,<1" 372 | filelock = ">=3.12.2,<4" 373 | importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} 374 | platformdirs = ">=3.9.1,<5" 375 | 376 | [package.extras] 377 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] 378 | test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] 379 | 380 | [[package]] 381 | name = "wcwidth" 382 | version = "0.2.13" 383 | description = "Measures the displayed width of unicode strings in a terminal" 384 | optional = false 385 | python-versions = "*" 386 | files = [ 387 | {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, 388 | {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, 389 | ] 390 | 391 | [[package]] 392 | name = "zipp" 393 | version = "3.15.0" 394 | description = "Backport of pathlib-compatible object wrapper for zip files" 395 | optional = false 396 | python-versions = ">=3.7" 397 | files = [ 398 | {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, 399 | {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, 400 | ] 401 | 402 | [package.extras] 403 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 404 | testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 405 | 406 | [metadata] 407 | lock-version = "2.0" 408 | python-versions = ">=3.7" 409 | content-hash = "8da55925859b407644ea7f8375efc71d197c55922d76bf8af90e85b80fc3e6e0" 410 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "django-bulma" 3 | version = "0.9.0" 4 | description = "Bulma CSS Framework for Django projects" 5 | authors = ["Tim Kamanin "] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://timonweb.com" 9 | keywords = ["django", "css", "bulma", "theme"] 10 | classifiers = [ 11 | "Development Status :: 4 - Beta", 12 | "Intended Audience :: Developers", 13 | "License :: OSI Approved :: Apache Software License", 14 | "Programming Language :: Python :: 3.7", 15 | "Programming Language :: Python :: 3.8", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Operating System :: OS Independent", 20 | "Topic :: Software Development :: Libraries", 21 | "Topic :: Utilities", 22 | "Environment :: Web Environment", 23 | "Framework :: Django" 24 | ] 25 | packages = [ 26 | { include = "bulma" } 27 | ] 28 | 29 | [tool.poetry.dependencies] 30 | python = ">=3.7" 31 | django = ">=2.2" 32 | 33 | [tool.poetry.dev-dependencies] 34 | pytest-django = "^3.8.0" 35 | pytest = "^5.3.4" 36 | tox = "^3.14.3" 37 | beautifulsoup4 = "^4.8.2" 38 | 39 | [build-system] 40 | requires = ["poetry>=0.12"] 41 | build-backend = "poetry.masonry.api" 42 | -------------------------------------------------------------------------------- /showcase/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/showcase/__init__.py -------------------------------------------------------------------------------- /showcase/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /showcase/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ShowcaseConfig(AppConfig): 5 | name = 'showcase' 6 | -------------------------------------------------------------------------------- /showcase/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | COLOR_CHOICES = ( 4 | ('red', 'Red'), 5 | ('green', 'Green'), 6 | ('blue', 'Blue') 7 | ) 8 | 9 | 10 | class FormExample(forms.Form): 11 | text = forms.CharField() 12 | email = forms.EmailField() 13 | number = forms.CharField(widget=forms.NumberInput()) 14 | url = forms.CharField(widget=forms.URLInput()) 15 | password = forms.CharField(widget=forms.PasswordInput()) 16 | select = forms.ChoiceField(choices=COLOR_CHOICES) 17 | multi_select = forms.MultipleChoiceField(choices=COLOR_CHOICES) 18 | textarea = forms.CharField(widget=forms.Textarea()) 19 | checkbox = forms.BooleanField() 20 | checkboxes = forms.MultipleChoiceField( 21 | choices=COLOR_CHOICES, 22 | widget=forms.CheckboxSelectMultiple() 23 | ) 24 | radios = forms.ChoiceField( 25 | choices=COLOR_CHOICES, 26 | widget=forms.RadioSelect() 27 | ) 28 | file = forms.FileField(required=True) 29 | -------------------------------------------------------------------------------- /showcase/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.6 on 2018-02-26 16:53 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Task', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=128)), 21 | ('done', models.BooleanField(default=False)), 22 | ], 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /showcase/migrations/0002_auto_20180226_1645.py: -------------------------------------------------------------------------------- 1 | import random 2 | from django.db import migrations 3 | 4 | 5 | def create_tasks(apps, schema_editor): 6 | Task = apps.get_model('showcase', 'Task') 7 | for number in range(1, 51): 8 | task = Task( 9 | name='Boring task name #{}'.format(number), 10 | done=random.randint(0, 1) 11 | ) 12 | task.save() 13 | 14 | 15 | def delete_tasks(apps, schema_editor): 16 | Task = apps.get_model('showcase', 'Task') 17 | Task.objects.all().delete() 18 | 19 | 20 | class Migration(migrations.Migration): 21 | 22 | dependencies = [ 23 | ('showcase', '0001_initial'), 24 | ] 25 | 26 | operations = [ 27 | migrations.RunPython(create_tasks, delete_tasks), 28 | ] 29 | -------------------------------------------------------------------------------- /showcase/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/showcase/migrations/__init__.py -------------------------------------------------------------------------------- /showcase/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Task(models.Model): 5 | name = models.CharField(max_length=128) 6 | done = models.BooleanField(default=False) 7 | 8 | -------------------------------------------------------------------------------- /showcase/templates/showcase/form.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load bulma_tags %} 3 | 4 | {% block content %} 5 |
6 | {% csrf_token %} 7 | {{ form|bulma }} 8 | 9 |
10 | {% endblock %} -------------------------------------------------------------------------------- /showcase/templates/showcase/paginated_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% for task in object_list %} 13 | 14 | 15 | 20 | {% endfor %} 21 | 22 |
TaskDone?
{{ task.name }} 16 | 17 | 18 | 19 |
23 | {% include 'pagination.html' %} 24 | {% endblock %} -------------------------------------------------------------------------------- /showcase/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | app_name = 'showcase' 6 | urlpatterns = [ 7 | url(r'^list/$', views.PaginatedList.as_view(), name='paginated_list'), 8 | url(r'^form/$', views.FormExampleView.as_view(), name='form'), 9 | ] 10 | -------------------------------------------------------------------------------- /showcase/views.py: -------------------------------------------------------------------------------- 1 | from django.views.generic import ListView, FormView 2 | 3 | from .forms import FormExample 4 | from .models import Task 5 | 6 | 7 | class PaginatedList(ListView): 8 | template_name = 'showcase/paginated_list.html' 9 | model = Task 10 | paginate_by = 20 11 | 12 | 13 | class FormExampleView(FormView): 14 | template_name = 'showcase/form.html' 15 | form_class = FormExample 16 | -------------------------------------------------------------------------------- /test_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timonweb/django-bulma/15836cfd5be0d63d9be77ddf378d3253a872498d/test_project/__init__.py -------------------------------------------------------------------------------- /test_project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | from django.conf import settings 10 | settings.DEBUG = True 11 | 12 | execute_from_command_line(sys.argv) -------------------------------------------------------------------------------- /test_project/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | ALLOWED_HOSTS = ['*'] 4 | 5 | BASE_DIR = os.path.dirname(__file__) 6 | 7 | SECRET_KEY = "007" 8 | 9 | INSTALLED_APPS = [ 10 | # Default Django apps 11 | "django.contrib.admin", 12 | "django.contrib.auth", 13 | "django.contrib.contenttypes", 14 | "django.contrib.sessions", 15 | "django.contrib.messages", 16 | "django.contrib.staticfiles", 17 | 18 | "bulma", 19 | "showcase" 20 | ] 21 | 22 | ROOT_URLCONF = "test_project.urls" 23 | 24 | DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}} 25 | 26 | MIDDLEWARE = ( 27 | "django.contrib.sessions.middleware.SessionMiddleware", 28 | "django.contrib.auth.middleware.AuthenticationMiddleware", # required for django.contrib.admin 29 | "django.contrib.messages.middleware.MessageMiddleware", # required for django.contrib.admin 30 | ) 31 | 32 | STATIC_URL = "/static/" 33 | 34 | STATICFILES_DIRS = [ 35 | os.path.join(BASE_DIR, 'static') 36 | ] 37 | 38 | TEMPLATES = [ 39 | { 40 | "BACKEND": "django.template.backends.django.DjangoTemplates", 41 | 'DIRS': [ 42 | os.path.join(BASE_DIR, 'templates') 43 | ], 44 | "APP_DIRS": True, 45 | "OPTIONS": { 46 | "context_processors": [ 47 | "django.contrib.auth.context_processors.auth", 48 | "django.template.context_processors.debug", 49 | "django.template.context_processors.i18n", 50 | "django.template.context_processors.media", 51 | "django.template.context_processors.static", 52 | "django.template.context_processors.tz", 53 | "django.contrib.messages.context_processors.messages", 54 | ] 55 | }, 56 | } 57 | ] 58 | -------------------------------------------------------------------------------- /test_project/templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'bulma/base.html' %} -------------------------------------------------------------------------------- /test_project/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |

7 | Hello World 8 |

9 |

10 | My first website with Django-Bulma! 11 |

12 |
13 |

Demo pages:

14 | 18 |
19 |
20 |
21 | {% endblock %} -------------------------------------------------------------------------------- /test_project/urls.py: -------------------------------------------------------------------------------- 1 | """example URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | from django.views.generic import TemplateView 19 | from django.contrib.auth.views import LoginView 20 | 21 | urlpatterns = [ 22 | url(r'^$', TemplateView.as_view(template_name='home.html')), 23 | url(r'^login/$', LoginView.as_view(), name='login'), 24 | url(r'^admin/', admin.site.urls), 25 | url(r'^showcase/', include('showcase.urls', namespace='showcase')), 26 | ] 27 | -------------------------------------------------------------------------------- /test_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for example project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | DJANGO_SETTINGS_MODULE = test_project.settings 3 | python_files = tests.py test_*.py *_tests.py 4 | ignore = 'node_modules' 5 | 6 | [tox] 7 | isolated_build = True 8 | envlist = django{22,30,32} 9 | 10 | [tox:.package] 11 | # note tox will use the same python version as under what tox is installed to package 12 | # so unless this is python 3 you can require a given python version for the packaging 13 | # environment via the basepython key 14 | basepython = python3 15 | 16 | [testenv] 17 | commands = pytest {posargs} 18 | deps = 19 | django22: Django>=2.2.9,<3.0 20 | django30: Django>=3.0,<3.1 21 | django32: Django>=3.2,<3.3 22 | setenv = 23 | DJANGO_SETTINGS_MODULE = test_project.settings 24 | PYTHONPATH = {toxinidir} 25 | --------------------------------------------------------------------------------