Release 1
This commit is contained in:
commit
9ac6e9930e
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.idea
|
||||
__pycache__/
|
||||
venv
|
||||
db/labertasche.db-shm
|
||||
db/labertasche.db-wal
|
||||
output
|
||||
/output/
|
||||
*.sql
|
22
LICENSE.md
Normal file
22
LICENSE.md
Normal file
@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Domeniko Gentner <code@tuxstash.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
20
Pipfile
Normal file
20
Pipfile
Normal file
@ -0,0 +1,20 @@
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
flask = "*"
|
||||
pyyaml = "*"
|
||||
flask-sqlalchemy = "*"
|
||||
flask-cors = "*"
|
||||
antispam = "*"
|
||||
flask-login = "*"
|
||||
sqlalchemy = "*"
|
||||
requests = "*"
|
||||
py3-validate-email = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
251
Pipfile.lock
generated
Normal file
251
Pipfile.lock
generated
Normal file
@ -0,0 +1,251 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "57134ef6f8a30aa46c1ab6263e62e14edbb27d6df2911fc6b2140dde8c49d27c"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.8"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"antispam": {
|
||||
"hashes": [
|
||||
"sha256:e188b424ea9b76c408a592a5ff60eb1280f45f26b404db4d5e96123f485de39b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.0.10"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd",
|
||||
"sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"
|
||||
],
|
||||
"version": "==2020.11.8"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"dnspython": {
|
||||
"hashes": [
|
||||
"sha256:044af09374469c3a39eeea1a146e8cac27daec951f1f1f157b1962fc7cb9d1b7",
|
||||
"sha256:40bb3c24b9d4ec12500f0124288a65df232a3aa749bb0c39734b782873a2544d"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"filelock": {
|
||||
"hashes": [
|
||||
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
|
||||
"sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
|
||||
],
|
||||
"version": "==3.0.12"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
|
||||
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.2"
|
||||
},
|
||||
"flask-cors": {
|
||||
"hashes": [
|
||||
"sha256:6bcfc100288c5d1bcb1dbb854babd59beee622ffd321e444b05f24d6d58466b8",
|
||||
"sha256:cee4480aaee421ed029eaa788f4049e3e26d15b5affb6a880dade6bafad38324"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.9"
|
||||
},
|
||||
"flask-login": {
|
||||
"hashes": [
|
||||
"sha256:6d33aef15b5bcead780acc339464aae8a6e28f13c90d8b1cf9de8b549d1c0b4b",
|
||||
"sha256:7451b5001e17837ba58945aead261ba425fdf7b4f0448777e597ddab39f4fba0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"flask-sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:05b31d2034dd3f2a685cbbae4cfc4ed906b2a733cff7964ada450fd5e462b84e",
|
||||
"sha256:bfc7150eaf809b1c283879302f04c42791136060c6eeb12c0c6674fb1291fae5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.4.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
|
||||
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
|
||||
],
|
||||
"version": "==2.11.2"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"py3-validate-email": {
|
||||
"hashes": [
|
||||
"sha256:3bbb264b49c0ae09afdb2738956f00b0e8dd7e079e2d079b2e9b6688de474d28"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.10"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97",
|
||||
"sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76",
|
||||
"sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2",
|
||||
"sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648",
|
||||
"sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf",
|
||||
"sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f",
|
||||
"sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2",
|
||||
"sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee",
|
||||
"sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d",
|
||||
"sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c",
|
||||
"sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.3.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8",
|
||||
"sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.25.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
|
||||
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
|
||||
],
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:009e8388d4d551a2107632921320886650b46332f61dc935e70c8bcf37d8e0d6",
|
||||
"sha256:0157c269701d88f5faf1fa0e4560e4d814f210c01a5b55df3cab95e9346a8bcc",
|
||||
"sha256:0a92745bb1ebbcb3985ed7bda379b94627f0edbc6c82e9e4bac4fb5647ae609a",
|
||||
"sha256:0cca1844ba870e81c03633a99aa3dc62256fb96323431a5dec7d4e503c26372d",
|
||||
"sha256:166917a729b9226decff29416f212c516227c2eb8a9c9f920d69ced24e30109f",
|
||||
"sha256:1f5f369202912be72fdf9a8f25067a5ece31a2b38507bb869306f173336348da",
|
||||
"sha256:2909dffe5c9a615b7e6c92d1ac2d31e3026dc436440a4f750f4749d114d88ceb",
|
||||
"sha256:2b5dafed97f778e9901b79cc01b88d39c605e0545b4541f2551a2fd785adc15b",
|
||||
"sha256:2e9bd5b23bba8ae8ce4219c9333974ff5e103c857d9ff0e4b73dc4cb244c7d86",
|
||||
"sha256:3aa6d45e149a16aa1f0c46816397e12313d5e37f22205c26e06975e150ffcf2a",
|
||||
"sha256:4bdbdb8ca577c6c366d15791747c1de6ab14529115a2eb52774240c412a7b403",
|
||||
"sha256:53fd857c6c8ffc0aa6a5a3a2619f6a74247e42ec9e46b836a8ffa4abe7aab327",
|
||||
"sha256:5cdfe54c1e37279dc70d92815464b77cd8ee30725adc9350f06074f91dbfeed2",
|
||||
"sha256:5d92c18458a4aa27497a986038d5d797b5279268a2de303cd00910658e8d149c",
|
||||
"sha256:632b32183c0cb0053194a4085c304bc2320e5299f77e3024556fa2aa395c2a8b",
|
||||
"sha256:7c735c7a6db8ee9554a3935e741cf288f7dcbe8706320251eb38c412e6a4281d",
|
||||
"sha256:7cd40cb4bc50d9e87b3540b23df6e6b24821ba7e1f305c1492b0806c33dbdbec",
|
||||
"sha256:84f0ac4a09971536b38cc5d515d6add7926a7e13baa25135a1dbb6afa351a376",
|
||||
"sha256:8dcbf377529a9af167cbfc5b8acec0fadd7c2357fc282a1494c222d3abfc9629",
|
||||
"sha256:950f0e17ffba7a7ceb0dd056567bc5ade22a11a75920b0e8298865dc28c0eff6",
|
||||
"sha256:9e379674728f43a0cd95c423ac0e95262500f9bfd81d33b999daa8ea1756d162",
|
||||
"sha256:b15002b9788ffe84e42baffc334739d3b68008a973d65fad0a410ca5d0531980",
|
||||
"sha256:b6f036ecc017ec2e2cc2a40615b41850dc7aaaea6a932628c0afc73ab98ba3fb",
|
||||
"sha256:bad73f9888d30f9e1d57ac8829f8a12091bdee4949b91db279569774a866a18e",
|
||||
"sha256:bbc58fca72ce45a64bb02b87f73df58e29848b693869e58bd890b2ddbb42d83b",
|
||||
"sha256:bca4d367a725694dae3dfdc86cf1d1622b9f414e70bd19651f5ac4fb3aa96d61",
|
||||
"sha256:be41d5de7a8e241864189b7530ca4aaf56a5204332caa70555c2d96379e18079",
|
||||
"sha256:bf53d8dddfc3e53a5bda65f7f4aa40fae306843641e3e8e701c18a5609471edf",
|
||||
"sha256:c092fe282de83d48e64d306b4bce03114859cdbfe19bf8a978a78a0d44ddadb1",
|
||||
"sha256:c3ab23ee9674336654bf9cac30eb75ac6acb9150dc4b1391bec533a7a4126471",
|
||||
"sha256:ce64a44c867d128ab8e675f587aae7f61bd2db836a3c4ba522d884cd7c298a77",
|
||||
"sha256:d05cef4a164b44ffda58200efcb22355350979e000828479971ebca49b82ddb1",
|
||||
"sha256:d2f25c7f410338d31666d7ddedfa67570900e248b940d186b48461bd4e5569a1",
|
||||
"sha256:d3b709d64b5cf064972b3763b47139e4a0dc4ae28a36437757f7663f67b99710",
|
||||
"sha256:e32e3455db14602b6117f0f422f46bc297a3853ae2c322ecd1e2c4c04daf6ed5",
|
||||
"sha256:ed53209b5f0f383acb49a927179fa51a6e2259878e164273ebc6815f3a752465",
|
||||
"sha256:f605f348f4e6a2ba00acb3399c71d213b92f27f2383fc4abebf7a37368c12142",
|
||||
"sha256:fcdb3755a7c355bc29df1b5e6fb8226d5c8b90551d202d69d0076a8a5649d68b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.20"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08",
|
||||
"sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"
|
||||
],
|
||||
"version": "==1.26.2"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
|
||||
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
|
||||
],
|
||||
"version": "==1.0.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
130
README.md
Normal file
130
README.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Labertasche
|
||||
|
||||
A comment system for Hugo, written in Python (and Javascript).
|
||||
|
||||
## Feature Set
|
||||
|
||||
* Written in Python, utilizing Flask
|
||||
* Robust Database handling by utilizing SQLAlchemy, which supports all big database engines
|
||||
* flask-cors for robust security
|
||||
* Uses Javascript to send comment via POST to the comment server
|
||||
* Has callbacks for implementing your own notifications during the posting process.
|
||||
* No IP being logged
|
||||
* Email confirmation
|
||||
* EMail Blocklist
|
||||
* Only outputs JSON, so templates can be done independently, enhancing customization. Using the comments via a partial
|
||||
template in Hugo is the recommended way. See below for integration code.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* A public webserver capable of running Apache/NGINX and/or gunicorn. This server does not need to be the same as the
|
||||
server running the site, but it must have access to your CI/CD chain. Same server is of course easier to implement.
|
||||
|
||||
|
||||
## How does it work?
|
||||
|
||||
A picture often says more than a thousand words:
|
||||
|
||||

|
||||
|
||||
In some words, the user sends the comment from your site to the comment system, the comment system does the validation
|
||||
and confirmation. Then, a json is put into the data directory from where you can load it via Hugo and generate your
|
||||
template.
|
||||
|
||||
## Setup
|
||||
|
||||
Run `ssh://git@git.tuxstash.de:1235/gothseidank/labertasche.git` in the directory where you wish to host the comment
|
||||
system. For example, `/var/www/html`, I also recommend making use of `/srv/` or `/opt/`. It depends on you.
|
||||
|
||||
When everything is downloaded, create the directory `/etc/labertasche`. In this directory, we need 2 files:
|
||||
|
||||
* labertasche.yaml - you can find an example in the root directory.
|
||||
* mail_credentials.json - you can find an example in the root directory.
|
||||
|
||||
Copy these files from the root directory of this app to the folder `/etc/labertasche`. Make sure to set ownership for
|
||||
your user that runs your server later. I always do `chmown user:www-data`, so Apache has only group rights and enable read-only
|
||||
for the Apache user.
|
||||
|
||||
Make sure to read the config and replace the values as needed. The mail configuration should need no explanation,
|
||||
`labertasche.yaml` has comments. Feel free to bug about more documentation regarding this. Pay special attention to
|
||||
secrets and passwords.
|
||||
|
||||
Now, for the server there are several options. I personally always host flask apps with Apache and mod_wsgi.
|
||||
The config looks like this:
|
||||
|
||||
* [Apache](docs/apache-config.md)
|
||||
|
||||
Other options:
|
||||
|
||||
* [gunicorn](https://gunicorn.org/https://gunicorn.org/) + Apache/Nginx with Proxy Pass
|
||||
|
||||
Once you can see the administrative page, you can start integrating it into Hugo.
|
||||
|
||||
## Integrating it into Hugo
|
||||
|
||||
### Javascript
|
||||
|
||||
In the project folder is a small javascript file. You will need to load this into Hugo, I suggest using Hugo's asset
|
||||
pipeline to integrate it into your site. One thing is important to know: this script only does the bare bones post request
|
||||
to your comment backend. Anything else must be done by yourself, but don't worry: The function is making use of a callback,
|
||||
so you can control what happens during the various stages.
|
||||
|
||||
TODO: Example using the javascript properly
|
||||
|
||||
### Hugo templates
|
||||
|
||||
Remember the `labertasche.yaml` file? It asked you where the data folder of Hugo is. What this program does, is to place
|
||||
various json files into that folder, in folders that describe your sections. So, for each category/section of your blog
|
||||
where comments can be placed, one folder will be made. And for each page within that section it generates a json file.
|
||||
|
||||
Now create a new partial called "comments.html" (or something else). Within that template the following structure is needed:
|
||||
|
||||
```
|
||||
{{ $location := .Scratch.Get "location" }}
|
||||
{{ if (fileExists $location ) }}
|
||||
{{ $dataJ := getJSON $location }}
|
||||
{{ range $dataJ.comments }}
|
||||
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
This loads the json depending on the rel url and walks the list of comments. You can then use the following variables to
|
||||
access the per-comment data:
|
||||
|
||||
* .content => The body of the message the user has sent
|
||||
* .email => The mail the person used to send the mail
|
||||
* .created_on => The date and time the comment was posted
|
||||
* .comment_id => The comment id, great for making anchors
|
||||
* .gravatar => The md5 hash of the mail for gravatar, if caching is on, prepend e.g. `/images`, otherwise use the gravatar url to integrate it.
|
||||
|
||||
You can style around them as needed. You have free reign.
|
||||
|
||||
Of course you will also need a few inputs and a button that submits the data.
|
||||
Here is a base skeleton to start out:
|
||||
|
||||
```
|
||||
<div>
|
||||
<input type="text" maxlength=100 placeholder="Enter Email" id="labertasche-mail">
|
||||
<textarea cols="10" rows="10" id="labertasche-text"></textarea>
|
||||
<input type="button" onclick="labertasche_post_comment(this, labertasche_callback);">
|
||||
</div>
|
||||
```
|
||||
|
||||
Please take note of the `id` on each element, these are mandatory, as well as the function call for the `onclick` event.
|
||||
Again, style as needed and add more Javascript to your gusto.
|
||||
|
||||
|
||||
Inside your template `single.html`, or wherever you want to place comments, you qwill also need this:
|
||||
|
||||
```
|
||||
{{ $file := replaceRE "^(.*)[\\/]$" "data$1.json" .Page.RelPermalink }}
|
||||
{{ .Scratch.Set "location" $file }}
|
||||
{{ partial "partials/comments" . }}
|
||||
```
|
||||
|
||||
After that and configuring labertasche correctly, the json files should be placed in your data folder and all you got
|
||||
to do after that, is to rebuild Hugo and the new comment should appear.
|
||||
|
||||
|
35
docs/apache-config.md
Normal file
35
docs/apache-config.md
Normal file
@ -0,0 +1,35 @@
|
||||
This is an example server config for Apache Webserver with mod_wsgi.
|
||||
If you wish to use pipenv, then please take also a look at the
|
||||
[WSGIPythonHome](https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIPythonHome.html)
|
||||
directive.
|
||||
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin server@example.com
|
||||
ServerName comments.example.com
|
||||
Redirect permanent / https://comments.example.com
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerAdmin server@example.com
|
||||
ServerName comments.example.com
|
||||
|
||||
WSGIDaemonProcess laberflask user=user group=group threads=2
|
||||
WSGIScriptAlias / /var/www/html/labertasche/server.wsgi
|
||||
|
||||
SSLCertificateFile /etc/letsencrypt/live/comments.example.com/fullchain.pem
|
||||
SSLCertificateKeyFile /etc/letsencrypt/live/comments.example.com/privkey.pem
|
||||
Include /etc/letsencrypt/options-ssl-apache.conf
|
||||
|
||||
<Directory "/var/www/html/labertasche">
|
||||
WSGIProcessGroup laberflask
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Options -Indexes
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
ErrorLog ${APACHE_LOG_DIR}/laberflask.error.log
|
||||
CustomLog /dev/null common
|
||||
</VirtualHost>
|
||||
```
|
1
docs/flow-chart.drawio
Normal file
1
docs/flow-chart.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2020-11-15T15:20:17.771Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36" etag="1QcwDtM_10p-pEkd1fcO" version="13.9.8" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7Vttc9o4EP41fMyNLdnGfIVAm14uyZX00ny6kW2BXYTFWSJAf/1JtmxeRBsnBQSezjCMtJZsa3ef1b7ILdibLj9kaBb/RSNMWsCKli143QLAdgBoyZ8VrQpK21OEcZZEatCaMEy+Y0W0FHWeRJhtDeSUEp7MtokhTVMc8i0ayjK62B42omT7qTM0xhphGCKiU5+SiMcF1QftNf0jTsZx+WTb6xRXpqgcrFbCYhTRxQYJ9luwl1HKi9Z02cNEMq/ky9PN6oncTrwPn/5m/6Ev3T8f7/65Km42eMuUagkZTvm7b02GV3Nr6PUG7FO3C1CPsvbkylFL46uSXzgS7FNdmvGYjmmKSH9N7WZ0nkZY3tUSvfWYW0pngmgL4jfM+UrpAppzKkgxnxJ1FS8T/lVNl+1n2f7DVb3r5cal61XZSXm2+lreQHY2ZsnuelreK+cV65OL2lGHV3ipxjE6z0L8EwYq3eAoG2P+k3GgUhiBNEynWLykmJdhgnjysv1ySKn8uBq3FqtoKMm+QcqeUSlXkn3euPKKlDcE+7wl1/OWsmtSyuolXxCZqycNCGITQRri7AVnmhKsRSylsogTjoczlDNiITaDbXGOEkJ6lNAsnwuxHbm4LeiMZ3SCN650vDZEXiUU8WCOl+8Qi85GdRfgq5WqHclR3cXavNueosUbpr2cdnDGA43xn7FYNsOC+JDR5aopnHfPjPG2rXH2t2F7k2Fzaxo229qvGKexbK4GMHGbkE6ngglMNFO8aAGPiAV0A2HmvLFsPdwPHw8KvAhhfxTuA54X+jgYndDkVTAzBz2jnqPdeofnaLXOynO06zoVNjSJPdu9lBDhfARm1Nm3dT8wYXJ9MzRtwYFuEmM6DebszeZwNBqBcK85jLzAc4/ph0CwbQ4rM7dhDv1TWkMImu6I5L0HnCWCYTg7FeJATcQBzyji9ADgjh4MZ8Lb9yNnH858EEDvmDizzw5nF+PwHx0asO5m5BuFBtSg8YzZ4fYgP8T796DAdx3XOiI23HPDRpnRPn9sXNYe5F3GHuRpQGPidcUs9m/u+cmyi/zLxGUtVk5SJgDSkkWPJH9Umg8OCA0nJGFcB+yW3lwMaHcdR88yHUcDoztaI+Jovy5AjeawgNkQ4T2CPrNSW21B2x2jltjXLHEefyepfBohdCEECqzcrDYjHN91hZw9hYHTukKw6a7Q0bHWqYs1s15PR8NaMyJv6J0bpMymgRsAKVA3fQwco36Knj5uSMTu7Z4bMI4pv+mYMhKxA6cu0IzuXeVrbgAt9w51qP1CrG1wC/Occ4u14eWcgxOdk8OmbqILGj3l5hgV4psSJnuEeK5JlNrCd8w6J3qW8+Zu2P/8KGg3d4/3embzuqupC4vRTDbDFUmEVmTwdasaFPpzG1QEFE7GuVbdz7m4DVZ0ViiQ7eqm2OC5Pbs8xFGd4ddNcWePJa7qf4dH8e8I/RcRC+uGE9BoARDq4UR/OaN5sSGvMXycj2nxYGB9Y1QmyZKR+EupHFLUMFB1fuWgvpG583zuTnjf3lM8PLFvpJ+xHOA8USlNHU6jprB+JwjsGD9J6ZgtDDTBFNYtDDg/UI0TmUK9MKAMHqEoKrC2KvjCE0SaArhdW9cBxhFna4LozhMiBfCEAyb4KpUpFvwex6LVEwMGvZuDysPkRxw78rAt499xOEaTy00ogjt1c17QaBHc0XNeX5j8Mk1+/jtKsinLm/mHHaU5LI6kHBB7oxH2flApbXcC66jnT+zT+X2iu/42Ob+28YU37P8P</diagram></mxfile>
|
BIN
docs/flow-chart.png
Normal file
BIN
docs/flow-chart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
84
js/labertasche.js
Normal file
84
js/labertasche.js
Normal file
@ -0,0 +1,84 @@
|
||||
//**********************************************************************************
|
||||
// * _author : Domeniko Gentner
|
||||
// * _mail : code@tuxstash.de
|
||||
// * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
// * _license : This project is under MIT License
|
||||
// *********************************************************************************/
|
||||
|
||||
/*
|
||||
Callback example.
|
||||
Possible messages:
|
||||
|
||||
post-min-length
|
||||
post-max-length
|
||||
post-invalid-json
|
||||
post-duplicate
|
||||
post-internal-server-error
|
||||
post-success
|
||||
post-before-fetch
|
||||
|
||||
function labertasche_callback(state)
|
||||
{
|
||||
if (state === "post-before-fetch"){
|
||||
|
||||
}
|
||||
if (state === "post-min-length"){
|
||||
|
||||
}
|
||||
if (state === "post-success"){
|
||||
|
||||
}
|
||||
if (state === "post-fetch-exception" || state === "post-internal-server-error"){
|
||||
|
||||
}
|
||||
if (state === "post-invalid-email"){
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
function labertasche_post_comment(btn, callback)
|
||||
{
|
||||
let remote = document.getElementById('labertasche-comment-section').dataset.remote;
|
||||
let comment = document.getElementById('labertasche-text').value;
|
||||
let mail = document.getElementById('labertasche-mail').value;
|
||||
|
||||
if (mail.length <= 0 || comment.length < 40){
|
||||
callback('post-min-length');
|
||||
if(btn) {
|
||||
btn.preventDefault();
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
callback('post-before-fetch');
|
||||
fetch(remote,
|
||||
{
|
||||
mode:"cors",
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin':'*',
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: "POST",
|
||||
// use real location
|
||||
body: JSON.stringify({ "email": mail,
|
||||
"content": comment,
|
||||
"location": window.location.pathname,
|
||||
"replied_to": null // TODO: future feature: replies?
|
||||
})
|
||||
})
|
||||
.then(async function(response){
|
||||
let result = await response.json();
|
||||
callback(result['status']);
|
||||
})
|
||||
.catch(function(exc){
|
||||
console.log(exc);
|
||||
callback('post-fetch-exception');
|
||||
})
|
||||
|
||||
// Don't reload the page
|
||||
if (btn) {
|
||||
btn.preventDefault();
|
||||
}
|
||||
}
|
44
labertasche.yaml
Normal file
44
labertasche.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
|
||||
system:
|
||||
web_url: "http://dev.localhost:1314/" # Url where the comment system is served
|
||||
blog_url: "http://dev.localhost:1313/" # Url of your website
|
||||
cookie-domain: "dev.localhost" # Url where the comment system is served
|
||||
database_uri: "sqlite:///db/labertasche.db" # Database URI. See documentation. Default is sqlite.
|
||||
secret: "6Gxvb52bIJCm2vfDsmWKzShKp1omrzVG" # CHANGE ME! THIS IS IMPORTANT!
|
||||
output: "../../web/tuxstash.de/data/" # Base path for the output json
|
||||
debug: false # Leave this as is, this is for development.
|
||||
send_otp_to_publish: true # Disables confirmation w/ OTP via mail
|
||||
|
||||
gravatar:
|
||||
cache: true # Enable caching of gravatar images
|
||||
static_dir: "../../web/tuxstash.de/static/images/gravatar/" # Where to store cached images
|
||||
size: 256 # only applies if images are cached,
|
||||
# otherwise use ?s=size at the end of the gravatar url
|
||||
|
||||
dashboard:
|
||||
username: "admin" # CHANGE ME!
|
||||
password: "admin" # CHANGE ME!
|
||||
|
||||
addons:
|
||||
smileys: true # Enable smiley replacements, set to false if unwanted
|
||||
|
||||
# https://www.w3schools.com/charsets/ref_emoji_smileys.asp
|
||||
smileys:
|
||||
":)": "😀"
|
||||
":d": "😁"
|
||||
":D": "😁"
|
||||
";)": "😉"
|
||||
":p": "😋"
|
||||
":P": "😋"
|
||||
":8": "😎"
|
||||
"(:": "🙃"
|
||||
"$)": "🤑"
|
||||
":o": "😲"
|
||||
":O": "😲"
|
||||
|
26
labertasche/__init__.py
Normal file
26
labertasche/__init__.py
Normal file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
|
||||
from labertasche import (
|
||||
models,
|
||||
database,
|
||||
blueprints,
|
||||
helper,
|
||||
mail,
|
||||
settings
|
||||
)
|
||||
|
||||
_all_ = [
|
||||
models,
|
||||
database,
|
||||
blueprints,
|
||||
helper,
|
||||
mail,
|
||||
settings
|
||||
]
|
12
labertasche/blueprints/__init__.py
Normal file
12
labertasche/blueprints/__init__.py
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from .bp_comments import bp_comments
|
||||
from .bp_login import bp_login
|
||||
from .bp_dashboard import bp_dashboard
|
||||
|
189
labertasche/blueprints/bp_comments.py
Normal file
189
labertasche/blueprints/bp_comments.py
Normal file
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
import re
|
||||
from sys import stderr
|
||||
from antispam import is_spam as spam, score
|
||||
from flask import Blueprint, jsonify, request, make_response, redirect
|
||||
from flask_cors import cross_origin
|
||||
from sqlalchemy import exc
|
||||
from labertasche.database import labertasche_db as db
|
||||
from labertasche.helper import is_valid_json, default_timestamp, check_gravatar, export_location
|
||||
from labertasche.mail import mail
|
||||
from labertasche.models import TComments, TLocation, TEmail
|
||||
from labertasche.settings import Settings
|
||||
from secrets import compare_digest
|
||||
|
||||
|
||||
# Blueprint
|
||||
bp_comments = Blueprint("bp_comments", __name__, url_prefix='/comments')
|
||||
|
||||
|
||||
# Route for adding new comments
|
||||
@bp_comments.route("/new", methods=['POST'])
|
||||
@cross_origin()
|
||||
def check_and_insert_new_comment():
|
||||
if request.method == 'POST':
|
||||
settings = Settings()
|
||||
smileys = settings.smileys
|
||||
addons = settings.addons
|
||||
sender = mail()
|
||||
|
||||
# Check length of content and abort if too long or too short
|
||||
if request.content_length > 2048:
|
||||
return make_response(jsonify(status="post-max-length"), 400)
|
||||
if request.content_length <= 0:
|
||||
return make_response(jsonify(status="post-min-length"), 400)
|
||||
|
||||
# get json from request
|
||||
new_comment = request.json
|
||||
|
||||
# save and sanitize location, nice try, bitch
|
||||
location = new_comment['location'].strip().replace('.', '')
|
||||
|
||||
# Validate json and check length again
|
||||
if not is_valid_json(new_comment) or \
|
||||
len(new_comment['content']) < 40 or \
|
||||
len(new_comment['email']) < 5:
|
||||
print("too short", file=stderr)
|
||||
return make_response(jsonify(status='post-invalid-json'), 400)
|
||||
|
||||
# Strip any HTML from message body
|
||||
tags = re.compile('<.*?>')
|
||||
special = re.compile('[&].*[;]')
|
||||
content = re.sub(tags, '', new_comment['content']).strip()
|
||||
content = re.sub(special, '', content).strip()
|
||||
|
||||
# Convert smileys
|
||||
if addons['smileys']:
|
||||
for key, value in smileys.items():
|
||||
content = content.replace(key, value)
|
||||
|
||||
# Update values
|
||||
new_comment.update({"content": content})
|
||||
new_comment.update({"email": new_comment['email'].strip()})
|
||||
new_comment.update({"location": location})
|
||||
new_comment.update({"replied_to": None}) # Not (yet?) implemented
|
||||
|
||||
# Check mail
|
||||
if not sender.validate(new_comment['email']):
|
||||
return make_response(jsonify(status='post-invalid-email'), 400)
|
||||
|
||||
# check for spam
|
||||
is_spam = spam(new_comment['content'])
|
||||
has_score = score(new_comment['content'])
|
||||
|
||||
# Insert mail into spam if detected, allow if listed as such
|
||||
email = db.session.query(TEmail).filter(TEmail.email == new_comment['email']).first()
|
||||
if not email:
|
||||
if is_spam:
|
||||
entry = {
|
||||
"email": new_comment['email'],
|
||||
"is_blocked": True,
|
||||
"is_allowed": False
|
||||
}
|
||||
db.session.add(TEmail(**entry))
|
||||
if email:
|
||||
if not email.is_allowed:
|
||||
is_spam = True
|
||||
if email.is_allowed:
|
||||
is_spam = False
|
||||
|
||||
# Look for location
|
||||
loc_query = db.session.query(TLocation)\
|
||||
.filter(TLocation.location == new_comment['location'])
|
||||
|
||||
if loc_query.first():
|
||||
# Set existing location id
|
||||
new_comment.update({'location_id': loc_query.first().id_location})
|
||||
# TComments does not have this field
|
||||
new_comment.pop("location")
|
||||
else:
|
||||
# Insert new location
|
||||
loc_table = {
|
||||
'location': new_comment['location']
|
||||
}
|
||||
new_loc = TLocation(**loc_table)
|
||||
db.session.add(new_loc)
|
||||
db.session.flush()
|
||||
db.session.refresh(new_loc)
|
||||
new_comment.update({'location_id': new_loc.id_location})
|
||||
|
||||
# TComments does not have this field
|
||||
new_comment.pop("location")
|
||||
|
||||
# insert comment
|
||||
try:
|
||||
new_comment.update({"is_published": False})
|
||||
new_comment.update({"created_on": default_timestamp()})
|
||||
new_comment.update({"is_spam": is_spam})
|
||||
new_comment.update({"spam_score": has_score})
|
||||
new_comment.update({"gravatar": check_gravatar(new_comment['email'])})
|
||||
t_comment = TComments(**new_comment)
|
||||
db.session.add(t_comment)
|
||||
db.session.commit()
|
||||
db.session.flush()
|
||||
db.session.refresh(t_comment)
|
||||
|
||||
# Send confirmation link and store returned value
|
||||
hashes = sender.send_confirmation_link(new_comment['email'])
|
||||
setattr(t_comment, "confirmation", hashes[0])
|
||||
setattr(t_comment, "deletion", hashes[1])
|
||||
db.session.commit()
|
||||
|
||||
except exc.IntegrityError as e:
|
||||
# Comment body exists, because content is unique
|
||||
print(f"Duplicate from {request.environ['REMOTE_ADDR']}, error is:\n{e}", file=stderr)
|
||||
return make_response(jsonify(status="post-duplicate"), 400)
|
||||
|
||||
except Exception as e: # must be at bottom
|
||||
# mail(f"check_and_insert_new_comment has thrown an error: {e}", )
|
||||
print(e, file=stderr)
|
||||
return make_response(jsonify(status="post-internal-server-error"), 400)
|
||||
|
||||
export_location(location)
|
||||
return make_response(jsonify(status="post-success", comment_id=t_comment.comments_id), 200)
|
||||
|
||||
|
||||
# Route for confirming comments
|
||||
@bp_comments.route("/confirm/<email_hash>", methods=['GET'])
|
||||
@cross_origin()
|
||||
def check_confirmation_link(email_hash):
|
||||
settings = Settings()
|
||||
comment = db.session.query(TComments).filter(TComments.confirmation == email_hash).first()
|
||||
if comment:
|
||||
location = db.session.query(TLocation).filter(TLocation.id_location == comment.location_id).first()
|
||||
if compare_digest(comment.confirmation, email_hash):
|
||||
comment.confirmation = None
|
||||
if not comment.is_spam:
|
||||
setattr(comment, "is_published", True)
|
||||
db.session.commit()
|
||||
url = f"{settings.system['blog_url']}{location.location}#comment_{comment.comments_id}"
|
||||
export_location(location.location)
|
||||
return redirect(url)
|
||||
|
||||
return redirect(f"{settings.system['blog_url']}?cnf=true")
|
||||
|
||||
|
||||
# Route for deleting comments
|
||||
@bp_comments.route("/delete/<email_hash>", methods=['GET'])
|
||||
@cross_origin()
|
||||
def check_deletion_link(email_hash):
|
||||
settings = Settings()
|
||||
query = db.session.query(TComments).filter(TComments.deletion == email_hash)
|
||||
comment = query.first()
|
||||
if comment:
|
||||
location = db.session.query(TLocation).filter(TLocation.id_location == comment.location_id).first()
|
||||
if compare_digest(comment.deletion, email_hash):
|
||||
query.delete()
|
||||
db.session.commit()
|
||||
url = f"{settings.system['blog_url']}?deleted=true"
|
||||
export_location(location.location)
|
||||
return redirect(url)
|
||||
|
||||
return redirect(f"{settings.system['blog_url']}?cnf=true")
|
201
labertasche/blueprints/bp_dashboard.py
Normal file
201
labertasche/blueprints/bp_dashboard.py
Normal file
@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from flask import Blueprint, render_template, request, redirect
|
||||
from flask_login import login_required
|
||||
from labertasche.database import labertasche_db as db
|
||||
from labertasche.models import TLocation, TComments, TEmail
|
||||
from labertasche.helper import dates_of_the_week
|
||||
from sqlalchemy import func
|
||||
import re
|
||||
|
||||
# Blueprint
|
||||
bp_dashboard = Blueprint("bp_dashboard", __name__, url_prefix='/dashboard')
|
||||
|
||||
|
||||
@bp_dashboard.route('/')
|
||||
@login_required
|
||||
def dashboard_index():
|
||||
dates = dates_of_the_week()
|
||||
spam = list()
|
||||
published = list()
|
||||
unpublished = list()
|
||||
for each in dates:
|
||||
spam_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date())\
|
||||
.filter(TComments.is_spam == True).all()
|
||||
|
||||
pub_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date()) \
|
||||
.filter(TComments.is_spam == False)\
|
||||
.filter(TComments.is_published == True).all()
|
||||
|
||||
unpub_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date()) \
|
||||
.filter(TComments.is_spam == False)\
|
||||
.filter(TComments.is_published == False).all()
|
||||
|
||||
published.append(len(pub_comments))
|
||||
spam.append(len(spam_comments))
|
||||
unpublished.append(len(unpub_comments))
|
||||
|
||||
return render_template('dashboard.html', dates=dates, spam=spam, published=published, unpublished=unpublished)
|
||||
|
||||
|
||||
@bp_dashboard.route('/review-spam/', methods=["POST", "GET"])
|
||||
@bp_dashboard.route('/review-spam/<int:location>', methods=["POST", "GET"])
|
||||
@login_required
|
||||
def dashboard_review_spam(location=None):
|
||||
all_locations = db.session.query(TLocation).all()
|
||||
|
||||
# Check post
|
||||
if request.method == "POST":
|
||||
location = request.form.get('selected_location')
|
||||
|
||||
# no parameters found
|
||||
if location is None:
|
||||
return render_template("review-spam.html", locations=all_locations, selected=location)
|
||||
|
||||
try:
|
||||
if int(location) >= 1:
|
||||
spam_comments = db.session.query(TComments).filter(TComments.location_id == location)\
|
||||
.filter(TComments.is_spam == True)
|
||||
return render_template("review-spam.html", locations=all_locations, selected=location,
|
||||
spam_comments=spam_comments)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return render_template("review-spam.html", locations=all_locations, selected=location)
|
||||
|
||||
|
||||
@bp_dashboard.route('/manage-comments/', methods=["POST", "GET"])
|
||||
@bp_dashboard.route('/manage-comments/<int:location>', methods=["POST", "GET"])
|
||||
@login_required
|
||||
def dashboard_manage_regular_comments(location=None):
|
||||
all_locations = db.session.query(TLocation).all()
|
||||
|
||||
# Check post
|
||||
if request.method == "POST":
|
||||
location = request.form.get('selected_location')
|
||||
|
||||
# no parameters found
|
||||
if location is None:
|
||||
return render_template("manage-comments.html", locations=all_locations, selected=location)
|
||||
|
||||
try:
|
||||
if int(location) >= 1:
|
||||
spam_comments = db.session.query(TComments).filter(TComments.location_id == location) \
|
||||
.filter(TComments.is_spam == False)
|
||||
return render_template("manage-comments.html", locations=all_locations, selected=location,
|
||||
spam_comments=spam_comments)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return render_template("manage-comments.html", locations=all_locations, selected=location)
|
||||
|
||||
|
||||
@bp_dashboard.route('/manage-mail/')
|
||||
@login_required
|
||||
def dashboard_allow_email():
|
||||
addresses = db.session.query(TEmail).all()
|
||||
return render_template("manage_mail_addresses.html", addresses=addresses)
|
||||
|
||||
|
||||
@bp_dashboard.route('/toggle-mail-allowed/<int:id_email>')
|
||||
@login_required
|
||||
def dashboard_allow_email_toggle(id_email):
|
||||
address = db.session.query(TEmail).filter(TEmail.id_email == id_email).first()
|
||||
if address:
|
||||
setattr(address, "is_allowed", (not address.is_allowed))
|
||||
setattr(address, "is_blocked", (not address.is_blocked))
|
||||
db.session.commit()
|
||||
return redirect(request.referrer)
|
||||
|
||||
|
||||
@bp_dashboard.route('/reset-mail-reputation/<int:id_email>')
|
||||
@login_required
|
||||
def dashboard_reset_mail_reputation(id_email):
|
||||
db.session.query(TEmail).filter(TEmail.id_email == id_email).delete()
|
||||
db.session.commit()
|
||||
return redirect(request.referrer)
|
||||
|
||||
|
||||
@bp_dashboard.route('/delete-comment/<int:location_id>/<int:comment_id>', methods=['GET'])
|
||||
@login_required
|
||||
def dashboard_review_spam_delete_comment(location_id, comment_id):
|
||||
comment = db.session.query(TComments).filter(TComments.comments_id == comment_id).first()
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
# Remove after last slash, to keep the location but get rid of the comment id
|
||||
url = re.match("^(.*[/])", request.referrer)[0]
|
||||
return redirect(f"{url}/{location_id}")
|
||||
|
||||
|
||||
@bp_dashboard.route('/allow-comment/<int:location_id>/<int:comment_id>', methods=['GET'])
|
||||
@login_required
|
||||
def dashboard_review_spam_allow_comment(comment_id, location_id):
|
||||
comment = db.session.query(TComments).filter(TComments.comments_id == comment_id).first()
|
||||
if comment:
|
||||
setattr(comment, 'is_published', True)
|
||||
setattr(comment, 'is_spam', False)
|
||||
db.session.commit()
|
||||
|
||||
url = re.match("^(.*[/])", request.referrer)[0]
|
||||
return redirect(f"{url}/{location_id}")
|
||||
|
||||
|
||||
@bp_dashboard.route('/block-mail/<int:location_id>/<int:comment_id>', methods=["GET"])
|
||||
@login_required
|
||||
def dashboard_review_spam_block_mail(location_id, comment_id):
|
||||
comment = db.session.query(TComments).filter(TComments.comments_id == comment_id).first()
|
||||
if comment:
|
||||
mail = db.session.query(TEmail).filter(TEmail.email == comment.email).first()
|
||||
if mail:
|
||||
setattr(mail, 'is_allowed', False)
|
||||
setattr(mail, 'is_blocked', True)
|
||||
else:
|
||||
new_mail = {
|
||||
"email": comment.first().email,
|
||||
"is_allowed": False,
|
||||
"is_blocked": True
|
||||
}
|
||||
db.session.add(TEmail(**new_mail))
|
||||
|
||||
# Delete all comments made by this mail address
|
||||
db.session.query(TComments).filter(TComments.email == comment.email).delete()
|
||||
db.session.commit()
|
||||
|
||||
url = re.match("^(.*[/])", request.referrer)[0]
|
||||
return redirect(f"{url}/{location_id}")
|
||||
|
||||
|
||||
@bp_dashboard.route('/allow-user/<int:location_id>/<int:comment_id>', methods=["GET"])
|
||||
@login_required
|
||||
def dashboard_review_spam_allow_user(location_id, comment_id):
|
||||
comment = db.session.query(TComments).filter(TComments.comments_id == comment_id).first()
|
||||
if comment:
|
||||
mail = db.session.query(TEmail).filter(TEmail.email == comment.email).first()
|
||||
if mail:
|
||||
setattr(mail, 'is_allowed', True)
|
||||
setattr(mail, 'is_blocked', False)
|
||||
else:
|
||||
new_mail = {
|
||||
"email": comment.email,
|
||||
"is_allowed": True,
|
||||
"is_blocked": False
|
||||
}
|
||||
db.session.add(TEmail(**new_mail))
|
||||
|
||||
# Allow all comments made by this mail address
|
||||
all_comments = db.session.query(TComments).filter(TComments.email == comment.email).all()
|
||||
if all_comments:
|
||||
for comment in all_comments:
|
||||
setattr(comment, 'is_published', True)
|
||||
setattr(comment, 'is_spam', False)
|
||||
|
||||
db.session.commit()
|
||||
url = re.match("^(.*[/])", request.referrer)[0]
|
||||
return redirect(f"{url}/{location_id}")
|
46
labertasche/blueprints/bp_login.py
Normal file
46
labertasche/blueprints/bp_login.py
Normal file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
from flask_cors import cross_origin
|
||||
from labertasche.helper import check_auth, User
|
||||
from flask_login import login_user, current_user, logout_user
|
||||
|
||||
# Blueprint
|
||||
bp_login = Blueprint("bp_login", __name__)
|
||||
|
||||
|
||||
@cross_origin()
|
||||
@bp_login.route('/', methods=['GET'])
|
||||
def show_login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('bp_dashboard.dashboard_index'))
|
||||
return render_template('login.html')
|
||||
|
||||
|
||||
@cross_origin()
|
||||
@bp_login.route('/login', methods=['POST', 'GET'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
|
||||
if check_auth(username, password):
|
||||
login_user(User(0), remember=True)
|
||||
return redirect(url_for('bp_dashboard.dashboard_index'))
|
||||
|
||||
# Redirect get request to the login page
|
||||
return redirect(url_for('bp_login.show_login'))
|
||||
|
||||
|
||||
@cross_origin()
|
||||
@bp_login.route('/logout/', methods=["GET"])
|
||||
def logout():
|
||||
if current_user.is_authenticated:
|
||||
logout_user()
|
||||
return redirect(url_for("bp_login.show_login"))
|
12
labertasche/database/__init__.py
Normal file
12
labertasche/database/__init__.py
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
# Create SQLAlchemy
|
||||
labertasche_db = SQLAlchemy()
|
190
labertasche/helper/__init__.py
Normal file
190
labertasche/helper/__init__.py
Normal file
@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
import datetime
|
||||
import json
|
||||
from labertasche.models import TLocation, TComments
|
||||
from labertasche.settings import Settings
|
||||
from labertasche.database import labertasche_db as db
|
||||
from functools import wraps
|
||||
from hashlib import md5
|
||||
from flask import request
|
||||
from flask_login import UserMixin
|
||||
from secrets import compare_digest
|
||||
from pathlib import Path
|
||||
from sys import stderr
|
||||
from re import match as re_match
|
||||
import requests
|
||||
|
||||
|
||||
class User(UserMixin):
|
||||
def __init__(self, user_id):
|
||||
self.id = user_id
|
||||
|
||||
|
||||
def is_valid_json(j):
|
||||
"""
|
||||
Tries to load the json to test if it is valid.
|
||||
|
||||
:param j: The json to test.
|
||||
:return: True if the json is valid, False on any exception.
|
||||
"""
|
||||
try:
|
||||
json.dumps(j)
|
||||
return True
|
||||
except json.JSONDecodeError as e:
|
||||
print("not valid json")
|
||||
return False
|
||||
|
||||
|
||||
def default_timestamp():
|
||||
"""Timestamp used by the project to ensure consistency"""
|
||||
date = datetime.datetime.now().replace(microsecond=0)
|
||||
return date
|
||||
|
||||
|
||||
def time_to_js(obj):
|
||||
""""
|
||||
Returns a timestring readable by Javascript
|
||||
"""
|
||||
if isinstance(obj, (datetime.date, datetime.datetime)):
|
||||
return obj.isoformat()
|
||||
|
||||
|
||||
def alchemy_query_to_dict(obj):
|
||||
"""
|
||||
Used when exporting the data. It truncates the mail, removes the T from the date string, etc.
|
||||
|
||||
:param obj: A single query item from sqlalchemy.
|
||||
:return: a dict with the query
|
||||
"""
|
||||
no_mail = re_match("^.*[@]", obj.email)[0]
|
||||
result = {
|
||||
"comment_id": obj.comments_id,
|
||||
"email": no_mail,
|
||||
"content": obj.content,
|
||||
"created_on": time_to_js(obj.created_on).replace("T", " "),
|
||||
"replied_to": obj.replied_to,
|
||||
"gravatar": obj.gravatar
|
||||
}
|
||||
return dict(result)
|
||||
|
||||
|
||||
# Come on, it's a mail hash, don't complain
|
||||
# noinspection InsecureHash
|
||||
def check_gravatar(email: str):
|
||||
"""
|
||||
Builds the gravatar email hash, which uses md5.
|
||||
You may use ?size=128 for example to dictate size in the final template.
|
||||
:param email: the email to use for the hash
|
||||
:return: the gravatar url of the image
|
||||
"""
|
||||
settings = Settings()
|
||||
options = settings.gravatar
|
||||
gravatar_hash = md5(email.strip().lower().encode("utf8")).hexdigest()
|
||||
if options['cache']:
|
||||
url = f"https://www.gravatar.com/avatar/{gravatar_hash}?s={options['size']}"
|
||||
response = requests.get(url)
|
||||
if response.ok:
|
||||
outfile = Path(f"{options['static_dir']}/{gravatar_hash}.jpg")
|
||||
if not outfile.exists():
|
||||
with outfile.open('wb') as fp:
|
||||
response.raw.decode_content = True
|
||||
for chunk in response:
|
||||
fp.write(chunk)
|
||||
|
||||
return gravatar_hash
|
||||
|
||||
|
||||
def check_auth(username: str, password: str):
|
||||
"""
|
||||
Compares username and password from the settings file in a safe way.
|
||||
Direct string comparison is vulnerable to timing attacks
|
||||
https://sqreen.github.io/DevelopersSecurityBestPractices/timing-attack/python
|
||||
:param username: username entered by the user
|
||||
:param password: password entered by the user
|
||||
:return: True if equal, False if not
|
||||
"""
|
||||
settings = Settings()
|
||||
if compare_digest(username, settings.dashboard['username']) and \
|
||||
compare_digest(password, settings.dashboard['password']):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def basic_login_required(f):
|
||||
"""
|
||||
Decorator for basic auth
|
||||
"""
|
||||
@wraps(f)
|
||||
def wrapped_view(**kwargs):
|
||||
auth = request.authorization
|
||||
if not (auth and check_auth(auth.username, auth.password)):
|
||||
return ('Unauthorized', 401, {
|
||||
'WWW-Authenticate': 'Basic realm="Login Required"'
|
||||
})
|
||||
return f(**kwargs)
|
||||
return wrapped_view
|
||||
|
||||
|
||||
def export_location(location: str) -> bool:
|
||||
"""
|
||||
Exports the comments for the location after the comment was accepted
|
||||
:param location: relative url of the hugo page
|
||||
"""
|
||||
try:
|
||||
# Query
|
||||
loc_query = db.session.query(TLocation).filter(TLocation.location == location).first()
|
||||
|
||||
if loc_query:
|
||||
comments = db.session.query(TComments).filter(TComments.is_spam != True) \
|
||||
.filter(TComments.is_published == True) \
|
||||
.filter(TComments.location_id == loc_query.id_location) \
|
||||
.filter(TComments.replied_to == None)
|
||||
|
||||
bundle = {
|
||||
"comments": []
|
||||
}
|
||||
for comment in comments:
|
||||
bundle['comments'].append(alchemy_query_to_dict(comment))
|
||||
|
||||
path_loc = re_match(".*(?=/)", loc_query.location)[0]
|
||||
|
||||
system = Settings().system
|
||||
out = Path(f"{system['output']}/{path_loc}.json")
|
||||
out = out.absolute()
|
||||
print(out)
|
||||
folder = out.parents[0]
|
||||
folder.mkdir(parents=True, exist_ok=True)
|
||||
with out.open('w') as fp:
|
||||
json.dump(bundle, fp)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
# mail(f"export_comments has thrown an error: {str(e)}")
|
||||
print(e, file=stderr)
|
||||
return False
|
||||
|
||||
|
||||
def dates_of_the_week():
|
||||
"""
|
||||
Finds all dates of this week and returns them as a list,
|
||||
going from midnight on monday to sunday 1 second before midnight
|
||||
:return: A list containing the dates
|
||||
"""
|
||||
date_list = list()
|
||||
now = datetime.datetime.now()
|
||||
monday = now - datetime.timedelta(days=now.weekday(), hours=now.hour, minutes=now.minute, seconds=now.second,
|
||||
microseconds=now.microsecond)
|
||||
date_list.append(monday)
|
||||
for each in range(1, 6):
|
||||
monday = monday + datetime.timedelta(days=1)
|
||||
date_list.append(monday)
|
||||
date_list.append((monday + datetime.timedelta(days=1, hours=23, minutes=59, seconds=59)))
|
||||
return date_list
|
100
labertasche/mail/__init__.py
Normal file
100
labertasche/mail/__init__.py
Normal file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from json import load as j_load
|
||||
from pathlib import Path
|
||||
from platform import system
|
||||
from smtplib import SMTP_SSL, SMTPHeloError, SMTPAuthenticationError, SMTPException
|
||||
from ssl import create_default_context
|
||||
from labertasche.settings import Settings
|
||||
from validate_email import validate_email
|
||||
from secrets import token_urlsafe
|
||||
|
||||
|
||||
class mail:
|
||||
|
||||
def __init__(self):
|
||||
path = Path("/etc/labertasche/mail_credentials.json")
|
||||
if system().lower() == "windows":
|
||||
path = Path("mail_credentials.json")
|
||||
|
||||
with path.open("r") as fp:
|
||||
self.credentials = j_load(fp)
|
||||
|
||||
def send(self, txt_what: str, html_what: str, to: str):
|
||||
if not self.credentials['enable']:
|
||||
return
|
||||
|
||||
txtmail = MIMEText(txt_what, "plain", _charset='utf8')
|
||||
|
||||
multimime = MIMEMultipart('alternative')
|
||||
multimime['Subject'] = "Comment confirmation pending"
|
||||
multimime['From'] = self.credentials['email-sendfrom']
|
||||
multimime['To'] = to
|
||||
multimime.attach(txtmail)
|
||||
|
||||
# Only send HTML if needed
|
||||
if html_what is not None:
|
||||
htmlmail = MIMEText(html_what, "html", _charset='utf8')
|
||||
multimime.attach(htmlmail)
|
||||
|
||||
try:
|
||||
with SMTP_SSL(host=self.credentials['smtp-server'],
|
||||
port=self.credentials['smtp-port'],
|
||||
context=create_default_context()) as server:
|
||||
server.login(user=self.credentials['email-user'], password=self.credentials['email-password'])
|
||||
server.sendmail(to_addrs=to,
|
||||
msg=multimime.as_string(),
|
||||
from_addr=self.credentials['email-sendfrom'])
|
||||
|
||||
except SMTPHeloError as helo:
|
||||
print(f"SMTPHeloError: {helo}")
|
||||
except SMTPAuthenticationError as auth_error:
|
||||
print(f"Authentication Error: {auth_error}")
|
||||
except SMTPException as e:
|
||||
print(f"SMTPException: {e}")
|
||||
|
||||
def send_confirmation_link(self, email):
|
||||
"""
|
||||
Send confirmation link after entering a comment
|
||||
:param email: The address to send the mail to
|
||||
:return: A tuple with the confirmation token and the deletion token, in this order
|
||||
"""
|
||||
settings = Settings()
|
||||
confirm_digest = token_urlsafe(48)
|
||||
delete_digest = token_urlsafe(48)
|
||||
|
||||
confirm_url = f"{settings.system['web_url']}/comments/confirm/{confirm_digest}"
|
||||
delete_url = f"{settings.system['web_url']}/comments/delete/{delete_digest}"
|
||||
|
||||
txt_what = f"Hey there. You have made a comment on {settings.system['blog_url']}. Please confirm it by " \
|
||||
f"copying this link into your browser:\n{confirm_url}\nIf you want to delete your comment for,"\
|
||||
f"whatever reason, please use this link:\n{delete_url}"
|
||||
|
||||
html_what = f"Hey there. You have made a comment on {settings.system['blog_url']}.<br>Please confirm it by " \
|
||||
f"clicking on this <a href='{confirm_url}'>link</a>.<br>"\
|
||||
f"In case you want to delete your comment later, please click <a href='{delete_url}'>here</a>."\
|
||||
f"<br><br>If you think this is in error or someone made this comment in your name, please "\
|
||||
f"write me a <a href='mailto:contact@tuxstash.de'>mail</a> to discuss options such as " \
|
||||
f"blocking your mail from being used."
|
||||
|
||||
self.send(txt_what, html_what, email)
|
||||
|
||||
return confirm_digest, delete_digest
|
||||
|
||||
def validate(self, addr):
|
||||
# validate email
|
||||
is_valid = validate_email(email_address=addr,
|
||||
check_regex=True,
|
||||
check_mx=False,
|
||||
dns_timeout=10,
|
||||
use_blacklist=True,
|
||||
debug=False)
|
||||
return is_valid
|
11
labertasche/models/__init__.py
Normal file
11
labertasche/models/__init__.py
Normal file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from .t_comments import TComments
|
||||
from .t_location import TLocation
|
||||
from .t_emails import TEmail
|
34
labertasche/models/t_comments.py
Normal file
34
labertasche/models/t_comments.py
Normal file
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from labertasche.database import labertasche_db as db
|
||||
from sqlalchemy import ForeignKey
|
||||
|
||||
|
||||
class TComments(db.Model):
|
||||
# table name
|
||||
__tablename__ = "t_comments"
|
||||
__table_args__ = {'useexisting': True}
|
||||
|
||||
# primary key
|
||||
comments_id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# foreign keys
|
||||
location_id = db.Column(db.Text, ForeignKey('t_location.id_location'), nullable=False)
|
||||
|
||||
# data
|
||||
email = db.Column(db.Text, nullable=False)
|
||||
content = db.Column(db.Text, nullable=False, unique=True)
|
||||
created_on = db.Column(db.DateTime, nullable=False)
|
||||
is_published = db.Column(db.Boolean, nullable=False)
|
||||
is_spam = db.Column(db.Boolean, nullable=False)
|
||||
spam_score = db.Column(db.Float, nullable=False)
|
||||
replied_to = db.Column(db.Boolean, nullable=True)
|
||||
confirmation = db.Column(db.Text, nullable=True)
|
||||
deletion = db.Column(db.Text, nullable=True)
|
||||
gravatar = db.Column(db.Text, nullable=True)
|
23
labertasche/models/t_emails.py
Normal file
23
labertasche/models/t_emails.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from labertasche.database import labertasche_db as db
|
||||
|
||||
|
||||
class TEmail(db.Model):
|
||||
# Table name
|
||||
__tablename__ = 't_email'
|
||||
__table_args__ = {'useexisting': True}
|
||||
|
||||
# primary key
|
||||
id_email = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# data
|
||||
email = db.Column(db.Integer, unique=True)
|
||||
is_blocked = db.Column(db.Boolean)
|
||||
is_allowed = db.Column(db.Boolean)
|
21
labertasche/models/t_location.py
Normal file
21
labertasche/models/t_location.py
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from labertasche.database import labertasche_db as db
|
||||
|
||||
|
||||
class TLocation(db.Model):
|
||||
# table name
|
||||
__tablename__ = "t_location"
|
||||
__table_args__ = {'useexisting': True}
|
||||
|
||||
# primary key
|
||||
id_location = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
# data
|
||||
location = db.Column(db.Text, nullable=False, unique=True)
|
30
labertasche/settings/__init__.py
Normal file
30
labertasche/settings/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from platform import system
|
||||
|
||||
|
||||
class Settings:
|
||||
"""
|
||||
Automatically loads the settings from /etc/ on Linux and same directory on other OS
|
||||
"""
|
||||
def __init__(self):
|
||||
file = Path("labertasche.yaml")
|
||||
if system().lower() == "linux":
|
||||
file = Path("/etc/labertasche/labertasche.yaml")
|
||||
|
||||
with file.open('r') as fp:
|
||||
conf = yaml.safe_load(fp)
|
||||
|
||||
self.system = conf['system']
|
||||
self.dashboard = conf['dashboard']
|
||||
self.gravatar = conf['gravatar']
|
||||
self.addons = conf['addons']
|
||||
self.smileys = conf['smileys']
|
9
mail_credentials.json
Normal file
9
mail_credentials.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"enable": true,
|
||||
"smtp-server": "mail server",
|
||||
"smtp-port": 465,
|
||||
"email-user": "username for smtp",
|
||||
"email-sendfrom": "sender mail",
|
||||
"email-password": "passw0rd",
|
||||
"email-sendto": "receiving mail"
|
||||
}
|
75
server.py
Normal file
75
server.py
Normal file
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
import logging
|
||||
from flask import Flask, redirect, url_for
|
||||
from flask_cors import CORS
|
||||
from sqlalchemy import event
|
||||
# noinspection PyProtectedMember
|
||||
from sqlalchemy.engine import Engine
|
||||
from labertasche.settings import Settings
|
||||
from labertasche.database import labertasche_db
|
||||
from labertasche.blueprints import bp_comments, bp_login, bp_dashboard
|
||||
from labertasche.helper import User
|
||||
from flask_login import LoginManager
|
||||
|
||||
|
||||
# Load settings
|
||||
settings = Settings()
|
||||
|
||||
# Flask App
|
||||
laberflask = Flask(__name__)
|
||||
laberflask.config.update(dict(
|
||||
SESSION_COOKIE_DOMAIN=settings.system['cookie-domain'],
|
||||
DEBUG=settings.system['debug'],
|
||||
SECRET_KEY=settings.system['secret'],
|
||||
TEMPLATES_AUTO_RELOAD=True,
|
||||
SQLALCHEMY_DATABASE_URI=settings.system['database_uri'],
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS=False
|
||||
))
|
||||
|
||||
# CORS
|
||||
CORS(laberflask, resources={r"/comments": {"origins": settings.system['blog_url']}})
|
||||
|
||||
# Import blueprints
|
||||
laberflask.register_blueprint(bp_comments)
|
||||
laberflask.register_blueprint(bp_dashboard)
|
||||
laberflask.register_blueprint(bp_login)
|
||||
|
||||
# Disable Werkzeug's verbosity during development
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
|
||||
# Initialize ORM
|
||||
labertasche_db.init_app(laberflask)
|
||||
with laberflask.app_context():
|
||||
labertasche_db.create_all()
|
||||
|
||||
# Set up login manager
|
||||
loginmgr = LoginManager(laberflask)
|
||||
loginmgr.login_view = 'bp_admin_login.login'
|
||||
|
||||
|
||||
@loginmgr.user_loader
|
||||
def user_loader(user_id):
|
||||
if user_id != "0":
|
||||
return None
|
||||
return User(user_id)
|
||||
|
||||
|
||||
@loginmgr.unauthorized_handler
|
||||
def login_invalid():
|
||||
return redirect(url_for('bp_login.show_login'))
|
||||
|
||||
|
||||
@event.listens_for(Engine, "connect")
|
||||
def set_sqlite_pragma(dbapi_connection, connection_record):
|
||||
if settings.system["database_uri"][0:6] == 'sqlite':
|
||||
cursor = dbapi_connection.cursor()
|
||||
cursor.execute("PRAGMA journal_mode=WAL;")
|
||||
cursor.close()
|
16
server.wsgi
Normal file
16
server.wsgi
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# """
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/piradio
|
||||
# * _license : This project is under GPL.v2
|
||||
# *********************************************************************************/
|
||||
from sys import path as sys_path
|
||||
from os import path as os_path
|
||||
|
||||
sys_path.insert(0, os_path.dirname(os_path.realpath(__file__)))
|
||||
|
||||
from server import laberflask
|
||||
application = laberflask
|
1
static/css/Chart.min.css
vendored
Normal file
1
static/css/Chart.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
|
10168
static/css/labertasche.css
Normal file
10168
static/css/labertasche.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
static/css/open-sans-v18-latin-700.woff2
Normal file
BIN
static/css/open-sans-v18-latin-700.woff2
Normal file
Binary file not shown.
BIN
static/css/open-sans-v18-latin-700italic.woff2
Normal file
BIN
static/css/open-sans-v18-latin-700italic.woff2
Normal file
Binary file not shown.
BIN
static/css/open-sans-v18-latin-italic.woff2
Normal file
BIN
static/css/open-sans-v18-latin-italic.woff2
Normal file
Binary file not shown.
BIN
static/css/open-sans-v18-latin-regular.woff2
Normal file
BIN
static/css/open-sans-v18-latin-regular.woff2
Normal file
Binary file not shown.
5
static/css/sass/bulma/base/_all.sass
Normal file
5
static/css/sass/bulma/base/_all.sass
Normal file
@ -0,0 +1,5 @@
|
||||
/* Bulma Base */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "minireset.sass"
|
||||
@import "generic.sass"
|
143
static/css/sass/bulma/base/generic.sass
Normal file
143
static/css/sass/bulma/base/generic.sass
Normal file
@ -0,0 +1,143 @@
|
||||
$body-background-color: $scheme-main !default
|
||||
$body-size: 16px !default
|
||||
$body-min-width: 300px !default
|
||||
$body-rendering: optimizeLegibility !default
|
||||
$body-family: $family-primary !default
|
||||
$body-overflow-x: hidden !default
|
||||
$body-overflow-y: scroll !default
|
||||
|
||||
$body-color: $text !default
|
||||
$body-font-size: 1em !default
|
||||
$body-weight: $weight-normal !default
|
||||
$body-line-height: 1.5 !default
|
||||
|
||||
$code-family: $family-code !default
|
||||
$code-padding: 0.25em 0.5em 0.25em !default
|
||||
$code-weight: normal !default
|
||||
$code-size: 0.875em !default
|
||||
|
||||
$small-font-size: 0.875em !default
|
||||
|
||||
$hr-background-color: $background !default
|
||||
$hr-height: 2px !default
|
||||
$hr-margin: 1.5rem 0 !default
|
||||
|
||||
$strong-color: $text-strong !default
|
||||
$strong-weight: $weight-bold !default
|
||||
|
||||
$pre-font-size: 0.875em !default
|
||||
$pre-padding: 1.25rem 1.5rem !default
|
||||
$pre-code-font-size: 1em !default
|
||||
|
||||
html
|
||||
background-color: $body-background-color
|
||||
font-size: $body-size
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
-webkit-font-smoothing: antialiased
|
||||
min-width: $body-min-width
|
||||
overflow-x: $body-overflow-x
|
||||
overflow-y: $body-overflow-y
|
||||
text-rendering: $body-rendering
|
||||
text-size-adjust: 100%
|
||||
|
||||
article,
|
||||
aside,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
section
|
||||
display: block
|
||||
|
||||
body,
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea
|
||||
font-family: $body-family
|
||||
|
||||
code,
|
||||
pre
|
||||
-moz-osx-font-smoothing: auto
|
||||
-webkit-font-smoothing: auto
|
||||
font-family: $code-family
|
||||
|
||||
body
|
||||
color: $body-color
|
||||
font-size: $body-font-size
|
||||
font-weight: $body-weight
|
||||
line-height: $body-line-height
|
||||
|
||||
// Inline
|
||||
|
||||
a
|
||||
color: $link
|
||||
cursor: pointer
|
||||
text-decoration: none
|
||||
strong
|
||||
color: currentColor
|
||||
&:hover
|
||||
color: $link-hover
|
||||
|
||||
code
|
||||
background-color: $code-background
|
||||
color: $code
|
||||
font-size: $code-size
|
||||
font-weight: $code-weight
|
||||
padding: $code-padding
|
||||
|
||||
hr
|
||||
background-color: $hr-background-color
|
||||
border: none
|
||||
display: block
|
||||
height: $hr-height
|
||||
margin: $hr-margin
|
||||
|
||||
img
|
||||
height: auto
|
||||
max-width: 100%
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"]
|
||||
vertical-align: baseline
|
||||
|
||||
small
|
||||
font-size: $small-font-size
|
||||
|
||||
span
|
||||
font-style: inherit
|
||||
font-weight: inherit
|
||||
|
||||
strong
|
||||
color: $strong-color
|
||||
font-weight: $strong-weight
|
||||
|
||||
// Block
|
||||
|
||||
fieldset
|
||||
border: none
|
||||
|
||||
pre
|
||||
+overflow-touch
|
||||
background-color: $pre-background
|
||||
color: $pre
|
||||
font-size: $pre-font-size
|
||||
overflow-x: auto
|
||||
padding: $pre-padding
|
||||
white-space: pre
|
||||
word-wrap: normal
|
||||
code
|
||||
background-color: transparent
|
||||
color: currentColor
|
||||
font-size: $pre-code-font-size
|
||||
padding: 0
|
||||
|
||||
table
|
||||
td,
|
||||
th
|
||||
vertical-align: top
|
||||
&:not([align])
|
||||
text-align: inherit
|
||||
th
|
||||
color: $text-strong
|
1
static/css/sass/bulma/base/helpers.sass
Normal file
1
static/css/sass/bulma/base/helpers.sass
Normal file
@ -0,0 +1 @@
|
||||
@warn "The helpers.sass file is DEPRECATED. It has moved into its own /helpers folder. Please import sass/helpers/_all instead."
|
79
static/css/sass/bulma/base/minireset.sass
Normal file
79
static/css/sass/bulma/base/minireset.sass
Normal file
@ -0,0 +1,79 @@
|
||||
/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */
|
||||
// Blocks
|
||||
html,
|
||||
body,
|
||||
p,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
blockquote,
|
||||
figure,
|
||||
fieldset,
|
||||
legend,
|
||||
textarea,
|
||||
pre,
|
||||
iframe,
|
||||
hr,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
// Headings
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
font-size: 100%
|
||||
font-weight: normal
|
||||
|
||||
// List
|
||||
ul
|
||||
list-style: none
|
||||
|
||||
// Form
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea
|
||||
margin: 0
|
||||
|
||||
// Box sizing
|
||||
html
|
||||
box-sizing: border-box
|
||||
|
||||
*
|
||||
&,
|
||||
&::before,
|
||||
&::after
|
||||
box-sizing: inherit
|
||||
|
||||
// Media
|
||||
img,
|
||||
video
|
||||
height: auto
|
||||
max-width: 100%
|
||||
|
||||
// Iframe
|
||||
iframe
|
||||
border: 0
|
||||
|
||||
// Table
|
||||
table
|
||||
border-collapse: collapse
|
||||
border-spacing: 0
|
||||
|
||||
td,
|
||||
th
|
||||
padding: 0
|
||||
&:not([align])
|
||||
text-align: inherit
|
15
static/css/sass/bulma/components/_all.sass
Normal file
15
static/css/sass/bulma/components/_all.sass
Normal file
@ -0,0 +1,15 @@
|
||||
/* Bulma Components */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "breadcrumb.sass"
|
||||
@import "card.sass"
|
||||
@import "dropdown.sass"
|
||||
@import "level.sass"
|
||||
@import "media.sass"
|
||||
@import "menu.sass"
|
||||
@import "message.sass"
|
||||
@import "modal.sass"
|
||||
@import "navbar.sass"
|
||||
@import "pagination.sass"
|
||||
@import "panel.sass"
|
||||
@import "tabs.sass"
|
75
static/css/sass/bulma/components/breadcrumb.sass
Normal file
75
static/css/sass/bulma/components/breadcrumb.sass
Normal file
@ -0,0 +1,75 @@
|
||||
$breadcrumb-item-color: $link !default
|
||||
$breadcrumb-item-hover-color: $link-hover !default
|
||||
$breadcrumb-item-active-color: $text-strong !default
|
||||
|
||||
$breadcrumb-item-padding-vertical: 0 !default
|
||||
$breadcrumb-item-padding-horizontal: 0.75em !default
|
||||
|
||||
$breadcrumb-item-separator-color: $border-hover !default
|
||||
|
||||
.breadcrumb
|
||||
@extend %block
|
||||
@extend %unselectable
|
||||
font-size: $size-normal
|
||||
white-space: nowrap
|
||||
a
|
||||
align-items: center
|
||||
color: $breadcrumb-item-color
|
||||
display: flex
|
||||
justify-content: center
|
||||
padding: $breadcrumb-item-padding-vertical $breadcrumb-item-padding-horizontal
|
||||
&:hover
|
||||
color: $breadcrumb-item-hover-color
|
||||
li
|
||||
align-items: center
|
||||
display: flex
|
||||
&:first-child a
|
||||
+ltr-property("padding", 0, false)
|
||||
&.is-active
|
||||
a
|
||||
color: $breadcrumb-item-active-color
|
||||
cursor: default
|
||||
pointer-events: none
|
||||
& + li::before
|
||||
color: $breadcrumb-item-separator-color
|
||||
content: "\0002f"
|
||||
ul,
|
||||
ol
|
||||
align-items: flex-start
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
justify-content: flex-start
|
||||
.icon
|
||||
&:first-child
|
||||
+ltr-property("margin", 0.5em)
|
||||
&:last-child
|
||||
+ltr-property("margin", 0.5em, false)
|
||||
// Alignment
|
||||
&.is-centered
|
||||
ol,
|
||||
ul
|
||||
justify-content: center
|
||||
&.is-right
|
||||
ol,
|
||||
ul
|
||||
justify-content: flex-end
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
// Styles
|
||||
&.has-arrow-separator
|
||||
li + li::before
|
||||
content: "\02192"
|
||||
&.has-bullet-separator
|
||||
li + li::before
|
||||
content: "\02022"
|
||||
&.has-dot-separator
|
||||
li + li::before
|
||||
content: "\000b7"
|
||||
&.has-succeeds-separator
|
||||
li + li::before
|
||||
content: "\0227B"
|
83
static/css/sass/bulma/components/card.sass
Normal file
83
static/css/sass/bulma/components/card.sass
Normal file
@ -0,0 +1,83 @@
|
||||
$card-color: $text !default
|
||||
$card-background-color: $scheme-main !default
|
||||
$card-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02) !default
|
||||
$card-radius: 0.25rem !default
|
||||
$card-overflow: hidden !default
|
||||
|
||||
$card-header-background-color: transparent !default
|
||||
$card-header-color: $text-strong !default
|
||||
$card-header-padding: 0.75rem 1rem !default
|
||||
$card-header-shadow: 0 0.125em 0.25em rgba($scheme-invert, 0.1) !default
|
||||
$card-header-weight: $weight-bold !default
|
||||
|
||||
$card-content-background-color: transparent !default
|
||||
$card-content-padding: 1.5rem !default
|
||||
|
||||
$card-footer-background-color: transparent !default
|
||||
$card-footer-border-top: 1px solid $border-light !default
|
||||
$card-footer-padding: 0.75rem !default
|
||||
|
||||
$card-media-margin: $block-spacing !default
|
||||
|
||||
.card
|
||||
background-color: $card-background-color
|
||||
border-radius: $card-radius
|
||||
box-shadow: $card-shadow
|
||||
color: $card-color
|
||||
max-width: 100%
|
||||
overflow: $card-overflow
|
||||
position: relative
|
||||
|
||||
.card-header
|
||||
background-color: $card-header-background-color
|
||||
align-items: stretch
|
||||
box-shadow: $card-header-shadow
|
||||
display: flex
|
||||
|
||||
.card-header-title
|
||||
align-items: center
|
||||
color: $card-header-color
|
||||
display: flex
|
||||
flex-grow: 1
|
||||
font-weight: $card-header-weight
|
||||
padding: $card-header-padding
|
||||
&.is-centered
|
||||
justify-content: center
|
||||
|
||||
.card-header-icon
|
||||
align-items: center
|
||||
cursor: pointer
|
||||
display: flex
|
||||
justify-content: center
|
||||
padding: $card-header-padding
|
||||
|
||||
.card-image
|
||||
display: block
|
||||
position: relative
|
||||
|
||||
.card-content
|
||||
background-color: $card-content-background-color
|
||||
padding: $card-content-padding
|
||||
|
||||
.card-footer
|
||||
background-color: $card-footer-background-color
|
||||
border-top: $card-footer-border-top
|
||||
align-items: stretch
|
||||
display: flex
|
||||
|
||||
.card-footer-item
|
||||
align-items: center
|
||||
display: flex
|
||||
flex-basis: 0
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
justify-content: center
|
||||
padding: $card-footer-padding
|
||||
&:not(:last-child)
|
||||
+ltr-property("border", $card-footer-border-top)
|
||||
|
||||
// Combinations
|
||||
|
||||
.card
|
||||
.media:not(:last-child)
|
||||
margin-bottom: $card-media-margin
|
81
static/css/sass/bulma/components/dropdown.sass
Normal file
81
static/css/sass/bulma/components/dropdown.sass
Normal file
@ -0,0 +1,81 @@
|
||||
$dropdown-menu-min-width: 12rem !default
|
||||
|
||||
$dropdown-content-background-color: $scheme-main !default
|
||||
$dropdown-content-arrow: $link !default
|
||||
$dropdown-content-offset: 4px !default
|
||||
$dropdown-content-padding-bottom: 0.5rem !default
|
||||
$dropdown-content-padding-top: 0.5rem !default
|
||||
$dropdown-content-radius: $radius !default
|
||||
$dropdown-content-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02) !default
|
||||
$dropdown-content-z: 20 !default
|
||||
|
||||
$dropdown-item-color: $text !default
|
||||
$dropdown-item-hover-color: $scheme-invert !default
|
||||
$dropdown-item-hover-background-color: $background !default
|
||||
$dropdown-item-active-color: $link-invert !default
|
||||
$dropdown-item-active-background-color: $link !default
|
||||
|
||||
$dropdown-divider-background-color: $border-light !default
|
||||
|
||||
.dropdown
|
||||
display: inline-flex
|
||||
position: relative
|
||||
vertical-align: top
|
||||
&.is-active,
|
||||
&.is-hoverable:hover
|
||||
.dropdown-menu
|
||||
display: block
|
||||
&.is-right
|
||||
.dropdown-menu
|
||||
left: auto
|
||||
right: 0
|
||||
&.is-up
|
||||
.dropdown-menu
|
||||
bottom: 100%
|
||||
padding-bottom: $dropdown-content-offset
|
||||
padding-top: initial
|
||||
top: auto
|
||||
|
||||
.dropdown-menu
|
||||
display: none
|
||||
+ltr-position(0, false)
|
||||
min-width: $dropdown-menu-min-width
|
||||
padding-top: $dropdown-content-offset
|
||||
position: absolute
|
||||
top: 100%
|
||||
z-index: $dropdown-content-z
|
||||
|
||||
.dropdown-content
|
||||
background-color: $dropdown-content-background-color
|
||||
border-radius: $dropdown-content-radius
|
||||
box-shadow: $dropdown-content-shadow
|
||||
padding-bottom: $dropdown-content-padding-bottom
|
||||
padding-top: $dropdown-content-padding-top
|
||||
|
||||
.dropdown-item
|
||||
color: $dropdown-item-color
|
||||
display: block
|
||||
font-size: 0.875rem
|
||||
line-height: 1.5
|
||||
padding: 0.375rem 1rem
|
||||
position: relative
|
||||
|
||||
a.dropdown-item,
|
||||
button.dropdown-item
|
||||
+ltr-property("padding", 3rem)
|
||||
text-align: inherit
|
||||
white-space: nowrap
|
||||
width: 100%
|
||||
&:hover
|
||||
background-color: $dropdown-item-hover-background-color
|
||||
color: $dropdown-item-hover-color
|
||||
&.is-active
|
||||
background-color: $dropdown-item-active-background-color
|
||||
color: $dropdown-item-active-color
|
||||
|
||||
.dropdown-divider
|
||||
background-color: $dropdown-divider-background-color
|
||||
border: none
|
||||
display: block
|
||||
height: 1px
|
||||
margin: 0.5rem 0
|
77
static/css/sass/bulma/components/level.sass
Normal file
77
static/css/sass/bulma/components/level.sass
Normal file
@ -0,0 +1,77 @@
|
||||
$level-item-spacing: ($block-spacing / 2) !default
|
||||
|
||||
.level
|
||||
@extend %block
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
code
|
||||
border-radius: $radius
|
||||
img
|
||||
display: inline-block
|
||||
vertical-align: top
|
||||
// Modifiers
|
||||
&.is-mobile
|
||||
display: flex
|
||||
.level-left,
|
||||
.level-right
|
||||
display: flex
|
||||
.level-left + .level-right
|
||||
margin-top: 0
|
||||
.level-item
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0
|
||||
+ltr-property("margin", $level-item-spacing)
|
||||
&:not(.is-narrow)
|
||||
flex-grow: 1
|
||||
// Responsiveness
|
||||
+tablet
|
||||
display: flex
|
||||
& > .level-item
|
||||
&:not(.is-narrow)
|
||||
flex-grow: 1
|
||||
|
||||
.level-item
|
||||
align-items: center
|
||||
display: flex
|
||||
flex-basis: auto
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
justify-content: center
|
||||
.title,
|
||||
.subtitle
|
||||
margin-bottom: 0
|
||||
// Responsiveness
|
||||
+mobile
|
||||
&:not(:last-child)
|
||||
margin-bottom: $level-item-spacing
|
||||
|
||||
.level-left,
|
||||
.level-right
|
||||
flex-basis: auto
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
.level-item
|
||||
// Modifiers
|
||||
&.is-flexible
|
||||
flex-grow: 1
|
||||
// Responsiveness
|
||||
+tablet
|
||||
&:not(:last-child)
|
||||
+ltr-property("margin", $level-item-spacing)
|
||||
|
||||
.level-left
|
||||
align-items: center
|
||||
justify-content: flex-start
|
||||
// Responsiveness
|
||||
+mobile
|
||||
& + .level-right
|
||||
margin-top: 1.5rem
|
||||
+tablet
|
||||
display: flex
|
||||
|
||||
.level-right
|
||||
align-items: center
|
||||
justify-content: flex-end
|
||||
// Responsiveness
|
||||
+tablet
|
||||
display: flex
|
52
static/css/sass/bulma/components/media.sass
Normal file
52
static/css/sass/bulma/components/media.sass
Normal file
@ -0,0 +1,52 @@
|
||||
$media-border-color: bulmaRgba($border, 0.5) !default
|
||||
$media-spacing: 1rem
|
||||
$media-spacing-large: 1.5rem
|
||||
|
||||
.media
|
||||
align-items: flex-start
|
||||
display: flex
|
||||
text-align: inherit
|
||||
.content:not(:last-child)
|
||||
margin-bottom: 0.75rem
|
||||
.media
|
||||
border-top: 1px solid $media-border-color
|
||||
display: flex
|
||||
padding-top: 0.75rem
|
||||
.content:not(:last-child),
|
||||
.control:not(:last-child)
|
||||
margin-bottom: 0.5rem
|
||||
.media
|
||||
padding-top: 0.5rem
|
||||
& + .media
|
||||
margin-top: 0.5rem
|
||||
& + .media
|
||||
border-top: 1px solid $media-border-color
|
||||
margin-top: $media-spacing
|
||||
padding-top: $media-spacing
|
||||
// Sizes
|
||||
&.is-large
|
||||
& + .media
|
||||
margin-top: $media-spacing-large
|
||||
padding-top: $media-spacing-large
|
||||
|
||||
.media-left,
|
||||
.media-right
|
||||
flex-basis: auto
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
|
||||
.media-left
|
||||
+ltr-property("margin", $media-spacing)
|
||||
|
||||
.media-right
|
||||
+ltr-property("margin", $media-spacing, false)
|
||||
|
||||
.media-content
|
||||
flex-basis: auto
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
text-align: inherit
|
||||
|
||||
+mobile
|
||||
.media-content
|
||||
overflow-x: auto
|
57
static/css/sass/bulma/components/menu.sass
Normal file
57
static/css/sass/bulma/components/menu.sass
Normal file
@ -0,0 +1,57 @@
|
||||
$menu-item-color: $text !default
|
||||
$menu-item-radius: $radius-small !default
|
||||
$menu-item-hover-color: $text-strong !default
|
||||
$menu-item-hover-background-color: $background !default
|
||||
$menu-item-active-color: $link-invert !default
|
||||
$menu-item-active-background-color: $link !default
|
||||
|
||||
$menu-list-border-left: 1px solid $border !default
|
||||
$menu-list-line-height: 1.25 !default
|
||||
$menu-list-link-padding: 0.5em 0.75em !default
|
||||
$menu-nested-list-margin: 0.75em !default
|
||||
$menu-nested-list-padding-left: 0.75em !default
|
||||
|
||||
$menu-label-color: $text-light !default
|
||||
$menu-label-font-size: 0.75em !default
|
||||
$menu-label-letter-spacing: 0.1em !default
|
||||
$menu-label-spacing: 1em !default
|
||||
|
||||
.menu
|
||||
font-size: $size-normal
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
|
||||
.menu-list
|
||||
line-height: $menu-list-line-height
|
||||
a
|
||||
border-radius: $menu-item-radius
|
||||
color: $menu-item-color
|
||||
display: block
|
||||
padding: $menu-list-link-padding
|
||||
&:hover
|
||||
background-color: $menu-item-hover-background-color
|
||||
color: $menu-item-hover-color
|
||||
// Modifiers
|
||||
&.is-active
|
||||
background-color: $menu-item-active-background-color
|
||||
color: $menu-item-active-color
|
||||
li
|
||||
ul
|
||||
+ltr-property("border", $menu-list-border-left, false)
|
||||
margin: $menu-nested-list-margin
|
||||
+ltr-property("padding", $menu-nested-list-padding-left, false)
|
||||
|
||||
.menu-label
|
||||
color: $menu-label-color
|
||||
font-size: $menu-label-font-size
|
||||
letter-spacing: $menu-label-letter-spacing
|
||||
text-transform: uppercase
|
||||
&:not(:first-child)
|
||||
margin-top: $menu-label-spacing
|
||||
&:not(:last-child)
|
||||
margin-bottom: $menu-label-spacing
|
99
static/css/sass/bulma/components/message.sass
Normal file
99
static/css/sass/bulma/components/message.sass
Normal file
@ -0,0 +1,99 @@
|
||||
$message-background-color: $background !default
|
||||
$message-radius: $radius !default
|
||||
|
||||
$message-header-background-color: $text !default
|
||||
$message-header-color: $text-invert !default
|
||||
$message-header-weight: $weight-bold !default
|
||||
$message-header-padding: 0.75em 1em !default
|
||||
$message-header-radius: $radius !default
|
||||
|
||||
$message-body-border-color: $border !default
|
||||
$message-body-border-width: 0 0 0 4px !default
|
||||
$message-body-color: $text !default
|
||||
$message-body-padding: 1.25em 1.5em !default
|
||||
$message-body-radius: $radius !default
|
||||
|
||||
$message-body-pre-background-color: $scheme-main !default
|
||||
$message-body-pre-code-background-color: transparent !default
|
||||
|
||||
$message-header-body-border-width: 0 !default
|
||||
$message-colors: $colors !default
|
||||
|
||||
.message
|
||||
@extend %block
|
||||
background-color: $message-background-color
|
||||
border-radius: $message-radius
|
||||
font-size: $size-normal
|
||||
strong
|
||||
color: currentColor
|
||||
a:not(.button):not(.tag):not(.dropdown-item)
|
||||
color: currentColor
|
||||
text-decoration: underline
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
// Colors
|
||||
@each $name, $components in $message-colors
|
||||
$color: nth($components, 1)
|
||||
$color-invert: nth($components, 2)
|
||||
$color-light: null
|
||||
$color-dark: null
|
||||
|
||||
@if length($components) >= 3
|
||||
$color-light: nth($components, 3)
|
||||
@if length($components) >= 4
|
||||
$color-dark: nth($components, 4)
|
||||
@else
|
||||
$color-luminance: colorLuminance($color)
|
||||
$darken-percentage: $color-luminance * 70%
|
||||
$desaturate-percentage: $color-luminance * 30%
|
||||
$color-dark: desaturate(darken($color, $darken-percentage), $desaturate-percentage)
|
||||
@else
|
||||
$color-lightning: max((100% - lightness($color)) - 2%, 0%)
|
||||
$color-light: lighten($color, $color-lightning)
|
||||
|
||||
&.is-#{$name}
|
||||
background-color: $color-light
|
||||
.message-header
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
.message-body
|
||||
border-color: $color
|
||||
color: $color-dark
|
||||
|
||||
.message-header
|
||||
align-items: center
|
||||
background-color: $message-header-background-color
|
||||
border-radius: $message-header-radius $message-header-radius 0 0
|
||||
color: $message-header-color
|
||||
display: flex
|
||||
font-weight: $message-header-weight
|
||||
justify-content: space-between
|
||||
line-height: 1.25
|
||||
padding: $message-header-padding
|
||||
position: relative
|
||||
.delete
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
+ltr-property("margin", 0.75em, false)
|
||||
& + .message-body
|
||||
border-width: $message-header-body-border-width
|
||||
border-top-left-radius: 0
|
||||
border-top-right-radius: 0
|
||||
|
||||
.message-body
|
||||
border-color: $message-body-border-color
|
||||
border-radius: $message-body-radius
|
||||
border-style: solid
|
||||
border-width: $message-body-border-width
|
||||
color: $message-body-color
|
||||
padding: $message-body-padding
|
||||
code,
|
||||
pre
|
||||
background-color: $message-body-pre-background-color
|
||||
pre code
|
||||
background-color: $message-body-pre-code-background-color
|
115
static/css/sass/bulma/components/modal.sass
Normal file
115
static/css/sass/bulma/components/modal.sass
Normal file
@ -0,0 +1,115 @@
|
||||
$modal-z: 40 !default
|
||||
|
||||
$modal-background-background-color: bulmaRgba($scheme-invert, 0.86) !default
|
||||
|
||||
$modal-content-width: 640px !default
|
||||
$modal-content-margin-mobile: 20px !default
|
||||
$modal-content-spacing-mobile: 160px !default
|
||||
$modal-content-spacing-tablet: 40px !default
|
||||
|
||||
$modal-close-dimensions: 40px !default
|
||||
$modal-close-right: 20px !default
|
||||
$modal-close-top: 20px !default
|
||||
|
||||
$modal-card-spacing: 40px !default
|
||||
|
||||
$modal-card-head-background-color: $background !default
|
||||
$modal-card-head-border-bottom: 1px solid $border !default
|
||||
$modal-card-head-padding: 20px !default
|
||||
$modal-card-head-radius: $radius-large !default
|
||||
|
||||
$modal-card-title-color: $text-strong !default
|
||||
$modal-card-title-line-height: 1 !default
|
||||
$modal-card-title-size: $size-4 !default
|
||||
|
||||
$modal-card-foot-radius: $radius-large !default
|
||||
$modal-card-foot-border-top: 1px solid $border !default
|
||||
|
||||
$modal-card-body-background-color: $scheme-main !default
|
||||
$modal-card-body-padding: 20px !default
|
||||
|
||||
$modal-breakpoint: $tablet !default
|
||||
|
||||
.modal
|
||||
@extend %overlay
|
||||
align-items: center
|
||||
display: none
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
overflow: hidden
|
||||
position: fixed
|
||||
z-index: $modal-z
|
||||
// Modifiers
|
||||
&.is-active
|
||||
display: flex
|
||||
|
||||
.modal-background
|
||||
@extend %overlay
|
||||
background-color: $modal-background-background-color
|
||||
|
||||
.modal-content,
|
||||
.modal-card
|
||||
margin: 0 $modal-content-margin-mobile
|
||||
max-height: calc(100vh - #{$modal-content-spacing-mobile})
|
||||
overflow: auto
|
||||
position: relative
|
||||
width: 100%
|
||||
// Responsiveness
|
||||
+from($modal-breakpoint)
|
||||
margin: 0 auto
|
||||
max-height: calc(100vh - #{$modal-content-spacing-tablet})
|
||||
width: $modal-content-width
|
||||
|
||||
.modal-close
|
||||
@extend %delete
|
||||
background: none
|
||||
height: $modal-close-dimensions
|
||||
position: fixed
|
||||
+ltr-position($modal-close-right)
|
||||
top: $modal-close-top
|
||||
width: $modal-close-dimensions
|
||||
|
||||
.modal-card
|
||||
display: flex
|
||||
flex-direction: column
|
||||
max-height: calc(100vh - #{$modal-card-spacing})
|
||||
overflow: hidden
|
||||
-ms-overflow-y: visible
|
||||
|
||||
.modal-card-head,
|
||||
.modal-card-foot
|
||||
align-items: center
|
||||
background-color: $modal-card-head-background-color
|
||||
display: flex
|
||||
flex-shrink: 0
|
||||
justify-content: flex-start
|
||||
padding: $modal-card-head-padding
|
||||
position: relative
|
||||
|
||||
.modal-card-head
|
||||
border-bottom: $modal-card-head-border-bottom
|
||||
border-top-left-radius: $modal-card-head-radius
|
||||
border-top-right-radius: $modal-card-head-radius
|
||||
|
||||
.modal-card-title
|
||||
color: $modal-card-title-color
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
font-size: $modal-card-title-size
|
||||
line-height: $modal-card-title-line-height
|
||||
|
||||
.modal-card-foot
|
||||
border-bottom-left-radius: $modal-card-foot-radius
|
||||
border-bottom-right-radius: $modal-card-foot-radius
|
||||
border-top: $modal-card-foot-border-top
|
||||
.button
|
||||
&:not(:last-child)
|
||||
+ltr-property("margin", 0.5em)
|
||||
|
||||
.modal-card-body
|
||||
+overflow-touch
|
||||
background-color: $modal-card-body-background-color
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
overflow: auto
|
||||
padding: $modal-card-body-padding
|
443
static/css/sass/bulma/components/navbar.sass
Normal file
443
static/css/sass/bulma/components/navbar.sass
Normal file
@ -0,0 +1,443 @@
|
||||
$navbar-background-color: $scheme-main !default
|
||||
$navbar-box-shadow-size: 0 2px 0 0 !default
|
||||
$navbar-box-shadow-color: $background !default
|
||||
$navbar-height: 3.25rem !default
|
||||
$navbar-padding-vertical: 1rem !default
|
||||
$navbar-padding-horizontal: 2rem !default
|
||||
$navbar-z: 30 !default
|
||||
$navbar-fixed-z: 30 !default
|
||||
|
||||
$navbar-item-color: $text !default
|
||||
$navbar-item-hover-color: $link !default
|
||||
$navbar-item-hover-background-color: $scheme-main-bis !default
|
||||
$navbar-item-active-color: $scheme-invert !default
|
||||
$navbar-item-active-background-color: transparent !default
|
||||
$navbar-item-img-max-height: 1.75rem !default
|
||||
|
||||
$navbar-burger-color: $navbar-item-color !default
|
||||
|
||||
$navbar-tab-hover-background-color: transparent !default
|
||||
$navbar-tab-hover-border-bottom-color: $link !default
|
||||
$navbar-tab-active-color: $link !default
|
||||
$navbar-tab-active-background-color: transparent !default
|
||||
$navbar-tab-active-border-bottom-color: $link !default
|
||||
$navbar-tab-active-border-bottom-style: solid !default
|
||||
$navbar-tab-active-border-bottom-width: 3px !default
|
||||
|
||||
$navbar-dropdown-background-color: $scheme-main !default
|
||||
$navbar-dropdown-border-top: 2px solid $border !default
|
||||
$navbar-dropdown-offset: -4px !default
|
||||
$navbar-dropdown-arrow: $link !default
|
||||
$navbar-dropdown-radius: $radius-large !default
|
||||
$navbar-dropdown-z: 20 !default
|
||||
|
||||
$navbar-dropdown-boxed-radius: $radius-large !default
|
||||
$navbar-dropdown-boxed-shadow: 0 8px 8px bulmaRgba($scheme-invert, 0.1), 0 0 0 1px bulmaRgba($scheme-invert, 0.1) !default
|
||||
|
||||
$navbar-dropdown-item-hover-color: $scheme-invert !default
|
||||
$navbar-dropdown-item-hover-background-color: $background !default
|
||||
$navbar-dropdown-item-active-color: $link !default
|
||||
$navbar-dropdown-item-active-background-color: $background !default
|
||||
|
||||
$navbar-divider-background-color: $background !default
|
||||
$navbar-divider-height: 2px !default
|
||||
|
||||
$navbar-bottom-box-shadow-size: 0 -2px 0 0 !default
|
||||
|
||||
$navbar-breakpoint: $desktop !default
|
||||
|
||||
$navbar-colors: $colors !default
|
||||
|
||||
=navbar-fixed
|
||||
left: 0
|
||||
position: fixed
|
||||
right: 0
|
||||
z-index: $navbar-fixed-z
|
||||
|
||||
.navbar
|
||||
background-color: $navbar-background-color
|
||||
min-height: $navbar-height
|
||||
position: relative
|
||||
z-index: $navbar-z
|
||||
@each $name, $pair in $navbar-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
.navbar-brand
|
||||
& > .navbar-item,
|
||||
.navbar-link
|
||||
color: $color-invert
|
||||
& > a.navbar-item,
|
||||
.navbar-link
|
||||
&:focus,
|
||||
&:hover,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
color: $color-invert
|
||||
.navbar-link
|
||||
&::after
|
||||
border-color: $color-invert
|
||||
.navbar-burger
|
||||
color: $color-invert
|
||||
+from($navbar-breakpoint)
|
||||
.navbar-start,
|
||||
.navbar-end
|
||||
& > .navbar-item,
|
||||
.navbar-link
|
||||
color: $color-invert
|
||||
& > a.navbar-item,
|
||||
.navbar-link
|
||||
&:focus,
|
||||
&:hover,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
color: $color-invert
|
||||
.navbar-link
|
||||
&::after
|
||||
border-color: $color-invert
|
||||
.navbar-item.has-dropdown:focus .navbar-link,
|
||||
.navbar-item.has-dropdown:hover .navbar-link,
|
||||
.navbar-item.has-dropdown.is-active .navbar-link
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
color: $color-invert
|
||||
.navbar-dropdown
|
||||
a.navbar-item
|
||||
&.is-active
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
& > .container
|
||||
align-items: stretch
|
||||
display: flex
|
||||
min-height: $navbar-height
|
||||
width: 100%
|
||||
&.has-shadow
|
||||
box-shadow: $navbar-box-shadow-size $navbar-box-shadow-color
|
||||
&.is-fixed-bottom,
|
||||
&.is-fixed-top
|
||||
+navbar-fixed
|
||||
&.is-fixed-bottom
|
||||
bottom: 0
|
||||
&.has-shadow
|
||||
box-shadow: $navbar-bottom-box-shadow-size $navbar-box-shadow-color
|
||||
&.is-fixed-top
|
||||
top: 0
|
||||
|
||||
html,
|
||||
body
|
||||
&.has-navbar-fixed-top
|
||||
padding-top: $navbar-height
|
||||
&.has-navbar-fixed-bottom
|
||||
padding-bottom: $navbar-height
|
||||
|
||||
.navbar-brand,
|
||||
.navbar-tabs
|
||||
align-items: stretch
|
||||
display: flex
|
||||
flex-shrink: 0
|
||||
min-height: $navbar-height
|
||||
|
||||
.navbar-brand
|
||||
a.navbar-item
|
||||
&:focus,
|
||||
&:hover
|
||||
background-color: transparent
|
||||
|
||||
.navbar-tabs
|
||||
+overflow-touch
|
||||
max-width: 100vw
|
||||
overflow-x: auto
|
||||
overflow-y: hidden
|
||||
|
||||
.navbar-burger
|
||||
color: $navbar-burger-color
|
||||
+hamburger($navbar-height)
|
||||
+ltr-property("margin", auto, false)
|
||||
|
||||
.navbar-menu
|
||||
display: none
|
||||
|
||||
.navbar-item,
|
||||
.navbar-link
|
||||
color: $navbar-item-color
|
||||
display: block
|
||||
line-height: 1.5
|
||||
padding: 0.5rem 0.75rem
|
||||
position: relative
|
||||
.icon
|
||||
&:only-child
|
||||
margin-left: -0.25rem
|
||||
margin-right: -0.25rem
|
||||
|
||||
a.navbar-item,
|
||||
.navbar-link
|
||||
cursor: pointer
|
||||
&:focus,
|
||||
&:focus-within,
|
||||
&:hover,
|
||||
&.is-active
|
||||
background-color: $navbar-item-hover-background-color
|
||||
color: $navbar-item-hover-color
|
||||
|
||||
.navbar-item
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
img
|
||||
max-height: $navbar-item-img-max-height
|
||||
&.has-dropdown
|
||||
padding: 0
|
||||
&.is-expanded
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
&.is-tab
|
||||
border-bottom: 1px solid transparent
|
||||
min-height: $navbar-height
|
||||
padding-bottom: calc(0.5rem - 1px)
|
||||
&:focus,
|
||||
&:hover
|
||||
background-color: $navbar-tab-hover-background-color
|
||||
border-bottom-color: $navbar-tab-hover-border-bottom-color
|
||||
&.is-active
|
||||
background-color: $navbar-tab-active-background-color
|
||||
border-bottom-color: $navbar-tab-active-border-bottom-color
|
||||
border-bottom-style: $navbar-tab-active-border-bottom-style
|
||||
border-bottom-width: $navbar-tab-active-border-bottom-width
|
||||
color: $navbar-tab-active-color
|
||||
padding-bottom: calc(0.5rem - #{$navbar-tab-active-border-bottom-width})
|
||||
|
||||
.navbar-content
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
|
||||
.navbar-link:not(.is-arrowless)
|
||||
+ltr-property("padding", 2.5em)
|
||||
&::after
|
||||
@extend %arrow
|
||||
border-color: $navbar-dropdown-arrow
|
||||
margin-top: -0.375em
|
||||
+ltr-position(1.125em)
|
||||
|
||||
.navbar-dropdown
|
||||
font-size: 0.875rem
|
||||
padding-bottom: 0.5rem
|
||||
padding-top: 0.5rem
|
||||
.navbar-item
|
||||
padding-left: 1.5rem
|
||||
padding-right: 1.5rem
|
||||
|
||||
.navbar-divider
|
||||
background-color: $navbar-divider-background-color
|
||||
border: none
|
||||
display: none
|
||||
height: $navbar-divider-height
|
||||
margin: 0.5rem 0
|
||||
|
||||
+until($navbar-breakpoint)
|
||||
.navbar > .container
|
||||
display: block
|
||||
.navbar-brand,
|
||||
.navbar-tabs
|
||||
.navbar-item
|
||||
align-items: center
|
||||
display: flex
|
||||
.navbar-link
|
||||
&::after
|
||||
display: none
|
||||
.navbar-menu
|
||||
background-color: $navbar-background-color
|
||||
box-shadow: 0 8px 16px bulmaRgba($scheme-invert, 0.1)
|
||||
padding: 0.5rem 0
|
||||
&.is-active
|
||||
display: block
|
||||
// Fixed navbar
|
||||
.navbar
|
||||
&.is-fixed-bottom-touch,
|
||||
&.is-fixed-top-touch
|
||||
+navbar-fixed
|
||||
&.is-fixed-bottom-touch
|
||||
bottom: 0
|
||||
&.has-shadow
|
||||
box-shadow: 0 -2px 3px bulmaRgba($scheme-invert, 0.1)
|
||||
&.is-fixed-top-touch
|
||||
top: 0
|
||||
&.is-fixed-top,
|
||||
&.is-fixed-top-touch
|
||||
.navbar-menu
|
||||
+overflow-touch
|
||||
max-height: calc(100vh - #{$navbar-height})
|
||||
overflow: auto
|
||||
html,
|
||||
body
|
||||
&.has-navbar-fixed-top-touch
|
||||
padding-top: $navbar-height
|
||||
&.has-navbar-fixed-bottom-touch
|
||||
padding-bottom: $navbar-height
|
||||
|
||||
+from($navbar-breakpoint)
|
||||
.navbar,
|
||||
.navbar-menu,
|
||||
.navbar-start,
|
||||
.navbar-end
|
||||
align-items: stretch
|
||||
display: flex
|
||||
.navbar
|
||||
min-height: $navbar-height
|
||||
&.is-spaced
|
||||
padding: $navbar-padding-vertical $navbar-padding-horizontal
|
||||
.navbar-start,
|
||||
.navbar-end
|
||||
align-items: center
|
||||
a.navbar-item,
|
||||
.navbar-link
|
||||
border-radius: $radius
|
||||
&.is-transparent
|
||||
a.navbar-item,
|
||||
.navbar-link
|
||||
&:focus,
|
||||
&:hover,
|
||||
&.is-active
|
||||
background-color: transparent !important
|
||||
.navbar-item.has-dropdown
|
||||
&.is-active,
|
||||
&.is-hoverable:focus,
|
||||
&.is-hoverable:focus-within,
|
||||
&.is-hoverable:hover
|
||||
.navbar-link
|
||||
background-color: transparent !important
|
||||
.navbar-dropdown
|
||||
a.navbar-item
|
||||
&:focus,
|
||||
&:hover
|
||||
background-color: $navbar-dropdown-item-hover-background-color
|
||||
color: $navbar-dropdown-item-hover-color
|
||||
&.is-active
|
||||
background-color: $navbar-dropdown-item-active-background-color
|
||||
color: $navbar-dropdown-item-active-color
|
||||
.navbar-burger
|
||||
display: none
|
||||
.navbar-item,
|
||||
.navbar-link
|
||||
align-items: center
|
||||
display: flex
|
||||
.navbar-item
|
||||
&.has-dropdown
|
||||
align-items: stretch
|
||||
&.has-dropdown-up
|
||||
.navbar-link::after
|
||||
transform: rotate(135deg) translate(0.25em, -0.25em)
|
||||
.navbar-dropdown
|
||||
border-bottom: $navbar-dropdown-border-top
|
||||
border-radius: $navbar-dropdown-radius $navbar-dropdown-radius 0 0
|
||||
border-top: none
|
||||
bottom: 100%
|
||||
box-shadow: 0 -8px 8px bulmaRgba($scheme-invert, 0.1)
|
||||
top: auto
|
||||
&.is-active,
|
||||
&.is-hoverable:focus,
|
||||
&.is-hoverable:focus-within,
|
||||
&.is-hoverable:hover
|
||||
.navbar-dropdown
|
||||
display: block
|
||||
.navbar.is-spaced &,
|
||||
&.is-boxed
|
||||
opacity: 1
|
||||
pointer-events: auto
|
||||
transform: translateY(0)
|
||||
.navbar-menu
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
.navbar-start
|
||||
justify-content: flex-start
|
||||
+ltr-property("margin", auto)
|
||||
.navbar-end
|
||||
justify-content: flex-end
|
||||
+ltr-property("margin", auto, false)
|
||||
.navbar-dropdown
|
||||
background-color: $navbar-dropdown-background-color
|
||||
border-bottom-left-radius: $navbar-dropdown-radius
|
||||
border-bottom-right-radius: $navbar-dropdown-radius
|
||||
border-top: $navbar-dropdown-border-top
|
||||
box-shadow: 0 8px 8px bulmaRgba($scheme-invert, 0.1)
|
||||
display: none
|
||||
font-size: 0.875rem
|
||||
+ltr-position(0, false)
|
||||
min-width: 100%
|
||||
position: absolute
|
||||
top: 100%
|
||||
z-index: $navbar-dropdown-z
|
||||
.navbar-item
|
||||
padding: 0.375rem 1rem
|
||||
white-space: nowrap
|
||||
a.navbar-item
|
||||
+ltr-property("padding", 3rem)
|
||||
&:focus,
|
||||
&:hover
|
||||
background-color: $navbar-dropdown-item-hover-background-color
|
||||
color: $navbar-dropdown-item-hover-color
|
||||
&.is-active
|
||||
background-color: $navbar-dropdown-item-active-background-color
|
||||
color: $navbar-dropdown-item-active-color
|
||||
.navbar.is-spaced &,
|
||||
&.is-boxed
|
||||
border-radius: $navbar-dropdown-boxed-radius
|
||||
border-top: none
|
||||
box-shadow: $navbar-dropdown-boxed-shadow
|
||||
display: block
|
||||
opacity: 0
|
||||
pointer-events: none
|
||||
top: calc(100% + (#{$navbar-dropdown-offset}))
|
||||
transform: translateY(-5px)
|
||||
transition-duration: $speed
|
||||
transition-property: opacity, transform
|
||||
&.is-right
|
||||
left: auto
|
||||
right: 0
|
||||
.navbar-divider
|
||||
display: block
|
||||
.navbar > .container,
|
||||
.container > .navbar
|
||||
.navbar-brand
|
||||
+ltr-property("margin", -.75rem, false)
|
||||
.navbar-menu
|
||||
+ltr-property("margin", -.75rem)
|
||||
// Fixed navbar
|
||||
.navbar
|
||||
&.is-fixed-bottom-desktop,
|
||||
&.is-fixed-top-desktop
|
||||
+navbar-fixed
|
||||
&.is-fixed-bottom-desktop
|
||||
bottom: 0
|
||||
&.has-shadow
|
||||
box-shadow: 0 -2px 3px bulmaRgba($scheme-invert, 0.1)
|
||||
&.is-fixed-top-desktop
|
||||
top: 0
|
||||
html,
|
||||
body
|
||||
&.has-navbar-fixed-top-desktop
|
||||
padding-top: $navbar-height
|
||||
&.has-navbar-fixed-bottom-desktop
|
||||
padding-bottom: $navbar-height
|
||||
&.has-spaced-navbar-fixed-top
|
||||
padding-top: $navbar-height + ($navbar-padding-vertical * 2)
|
||||
&.has-spaced-navbar-fixed-bottom
|
||||
padding-bottom: $navbar-height + ($navbar-padding-vertical * 2)
|
||||
// Hover/Active states
|
||||
a.navbar-item,
|
||||
.navbar-link
|
||||
&.is-active
|
||||
color: $navbar-item-active-color
|
||||
&.is-active:not(:focus):not(:hover)
|
||||
background-color: $navbar-item-active-background-color
|
||||
.navbar-item.has-dropdown
|
||||
&:focus,
|
||||
&:hover,
|
||||
&.is-active
|
||||
.navbar-link
|
||||
background-color: $navbar-item-hover-background-color
|
||||
|
||||
// Combination
|
||||
|
||||
.hero
|
||||
&.is-fullheight-with-navbar
|
||||
min-height: calc(100vh - #{$navbar-height})
|
150
static/css/sass/bulma/components/pagination.sass
Normal file
150
static/css/sass/bulma/components/pagination.sass
Normal file
@ -0,0 +1,150 @@
|
||||
$pagination-color: $text-strong !default
|
||||
$pagination-border-color: $border !default
|
||||
$pagination-margin: -0.25rem !default
|
||||
$pagination-min-width: $control-height !default
|
||||
|
||||
$pagination-item-font-size: 1em !default
|
||||
$pagination-item-margin: 0.25rem !default
|
||||
$pagination-item-padding-left: 0.5em !default
|
||||
$pagination-item-padding-right: 0.5em !default
|
||||
|
||||
$pagination-hover-color: $link-hover !default
|
||||
$pagination-hover-border-color: $link-hover-border !default
|
||||
|
||||
$pagination-focus-color: $link-focus !default
|
||||
$pagination-focus-border-color: $link-focus-border !default
|
||||
|
||||
$pagination-active-color: $link-active !default
|
||||
$pagination-active-border-color: $link-active-border !default
|
||||
|
||||
$pagination-disabled-color: $text-light !default
|
||||
$pagination-disabled-background-color: $border !default
|
||||
$pagination-disabled-border-color: $border !default
|
||||
|
||||
$pagination-current-color: $link-invert !default
|
||||
$pagination-current-background-color: $link !default
|
||||
$pagination-current-border-color: $link !default
|
||||
|
||||
$pagination-ellipsis-color: $grey-light !default
|
||||
|
||||
$pagination-shadow-inset: inset 0 1px 2px rgba($scheme-invert, 0.2)
|
||||
|
||||
.pagination
|
||||
@extend %block
|
||||
font-size: $size-normal
|
||||
margin: $pagination-margin
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
&.is-rounded
|
||||
.pagination-previous,
|
||||
.pagination-next
|
||||
padding-left: 1em
|
||||
padding-right: 1em
|
||||
border-radius: $radius-rounded
|
||||
.pagination-link
|
||||
border-radius: $radius-rounded
|
||||
|
||||
.pagination,
|
||||
.pagination-list
|
||||
align-items: center
|
||||
display: flex
|
||||
justify-content: center
|
||||
text-align: center
|
||||
|
||||
.pagination-previous,
|
||||
.pagination-next,
|
||||
.pagination-link,
|
||||
.pagination-ellipsis
|
||||
@extend %control
|
||||
@extend %unselectable
|
||||
font-size: $pagination-item-font-size
|
||||
justify-content: center
|
||||
margin: $pagination-item-margin
|
||||
padding-left: $pagination-item-padding-left
|
||||
padding-right: $pagination-item-padding-right
|
||||
text-align: center
|
||||
|
||||
.pagination-previous,
|
||||
.pagination-next,
|
||||
.pagination-link
|
||||
border-color: $pagination-border-color
|
||||
color: $pagination-color
|
||||
min-width: $pagination-min-width
|
||||
&:hover
|
||||
border-color: $pagination-hover-border-color
|
||||
color: $pagination-hover-color
|
||||
&:focus
|
||||
border-color: $pagination-focus-border-color
|
||||
&:active
|
||||
box-shadow: $pagination-shadow-inset
|
||||
&[disabled]
|
||||
background-color: $pagination-disabled-background-color
|
||||
border-color: $pagination-disabled-border-color
|
||||
box-shadow: none
|
||||
color: $pagination-disabled-color
|
||||
opacity: 0.5
|
||||
|
||||
.pagination-previous,
|
||||
.pagination-next
|
||||
padding-left: 0.75em
|
||||
padding-right: 0.75em
|
||||
white-space: nowrap
|
||||
|
||||
.pagination-link
|
||||
&.is-current
|
||||
background-color: $pagination-current-background-color
|
||||
border-color: $pagination-current-border-color
|
||||
color: $pagination-current-color
|
||||
|
||||
.pagination-ellipsis
|
||||
color: $pagination-ellipsis-color
|
||||
pointer-events: none
|
||||
|
||||
.pagination-list
|
||||
flex-wrap: wrap
|
||||
|
||||
+mobile
|
||||
.pagination
|
||||
flex-wrap: wrap
|
||||
.pagination-previous,
|
||||
.pagination-next
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
.pagination-list
|
||||
li
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
|
||||
+tablet
|
||||
.pagination-list
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
justify-content: flex-start
|
||||
order: 1
|
||||
.pagination-previous
|
||||
order: 2
|
||||
.pagination-next
|
||||
order: 3
|
||||
.pagination
|
||||
justify-content: space-between
|
||||
&.is-centered
|
||||
.pagination-previous
|
||||
order: 1
|
||||
.pagination-list
|
||||
justify-content: center
|
||||
order: 2
|
||||
.pagination-next
|
||||
order: 3
|
||||
&.is-right
|
||||
.pagination-previous
|
||||
order: 1
|
||||
.pagination-next
|
||||
order: 2
|
||||
.pagination-list
|
||||
justify-content: flex-end
|
||||
order: 3
|
119
static/css/sass/bulma/components/panel.sass
Normal file
119
static/css/sass/bulma/components/panel.sass
Normal file
@ -0,0 +1,119 @@
|
||||
$panel-margin: $block-spacing !default
|
||||
$panel-item-border: 1px solid $border-light !default
|
||||
$panel-radius: $radius-large !default
|
||||
$panel-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02) !default
|
||||
|
||||
$panel-heading-background-color: $border-light !default
|
||||
$panel-heading-color: $text-strong !default
|
||||
$panel-heading-line-height: 1.25 !default
|
||||
$panel-heading-padding: 0.75em 1em !default
|
||||
$panel-heading-radius: $radius !default
|
||||
$panel-heading-size: 1.25em !default
|
||||
$panel-heading-weight: $weight-bold !default
|
||||
|
||||
$panel-tabs-font-size: 0.875em !default
|
||||
$panel-tab-border-bottom: 1px solid $border !default
|
||||
$panel-tab-active-border-bottom-color: $link-active-border !default
|
||||
$panel-tab-active-color: $link-active !default
|
||||
|
||||
$panel-list-item-color: $text !default
|
||||
$panel-list-item-hover-color: $link !default
|
||||
|
||||
$panel-block-color: $text-strong !default
|
||||
$panel-block-hover-background-color: $background !default
|
||||
$panel-block-active-border-left-color: $link !default
|
||||
$panel-block-active-color: $link-active !default
|
||||
$panel-block-active-icon-color: $link !default
|
||||
|
||||
$panel-icon-color: $text-light !default
|
||||
$panel-colors: $colors !default
|
||||
|
||||
.panel
|
||||
border-radius: $panel-radius
|
||||
box-shadow: $panel-shadow
|
||||
font-size: $size-normal
|
||||
&:not(:last-child)
|
||||
margin-bottom: $panel-margin
|
||||
// Colors
|
||||
@each $name, $components in $panel-colors
|
||||
$color: nth($components, 1)
|
||||
$color-invert: nth($components, 2)
|
||||
&.is-#{$name}
|
||||
.panel-heading
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
.panel-tabs a.is-active
|
||||
border-bottom-color: $color
|
||||
.panel-block.is-active .panel-icon
|
||||
color: $color
|
||||
|
||||
.panel-tabs,
|
||||
.panel-block
|
||||
&:not(:last-child)
|
||||
border-bottom: $panel-item-border
|
||||
|
||||
.panel-heading
|
||||
background-color: $panel-heading-background-color
|
||||
border-radius: $panel-radius $panel-radius 0 0
|
||||
color: $panel-heading-color
|
||||
font-size: $panel-heading-size
|
||||
font-weight: $panel-heading-weight
|
||||
line-height: $panel-heading-line-height
|
||||
padding: $panel-heading-padding
|
||||
|
||||
.panel-tabs
|
||||
align-items: flex-end
|
||||
display: flex
|
||||
font-size: $panel-tabs-font-size
|
||||
justify-content: center
|
||||
a
|
||||
border-bottom: $panel-tab-border-bottom
|
||||
margin-bottom: -1px
|
||||
padding: 0.5em
|
||||
// Modifiers
|
||||
&.is-active
|
||||
border-bottom-color: $panel-tab-active-border-bottom-color
|
||||
color: $panel-tab-active-color
|
||||
|
||||
.panel-list
|
||||
a
|
||||
color: $panel-list-item-color
|
||||
&:hover
|
||||
color: $panel-list-item-hover-color
|
||||
|
||||
.panel-block
|
||||
align-items: center
|
||||
color: $panel-block-color
|
||||
display: flex
|
||||
justify-content: flex-start
|
||||
padding: 0.5em 0.75em
|
||||
input[type="checkbox"]
|
||||
+ltr-property("margin", 0.75em)
|
||||
& > .control
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
width: 100%
|
||||
&.is-wrapped
|
||||
flex-wrap: wrap
|
||||
&.is-active
|
||||
border-left-color: $panel-block-active-border-left-color
|
||||
color: $panel-block-active-color
|
||||
.panel-icon
|
||||
color: $panel-block-active-icon-color
|
||||
&:last-child
|
||||
border-bottom-left-radius: $panel-radius
|
||||
border-bottom-right-radius: $panel-radius
|
||||
|
||||
a.panel-block,
|
||||
label.panel-block
|
||||
cursor: pointer
|
||||
&:hover
|
||||
background-color: $panel-block-hover-background-color
|
||||
|
||||
.panel-icon
|
||||
+fa(14px, 1em)
|
||||
color: $panel-icon-color
|
||||
+ltr-property("margin", 0.75em)
|
||||
.fa
|
||||
font-size: inherit
|
||||
line-height: inherit
|
174
static/css/sass/bulma/components/tabs.sass
Normal file
174
static/css/sass/bulma/components/tabs.sass
Normal file
@ -0,0 +1,174 @@
|
||||
$tabs-border-bottom-color: $border !default
|
||||
$tabs-border-bottom-style: solid !default
|
||||
$tabs-border-bottom-width: 1px !default
|
||||
$tabs-link-color: $text !default
|
||||
$tabs-link-hover-border-bottom-color: $text-strong !default
|
||||
$tabs-link-hover-color: $text-strong !default
|
||||
$tabs-link-active-border-bottom-color: $link !default
|
||||
$tabs-link-active-color: $link !default
|
||||
$tabs-link-padding: 0.5em 1em !default
|
||||
|
||||
$tabs-boxed-link-radius: $radius !default
|
||||
$tabs-boxed-link-hover-background-color: $background !default
|
||||
$tabs-boxed-link-hover-border-bottom-color: $border !default
|
||||
|
||||
$tabs-boxed-link-active-background-color: $scheme-main !default
|
||||
$tabs-boxed-link-active-border-color: $border !default
|
||||
$tabs-boxed-link-active-border-bottom-color: transparent !default
|
||||
|
||||
$tabs-toggle-link-border-color: $border !default
|
||||
$tabs-toggle-link-border-style: solid !default
|
||||
$tabs-toggle-link-border-width: 1px !default
|
||||
$tabs-toggle-link-hover-background-color: $background !default
|
||||
$tabs-toggle-link-hover-border-color: $border-hover !default
|
||||
$tabs-toggle-link-radius: $radius !default
|
||||
$tabs-toggle-link-active-background-color: $link !default
|
||||
$tabs-toggle-link-active-border-color: $link !default
|
||||
$tabs-toggle-link-active-color: $link-invert !default
|
||||
|
||||
.tabs
|
||||
@extend %block
|
||||
+overflow-touch
|
||||
@extend %unselectable
|
||||
align-items: stretch
|
||||
display: flex
|
||||
font-size: $size-normal
|
||||
justify-content: space-between
|
||||
overflow: hidden
|
||||
overflow-x: auto
|
||||
white-space: nowrap
|
||||
a
|
||||
align-items: center
|
||||
border-bottom-color: $tabs-border-bottom-color
|
||||
border-bottom-style: $tabs-border-bottom-style
|
||||
border-bottom-width: $tabs-border-bottom-width
|
||||
color: $tabs-link-color
|
||||
display: flex
|
||||
justify-content: center
|
||||
margin-bottom: -#{$tabs-border-bottom-width}
|
||||
padding: $tabs-link-padding
|
||||
vertical-align: top
|
||||
&:hover
|
||||
border-bottom-color: $tabs-link-hover-border-bottom-color
|
||||
color: $tabs-link-hover-color
|
||||
li
|
||||
display: block
|
||||
&.is-active
|
||||
a
|
||||
border-bottom-color: $tabs-link-active-border-bottom-color
|
||||
color: $tabs-link-active-color
|
||||
ul
|
||||
align-items: center
|
||||
border-bottom-color: $tabs-border-bottom-color
|
||||
border-bottom-style: $tabs-border-bottom-style
|
||||
border-bottom-width: $tabs-border-bottom-width
|
||||
display: flex
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
justify-content: flex-start
|
||||
&.is-left
|
||||
padding-right: 0.75em
|
||||
&.is-center
|
||||
flex: none
|
||||
justify-content: center
|
||||
padding-left: 0.75em
|
||||
padding-right: 0.75em
|
||||
&.is-right
|
||||
justify-content: flex-end
|
||||
padding-left: 0.75em
|
||||
.icon
|
||||
&:first-child
|
||||
+ltr-property("margin", 0.5em)
|
||||
&:last-child
|
||||
+ltr-property("margin", 0.5em, false)
|
||||
// Alignment
|
||||
&.is-centered
|
||||
ul
|
||||
justify-content: center
|
||||
&.is-right
|
||||
ul
|
||||
justify-content: flex-end
|
||||
// Styles
|
||||
&.is-boxed
|
||||
a
|
||||
border: 1px solid transparent
|
||||
+ltr
|
||||
border-radius: $tabs-boxed-link-radius $tabs-boxed-link-radius 0 0
|
||||
+rtl
|
||||
border-radius: 0 0 $tabs-boxed-link-radius $tabs-boxed-link-radius
|
||||
&:hover
|
||||
background-color: $tabs-boxed-link-hover-background-color
|
||||
border-bottom-color: $tabs-boxed-link-hover-border-bottom-color
|
||||
li
|
||||
&.is-active
|
||||
a
|
||||
background-color: $tabs-boxed-link-active-background-color
|
||||
border-color: $tabs-boxed-link-active-border-color
|
||||
border-bottom-color: $tabs-boxed-link-active-border-bottom-color !important
|
||||
&.is-fullwidth
|
||||
li
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
&.is-toggle
|
||||
a
|
||||
border-color: $tabs-toggle-link-border-color
|
||||
border-style: $tabs-toggle-link-border-style
|
||||
border-width: $tabs-toggle-link-border-width
|
||||
margin-bottom: 0
|
||||
position: relative
|
||||
&:hover
|
||||
background-color: $tabs-toggle-link-hover-background-color
|
||||
border-color: $tabs-toggle-link-hover-border-color
|
||||
z-index: 2
|
||||
li
|
||||
& + li
|
||||
+ltr-property("margin", -#{$tabs-toggle-link-border-width}, false)
|
||||
&:first-child a
|
||||
+ltr
|
||||
border-top-left-radius: $tabs-toggle-link-radius
|
||||
border-bottom-left-radius: $tabs-toggle-link-radius
|
||||
+rtl
|
||||
border-top-right-radius: $tabs-toggle-link-radius
|
||||
border-bottom-right-radius: $tabs-toggle-link-radius
|
||||
&:last-child a
|
||||
+ltr
|
||||
border-top-right-radius: $tabs-toggle-link-radius
|
||||
border-bottom-right-radius: $tabs-toggle-link-radius
|
||||
+rtl
|
||||
border-top-left-radius: $tabs-toggle-link-radius
|
||||
border-bottom-left-radius: $tabs-toggle-link-radius
|
||||
&.is-active
|
||||
a
|
||||
background-color: $tabs-toggle-link-active-background-color
|
||||
border-color: $tabs-toggle-link-active-border-color
|
||||
color: $tabs-toggle-link-active-color
|
||||
z-index: 1
|
||||
ul
|
||||
border-bottom: none
|
||||
&.is-toggle-rounded
|
||||
li
|
||||
&:first-child a
|
||||
+ltr
|
||||
border-bottom-left-radius: $radius-rounded
|
||||
border-top-left-radius: $radius-rounded
|
||||
padding-left: 1.25em
|
||||
+rtl
|
||||
border-bottom-right-radius: $radius-rounded
|
||||
border-top-right-radius: $radius-rounded
|
||||
padding-right: 1.25em
|
||||
&:last-child a
|
||||
+ltr
|
||||
border-bottom-right-radius: $radius-rounded
|
||||
border-top-right-radius: $radius-rounded
|
||||
padding-right: 1.25em
|
||||
+rtl
|
||||
border-bottom-left-radius: $radius-rounded
|
||||
border-top-left-radius: $radius-rounded
|
||||
padding-left: 1.25em
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
16
static/css/sass/bulma/elements/_all.sass
Normal file
16
static/css/sass/bulma/elements/_all.sass
Normal file
@ -0,0 +1,16 @@
|
||||
/* Bulma Elements */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "box.sass"
|
||||
@import "button.sass"
|
||||
@import "container.sass"
|
||||
@import "content.sass"
|
||||
@import "icon.sass"
|
||||
@import "image.sass"
|
||||
@import "notification.sass"
|
||||
@import "progress.sass"
|
||||
@import "table.sass"
|
||||
@import "tag.sass"
|
||||
@import "title.sass"
|
||||
|
||||
@import "other.sass"
|
24
static/css/sass/bulma/elements/box.sass
Normal file
24
static/css/sass/bulma/elements/box.sass
Normal file
@ -0,0 +1,24 @@
|
||||
$box-color: $text !default
|
||||
$box-background-color: $scheme-main !default
|
||||
$box-radius: $radius-large !default
|
||||
$box-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0px 0 1px rgba($scheme-invert, 0.02) !default
|
||||
$box-padding: 1.25rem !default
|
||||
|
||||
$box-link-hover-shadow: 0 0.5em 1em -0.125em rgba($scheme-invert, 0.1), 0 0 0 1px $link !default
|
||||
$box-link-active-shadow: inset 0 1px 2px rgba($scheme-invert, 0.2), 0 0 0 1px $link !default
|
||||
|
||||
.box
|
||||
@extend %block
|
||||
background-color: $box-background-color
|
||||
border-radius: $box-radius
|
||||
box-shadow: $box-shadow
|
||||
color: $box-color
|
||||
display: block
|
||||
padding: $box-padding
|
||||
|
||||
a.box
|
||||
&:hover,
|
||||
&:focus
|
||||
box-shadow: $box-link-hover-shadow
|
||||
&:active
|
||||
box-shadow: $box-link-active-shadow
|
325
static/css/sass/bulma/elements/button.sass
Normal file
325
static/css/sass/bulma/elements/button.sass
Normal file
@ -0,0 +1,325 @@
|
||||
$button-color: $text-strong !default
|
||||
$button-background-color: $scheme-main !default
|
||||
$button-family: false !default
|
||||
|
||||
$button-border-color: $border !default
|
||||
$button-border-width: $control-border-width !default
|
||||
|
||||
$button-padding-vertical: calc(0.5em - #{$button-border-width}) !default
|
||||
$button-padding-horizontal: 1em !default
|
||||
|
||||
$button-hover-color: $link-hover !default
|
||||
$button-hover-border-color: $link-hover-border !default
|
||||
|
||||
$button-focus-color: $link-focus !default
|
||||
$button-focus-border-color: $link-focus-border !default
|
||||
$button-focus-box-shadow-size: 0 0 0 0.125em !default
|
||||
$button-focus-box-shadow-color: bulmaRgba($link, 0.25) !default
|
||||
|
||||
$button-active-color: $link-active !default
|
||||
$button-active-border-color: $link-active-border !default
|
||||
|
||||
$button-text-color: $text !default
|
||||
$button-text-decoration: underline !default
|
||||
$button-text-hover-background-color: $background !default
|
||||
$button-text-hover-color: $text-strong !default
|
||||
|
||||
$button-disabled-background-color: $scheme-main !default
|
||||
$button-disabled-border-color: $border !default
|
||||
$button-disabled-shadow: none !default
|
||||
$button-disabled-opacity: 0.5 !default
|
||||
|
||||
$button-static-color: $text-light !default
|
||||
$button-static-background-color: $scheme-main-ter !default
|
||||
$button-static-border-color: $border !default
|
||||
|
||||
$button-colors: $colors !default
|
||||
|
||||
// The button sizes use mixins so they can be used at different breakpoints
|
||||
=button-small
|
||||
border-radius: $radius-small
|
||||
font-size: $size-small
|
||||
=button-normal
|
||||
font-size: $size-normal
|
||||
=button-medium
|
||||
font-size: $size-medium
|
||||
=button-large
|
||||
font-size: $size-large
|
||||
|
||||
.button
|
||||
@extend %control
|
||||
@extend %unselectable
|
||||
background-color: $button-background-color
|
||||
border-color: $button-border-color
|
||||
border-width: $button-border-width
|
||||
color: $button-color
|
||||
cursor: pointer
|
||||
@if $button-family
|
||||
font-family: $button-family
|
||||
justify-content: center
|
||||
padding-bottom: $button-padding-vertical
|
||||
padding-left: $button-padding-horizontal
|
||||
padding-right: $button-padding-horizontal
|
||||
padding-top: $button-padding-vertical
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
strong
|
||||
color: inherit
|
||||
.icon
|
||||
&,
|
||||
&.is-small,
|
||||
&.is-medium,
|
||||
&.is-large
|
||||
height: 1.5em
|
||||
width: 1.5em
|
||||
&:first-child:not(:last-child)
|
||||
+ltr-property("margin", calc(#{-1 / 2 * $button-padding-horizontal} - #{$button-border-width}), false)
|
||||
+ltr-property("margin", $button-padding-horizontal / 4)
|
||||
&:last-child:not(:first-child)
|
||||
+ltr-property("margin", $button-padding-horizontal / 4, false)
|
||||
+ltr-property("margin", calc(#{-1 / 2 * $button-padding-horizontal} - #{$button-border-width}))
|
||||
&:first-child:last-child
|
||||
margin-left: calc(#{-1 / 2 * $button-padding-horizontal} - #{$button-border-width})
|
||||
margin-right: calc(#{-1 / 2 * $button-padding-horizontal} - #{$button-border-width})
|
||||
// States
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
border-color: $button-hover-border-color
|
||||
color: $button-hover-color
|
||||
&:focus,
|
||||
&.is-focused
|
||||
border-color: $button-focus-border-color
|
||||
color: $button-focus-color
|
||||
&:not(:active)
|
||||
box-shadow: $button-focus-box-shadow-size $button-focus-box-shadow-color
|
||||
&:active,
|
||||
&.is-active
|
||||
border-color: $button-active-border-color
|
||||
color: $button-active-color
|
||||
// Colors
|
||||
&.is-text
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
color: $button-text-color
|
||||
text-decoration: $button-text-decoration
|
||||
&:hover,
|
||||
&.is-hovered,
|
||||
&:focus,
|
||||
&.is-focused
|
||||
background-color: $button-text-hover-background-color
|
||||
color: $button-text-hover-color
|
||||
&:active,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($button-text-hover-background-color, 5%)
|
||||
color: $button-text-hover-color
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
@each $name, $pair in $button-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
background-color: bulmaDarken($color, 2.5%)
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&:focus,
|
||||
&.is-focused
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&:not(:active)
|
||||
box-shadow: $button-focus-box-shadow-size bulmaRgba($color, 0.25)
|
||||
&:active,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: $color
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
&.is-inverted
|
||||
background-color: $color-invert
|
||||
color: $color
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
background-color: bulmaDarken($color-invert, 5%)
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: $color-invert
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
color: $color
|
||||
&.is-loading
|
||||
&::after
|
||||
border-color: transparent transparent $color-invert $color-invert !important
|
||||
&.is-outlined
|
||||
background-color: transparent
|
||||
border-color: $color
|
||||
color: $color
|
||||
&:hover,
|
||||
&.is-hovered,
|
||||
&:focus,
|
||||
&.is-focused
|
||||
background-color: $color
|
||||
border-color: $color
|
||||
color: $color-invert
|
||||
&.is-loading
|
||||
&::after
|
||||
border-color: transparent transparent $color $color !important
|
||||
&:hover,
|
||||
&.is-hovered,
|
||||
&:focus,
|
||||
&.is-focused
|
||||
&::after
|
||||
border-color: transparent transparent $color-invert $color-invert !important
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: transparent
|
||||
border-color: $color
|
||||
box-shadow: none
|
||||
color: $color
|
||||
&.is-inverted.is-outlined
|
||||
background-color: transparent
|
||||
border-color: $color-invert
|
||||
color: $color-invert
|
||||
&:hover,
|
||||
&.is-hovered,
|
||||
&:focus,
|
||||
&.is-focused
|
||||
background-color: $color-invert
|
||||
color: $color
|
||||
&.is-loading
|
||||
&:hover,
|
||||
&.is-hovered,
|
||||
&:focus,
|
||||
&.is-focused
|
||||
&::after
|
||||
border-color: transparent transparent $color $color !important
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: transparent
|
||||
border-color: $color-invert
|
||||
box-shadow: none
|
||||
color: $color-invert
|
||||
// If light and dark colors are provided
|
||||
@if length($pair) >= 4
|
||||
$color-light: nth($pair, 3)
|
||||
$color-dark: nth($pair, 4)
|
||||
&.is-light
|
||||
background-color: $color-light
|
||||
color: $color-dark
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
background-color: bulmaDarken($color-light, 2.5%)
|
||||
border-color: transparent
|
||||
color: $color-dark
|
||||
&:active,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($color-light, 5%)
|
||||
border-color: transparent
|
||||
color: $color-dark
|
||||
// Sizes
|
||||
&.is-small
|
||||
+button-small
|
||||
&.is-normal
|
||||
+button-normal
|
||||
&.is-medium
|
||||
+button-medium
|
||||
&.is-large
|
||||
+button-large
|
||||
// Modifiers
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: $button-disabled-background-color
|
||||
border-color: $button-disabled-border-color
|
||||
box-shadow: $button-disabled-shadow
|
||||
opacity: $button-disabled-opacity
|
||||
&.is-fullwidth
|
||||
display: flex
|
||||
width: 100%
|
||||
&.is-loading
|
||||
color: transparent !important
|
||||
pointer-events: none
|
||||
&::after
|
||||
@extend %loader
|
||||
+center(1em)
|
||||
position: absolute !important
|
||||
&.is-static
|
||||
background-color: $button-static-background-color
|
||||
border-color: $button-static-border-color
|
||||
color: $button-static-color
|
||||
box-shadow: none
|
||||
pointer-events: none
|
||||
&.is-rounded
|
||||
border-radius: $radius-rounded
|
||||
padding-left: calc(#{$button-padding-horizontal} + 0.25em)
|
||||
padding-right: calc(#{$button-padding-horizontal} + 0.25em)
|
||||
|
||||
.buttons
|
||||
align-items: center
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
justify-content: flex-start
|
||||
.button
|
||||
margin-bottom: 0.5rem
|
||||
&:not(:last-child):not(.is-fullwidth)
|
||||
+ltr-property("margin", 0.5rem)
|
||||
&:last-child
|
||||
margin-bottom: -0.5rem
|
||||
&:not(:last-child)
|
||||
margin-bottom: 1rem
|
||||
// Sizes
|
||||
&.are-small
|
||||
.button:not(.is-normal):not(.is-medium):not(.is-large)
|
||||
+button-small
|
||||
&.are-medium
|
||||
.button:not(.is-small):not(.is-normal):not(.is-large)
|
||||
+button-medium
|
||||
&.are-large
|
||||
.button:not(.is-small):not(.is-normal):not(.is-medium)
|
||||
+button-large
|
||||
&.has-addons
|
||||
.button
|
||||
&:not(:first-child)
|
||||
border-bottom-left-radius: 0
|
||||
border-top-left-radius: 0
|
||||
&:not(:last-child)
|
||||
border-bottom-right-radius: 0
|
||||
border-top-right-radius: 0
|
||||
+ltr-property("margin", -1px)
|
||||
&:last-child
|
||||
+ltr-property("margin", 0)
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
z-index: 2
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active,
|
||||
&.is-selected
|
||||
z-index: 3
|
||||
&:hover
|
||||
z-index: 4
|
||||
&.is-expanded
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
&.is-centered
|
||||
justify-content: center
|
||||
&:not(.has-addons)
|
||||
.button:not(.is-fullwidth)
|
||||
margin-left: 0.25rem
|
||||
margin-right: 0.25rem
|
||||
&.is-right
|
||||
justify-content: flex-end
|
||||
&:not(.has-addons)
|
||||
.button:not(.is-fullwidth)
|
||||
margin-left: 0.25rem
|
||||
margin-right: 0.25rem
|
27
static/css/sass/bulma/elements/container.sass
Normal file
27
static/css/sass/bulma/elements/container.sass
Normal file
@ -0,0 +1,27 @@
|
||||
$container-offset: (2 * $gap) !default
|
||||
$container-max-width: $fullhd !default
|
||||
|
||||
.container
|
||||
flex-grow: 1
|
||||
margin: 0 auto
|
||||
position: relative
|
||||
width: auto
|
||||
&.is-fluid
|
||||
max-width: none !important
|
||||
padding-left: $gap
|
||||
padding-right: $gap
|
||||
width: 100%
|
||||
+desktop
|
||||
max-width: $desktop - $container-offset
|
||||
+until-widescreen
|
||||
&.is-widescreen:not(.is-max-desktop)
|
||||
max-width: min($widescreen, $container-max-width) - $container-offset
|
||||
+until-fullhd
|
||||
&.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen)
|
||||
max-width: min($fullhd, $container-max-width) - $container-offset
|
||||
+widescreen
|
||||
&:not(.is-max-desktop)
|
||||
max-width: min($widescreen, $container-max-width) - $container-offset
|
||||
+fullhd
|
||||
&:not(.is-max-desktop):not(.is-max-widescreen)
|
||||
max-width: min($fullhd, $container-max-width) - $container-offset
|
155
static/css/sass/bulma/elements/content.sass
Normal file
155
static/css/sass/bulma/elements/content.sass
Normal file
@ -0,0 +1,155 @@
|
||||
$content-heading-color: $text-strong !default
|
||||
$content-heading-weight: $weight-semibold !default
|
||||
$content-heading-line-height: 1.125 !default
|
||||
|
||||
$content-blockquote-background-color: $background !default
|
||||
$content-blockquote-border-left: 5px solid $border !default
|
||||
$content-blockquote-padding: 1.25em 1.5em !default
|
||||
|
||||
$content-pre-padding: 1.25em 1.5em !default
|
||||
|
||||
$content-table-cell-border: 1px solid $border !default
|
||||
$content-table-cell-border-width: 0 0 1px !default
|
||||
$content-table-cell-padding: 0.5em 0.75em !default
|
||||
$content-table-cell-heading-color: $text-strong !default
|
||||
$content-table-head-cell-border-width: 0 0 2px !default
|
||||
$content-table-head-cell-color: $text-strong !default
|
||||
$content-table-foot-cell-border-width: 2px 0 0 !default
|
||||
$content-table-foot-cell-color: $text-strong !default
|
||||
|
||||
.content
|
||||
@extend %block
|
||||
// Inline
|
||||
li + li
|
||||
margin-top: 0.25em
|
||||
// Block
|
||||
p,
|
||||
dl,
|
||||
ol,
|
||||
ul,
|
||||
blockquote,
|
||||
pre,
|
||||
table
|
||||
&:not(:last-child)
|
||||
margin-bottom: 1em
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
color: $content-heading-color
|
||||
font-weight: $content-heading-weight
|
||||
line-height: $content-heading-line-height
|
||||
h1
|
||||
font-size: 2em
|
||||
margin-bottom: 0.5em
|
||||
&:not(:first-child)
|
||||
margin-top: 1em
|
||||
h2
|
||||
font-size: 1.75em
|
||||
margin-bottom: 0.5714em
|
||||
&:not(:first-child)
|
||||
margin-top: 1.1428em
|
||||
h3
|
||||
font-size: 1.5em
|
||||
margin-bottom: 0.6666em
|
||||
&:not(:first-child)
|
||||
margin-top: 1.3333em
|
||||
h4
|
||||
font-size: 1.25em
|
||||
margin-bottom: 0.8em
|
||||
h5
|
||||
font-size: 1.125em
|
||||
margin-bottom: 0.8888em
|
||||
h6
|
||||
font-size: 1em
|
||||
margin-bottom: 1em
|
||||
blockquote
|
||||
background-color: $content-blockquote-background-color
|
||||
+ltr-property("border", $content-blockquote-border-left, false)
|
||||
padding: $content-blockquote-padding
|
||||
ol
|
||||
list-style-position: outside
|
||||
+ltr-property("margin", 2em, false)
|
||||
margin-top: 1em
|
||||
&:not([type])
|
||||
list-style-type: decimal
|
||||
&.is-lower-alpha
|
||||
list-style-type: lower-alpha
|
||||
&.is-lower-roman
|
||||
list-style-type: lower-roman
|
||||
&.is-upper-alpha
|
||||
list-style-type: upper-alpha
|
||||
&.is-upper-roman
|
||||
list-style-type: upper-roman
|
||||
ul
|
||||
list-style: disc outside
|
||||
+ltr-property("margin", 2em, false)
|
||||
margin-top: 1em
|
||||
ul
|
||||
list-style-type: circle
|
||||
margin-top: 0.5em
|
||||
ul
|
||||
list-style-type: square
|
||||
dd
|
||||
+ltr-property("margin", 2em, false)
|
||||
figure
|
||||
margin-left: 2em
|
||||
margin-right: 2em
|
||||
text-align: center
|
||||
&:not(:first-child)
|
||||
margin-top: 2em
|
||||
&:not(:last-child)
|
||||
margin-bottom: 2em
|
||||
img
|
||||
display: inline-block
|
||||
figcaption
|
||||
font-style: italic
|
||||
pre
|
||||
+overflow-touch
|
||||
overflow-x: auto
|
||||
padding: $content-pre-padding
|
||||
white-space: pre
|
||||
word-wrap: normal
|
||||
sup,
|
||||
sub
|
||||
font-size: 75%
|
||||
table
|
||||
width: 100%
|
||||
td,
|
||||
th
|
||||
border: $content-table-cell-border
|
||||
border-width: $content-table-cell-border-width
|
||||
padding: $content-table-cell-padding
|
||||
vertical-align: top
|
||||
th
|
||||
color: $content-table-cell-heading-color
|
||||
&:not([align])
|
||||
text-align: inherit
|
||||
thead
|
||||
td,
|
||||
th
|
||||
border-width: $content-table-head-cell-border-width
|
||||
color: $content-table-head-cell-color
|
||||
tfoot
|
||||
td,
|
||||
th
|
||||
border-width: $content-table-foot-cell-border-width
|
||||
color: $content-table-foot-cell-color
|
||||
tbody
|
||||
tr
|
||||
&:last-child
|
||||
td,
|
||||
th
|
||||
border-bottom-width: 0
|
||||
.tabs
|
||||
li + li
|
||||
margin-top: 0
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
1
static/css/sass/bulma/elements/form.sass
Normal file
1
static/css/sass/bulma/elements/form.sass
Normal file
@ -0,0 +1 @@
|
||||
@warn "The form.sass file is DEPRECATED. It has moved into its own /form folder. Please import sass/form/_all instead."
|
21
static/css/sass/bulma/elements/icon.sass
Normal file
21
static/css/sass/bulma/elements/icon.sass
Normal file
@ -0,0 +1,21 @@
|
||||
$icon-dimensions: 1.5rem !default
|
||||
$icon-dimensions-small: 1rem !default
|
||||
$icon-dimensions-medium: 2rem !default
|
||||
$icon-dimensions-large: 3rem !default
|
||||
|
||||
.icon
|
||||
align-items: center
|
||||
display: inline-flex
|
||||
justify-content: center
|
||||
height: $icon-dimensions
|
||||
width: $icon-dimensions
|
||||
// Sizes
|
||||
&.is-small
|
||||
height: $icon-dimensions-small
|
||||
width: $icon-dimensions-small
|
||||
&.is-medium
|
||||
height: $icon-dimensions-medium
|
||||
width: $icon-dimensions-medium
|
||||
&.is-large
|
||||
height: $icon-dimensions-large
|
||||
width: $icon-dimensions-large
|
71
static/css/sass/bulma/elements/image.sass
Normal file
71
static/css/sass/bulma/elements/image.sass
Normal file
@ -0,0 +1,71 @@
|
||||
$dimensions: 16 24 32 48 64 96 128 !default
|
||||
|
||||
.image
|
||||
display: block
|
||||
position: relative
|
||||
img
|
||||
display: block
|
||||
height: auto
|
||||
width: 100%
|
||||
&.is-rounded
|
||||
border-radius: $radius-rounded
|
||||
&.is-fullwidth
|
||||
width: 100%
|
||||
// Ratio
|
||||
&.is-square,
|
||||
&.is-1by1,
|
||||
&.is-5by4,
|
||||
&.is-4by3,
|
||||
&.is-3by2,
|
||||
&.is-5by3,
|
||||
&.is-16by9,
|
||||
&.is-2by1,
|
||||
&.is-3by1,
|
||||
&.is-4by5,
|
||||
&.is-3by4,
|
||||
&.is-2by3,
|
||||
&.is-3by5,
|
||||
&.is-9by16,
|
||||
&.is-1by2,
|
||||
&.is-1by3
|
||||
img,
|
||||
.has-ratio
|
||||
@extend %overlay
|
||||
height: 100%
|
||||
width: 100%
|
||||
&.is-square,
|
||||
&.is-1by1
|
||||
padding-top: 100%
|
||||
&.is-5by4
|
||||
padding-top: 80%
|
||||
&.is-4by3
|
||||
padding-top: 75%
|
||||
&.is-3by2
|
||||
padding-top: 66.6666%
|
||||
&.is-5by3
|
||||
padding-top: 60%
|
||||
&.is-16by9
|
||||
padding-top: 56.25%
|
||||
&.is-2by1
|
||||
padding-top: 50%
|
||||
&.is-3by1
|
||||
padding-top: 33.3333%
|
||||
&.is-4by5
|
||||
padding-top: 125%
|
||||
&.is-3by4
|
||||
padding-top: 133.3333%
|
||||
&.is-2by3
|
||||
padding-top: 150%
|
||||
&.is-3by5
|
||||
padding-top: 166.6666%
|
||||
&.is-9by16
|
||||
padding-top: 177.7777%
|
||||
&.is-1by2
|
||||
padding-top: 200%
|
||||
&.is-1by3
|
||||
padding-top: 300%
|
||||
// Sizes
|
||||
@each $dimension in $dimensions
|
||||
&.is-#{$dimension}x#{$dimension}
|
||||
height: $dimension * 1px
|
||||
width: $dimension * 1px
|
50
static/css/sass/bulma/elements/notification.sass
Normal file
50
static/css/sass/bulma/elements/notification.sass
Normal file
@ -0,0 +1,50 @@
|
||||
$notification-background-color: $background !default
|
||||
$notification-code-background-color: $scheme-main !default
|
||||
$notification-radius: $radius !default
|
||||
$notification-padding: 1.25rem 2.5rem 1.25rem 1.5rem !default
|
||||
$notification-padding-ltr: 1.25rem 2.5rem 1.25rem 1.5rem !default
|
||||
$notification-padding-rtl: 1.25rem 1.5rem 1.25rem 2.5rem !default
|
||||
|
||||
$notification-colors: $colors !default
|
||||
|
||||
.notification
|
||||
@extend %block
|
||||
background-color: $notification-background-color
|
||||
border-radius: $notification-radius
|
||||
position: relative
|
||||
+ltr
|
||||
padding: $notification-padding-ltr
|
||||
+rtl
|
||||
padding: $notification-padding-rtl
|
||||
a:not(.button):not(.dropdown-item)
|
||||
color: currentColor
|
||||
text-decoration: underline
|
||||
strong
|
||||
color: currentColor
|
||||
code,
|
||||
pre
|
||||
background: $notification-code-background-color
|
||||
pre code
|
||||
background: transparent
|
||||
& > .delete
|
||||
+ltr-position(0.5rem)
|
||||
position: absolute
|
||||
top: 0.5rem
|
||||
.title,
|
||||
.subtitle,
|
||||
.content
|
||||
color: currentColor
|
||||
// Colors
|
||||
@each $name, $pair in $notification-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
// If light and dark colors are provided
|
||||
@if length($pair) >= 4
|
||||
$color-light: nth($pair, 3)
|
||||
$color-dark: nth($pair, 4)
|
||||
&.is-light
|
||||
background-color: $color-light
|
||||
color: $color-dark
|
39
static/css/sass/bulma/elements/other.sass
Normal file
39
static/css/sass/bulma/elements/other.sass
Normal file
@ -0,0 +1,39 @@
|
||||
.block
|
||||
@extend %block
|
||||
|
||||
.delete
|
||||
@extend %delete
|
||||
|
||||
.heading
|
||||
display: block
|
||||
font-size: 11px
|
||||
letter-spacing: 1px
|
||||
margin-bottom: 5px
|
||||
text-transform: uppercase
|
||||
|
||||
.highlight
|
||||
@extend %block
|
||||
font-weight: $weight-normal
|
||||
max-width: 100%
|
||||
overflow: hidden
|
||||
padding: 0
|
||||
pre
|
||||
overflow: auto
|
||||
max-width: 100%
|
||||
|
||||
.loader
|
||||
@extend %loader
|
||||
|
||||
.number
|
||||
align-items: center
|
||||
background-color: $background
|
||||
border-radius: $radius-rounded
|
||||
display: inline-flex
|
||||
font-size: $size-medium
|
||||
height: 2em
|
||||
justify-content: center
|
||||
margin-right: 1.5rem
|
||||
min-width: 2.5em
|
||||
padding: 0.25rem 0.5rem
|
||||
text-align: center
|
||||
vertical-align: top
|
71
static/css/sass/bulma/elements/progress.sass
Normal file
71
static/css/sass/bulma/elements/progress.sass
Normal file
@ -0,0 +1,71 @@
|
||||
$progress-bar-background-color: $border-light !default
|
||||
$progress-value-background-color: $text !default
|
||||
$progress-border-radius: $radius-rounded !default
|
||||
|
||||
$progress-indeterminate-duration: 1.5s !default
|
||||
|
||||
$progress-colors: $colors !default
|
||||
|
||||
.progress
|
||||
@extend %block
|
||||
-moz-appearance: none
|
||||
-webkit-appearance: none
|
||||
border: none
|
||||
border-radius: $progress-border-radius
|
||||
display: block
|
||||
height: $size-normal
|
||||
overflow: hidden
|
||||
padding: 0
|
||||
width: 100%
|
||||
&::-webkit-progress-bar
|
||||
background-color: $progress-bar-background-color
|
||||
&::-webkit-progress-value
|
||||
background-color: $progress-value-background-color
|
||||
&::-moz-progress-bar
|
||||
background-color: $progress-value-background-color
|
||||
&::-ms-fill
|
||||
background-color: $progress-value-background-color
|
||||
border: none
|
||||
// Colors
|
||||
@each $name, $pair in $progress-colors
|
||||
$color: nth($pair, 1)
|
||||
&.is-#{$name}
|
||||
&::-webkit-progress-value
|
||||
background-color: $color
|
||||
&::-moz-progress-bar
|
||||
background-color: $color
|
||||
&::-ms-fill
|
||||
background-color: $color
|
||||
&:indeterminate
|
||||
background-image: linear-gradient(to right, $color 30%, $progress-bar-background-color 30%)
|
||||
|
||||
&:indeterminate
|
||||
animation-duration: $progress-indeterminate-duration
|
||||
animation-iteration-count: infinite
|
||||
animation-name: moveIndeterminate
|
||||
animation-timing-function: linear
|
||||
background-color: $progress-bar-background-color
|
||||
background-image: linear-gradient(to right, $text 30%, $progress-bar-background-color 30%)
|
||||
background-position: top left
|
||||
background-repeat: no-repeat
|
||||
background-size: 150% 150%
|
||||
&::-webkit-progress-bar
|
||||
background-color: transparent
|
||||
&::-moz-progress-bar
|
||||
background-color: transparent
|
||||
&::-ms-fill
|
||||
animation-name: none
|
||||
|
||||
// Sizes
|
||||
&.is-small
|
||||
height: $size-small
|
||||
&.is-medium
|
||||
height: $size-medium
|
||||
&.is-large
|
||||
height: $size-large
|
||||
|
||||
@keyframes moveIndeterminate
|
||||
from
|
||||
background-position: 200% 0
|
||||
to
|
||||
background-position: -200% 0
|
131
static/css/sass/bulma/elements/table.sass
Normal file
131
static/css/sass/bulma/elements/table.sass
Normal file
@ -0,0 +1,131 @@
|
||||
$table-color: $text-strong !default
|
||||
$table-background-color: $scheme-main !default
|
||||
|
||||
$table-cell-border: 1px solid $border !default
|
||||
$table-cell-border-width: 0 0 1px !default
|
||||
$table-cell-padding: 0.5em 0.75em !default
|
||||
$table-cell-heading-color: $text-strong !default
|
||||
|
||||
$table-head-cell-border-width: 0 0 2px !default
|
||||
$table-head-cell-color: $text-strong !default
|
||||
$table-foot-cell-border-width: 2px 0 0 !default
|
||||
$table-foot-cell-color: $text-strong !default
|
||||
|
||||
$table-head-background-color: transparent !default
|
||||
$table-body-background-color: transparent !default
|
||||
$table-foot-background-color: transparent !default
|
||||
|
||||
$table-row-hover-background-color: $scheme-main-bis !default
|
||||
|
||||
$table-row-active-background-color: $primary !default
|
||||
$table-row-active-color: $primary-invert !default
|
||||
|
||||
$table-striped-row-even-background-color: $scheme-main-bis !default
|
||||
$table-striped-row-even-hover-background-color: $scheme-main-ter !default
|
||||
|
||||
$table-colors: $colors !default
|
||||
|
||||
.table
|
||||
@extend %block
|
||||
background-color: $table-background-color
|
||||
color: $table-color
|
||||
td,
|
||||
th
|
||||
border: $table-cell-border
|
||||
border-width: $table-cell-border-width
|
||||
padding: $table-cell-padding
|
||||
vertical-align: top
|
||||
// Colors
|
||||
@each $name, $pair in $table-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
border-color: $color
|
||||
color: $color-invert
|
||||
// Modifiers
|
||||
&.is-narrow
|
||||
white-space: nowrap
|
||||
width: 1%
|
||||
&.is-selected
|
||||
background-color: $table-row-active-background-color
|
||||
color: $table-row-active-color
|
||||
a,
|
||||
strong
|
||||
color: currentColor
|
||||
&.is-vcentered
|
||||
vertical-align: middle
|
||||
th
|
||||
color: $table-cell-heading-color
|
||||
&:not([align])
|
||||
text-align: inherit
|
||||
tr
|
||||
&.is-selected
|
||||
background-color: $table-row-active-background-color
|
||||
color: $table-row-active-color
|
||||
a,
|
||||
strong
|
||||
color: currentColor
|
||||
td,
|
||||
th
|
||||
border-color: $table-row-active-color
|
||||
color: currentColor
|
||||
thead
|
||||
background-color: $table-head-background-color
|
||||
td,
|
||||
th
|
||||
border-width: $table-head-cell-border-width
|
||||
color: $table-head-cell-color
|
||||
tfoot
|
||||
background-color: $table-foot-background-color
|
||||
td,
|
||||
th
|
||||
border-width: $table-foot-cell-border-width
|
||||
color: $table-foot-cell-color
|
||||
tbody
|
||||
background-color: $table-body-background-color
|
||||
tr
|
||||
&:last-child
|
||||
td,
|
||||
th
|
||||
border-bottom-width: 0
|
||||
// Modifiers
|
||||
&.is-bordered
|
||||
td,
|
||||
th
|
||||
border-width: 1px
|
||||
tr
|
||||
&:last-child
|
||||
td,
|
||||
th
|
||||
border-bottom-width: 1px
|
||||
&.is-fullwidth
|
||||
width: 100%
|
||||
&.is-hoverable
|
||||
tbody
|
||||
tr:not(.is-selected)
|
||||
&:hover
|
||||
background-color: $table-row-hover-background-color
|
||||
&.is-striped
|
||||
tbody
|
||||
tr:not(.is-selected)
|
||||
&:hover
|
||||
background-color: $table-row-hover-background-color
|
||||
&:nth-child(even)
|
||||
background-color: $table-striped-row-even-hover-background-color
|
||||
&.is-narrow
|
||||
td,
|
||||
th
|
||||
padding: 0.25em 0.5em
|
||||
&.is-striped
|
||||
tbody
|
||||
tr:not(.is-selected)
|
||||
&:nth-child(even)
|
||||
background-color: $table-striped-row-even-background-color
|
||||
|
||||
.table-container
|
||||
@extend %block
|
||||
+overflow-touch
|
||||
overflow: auto
|
||||
overflow-y: hidden
|
||||
max-width: 100%
|
138
static/css/sass/bulma/elements/tag.sass
Normal file
138
static/css/sass/bulma/elements/tag.sass
Normal file
@ -0,0 +1,138 @@
|
||||
$tag-background-color: $background !default
|
||||
$tag-color: $text !default
|
||||
$tag-radius: $radius !default
|
||||
$tag-delete-margin: 1px !default
|
||||
|
||||
$tag-colors: $colors !default
|
||||
|
||||
.tags
|
||||
align-items: center
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
justify-content: flex-start
|
||||
.tag
|
||||
margin-bottom: 0.5rem
|
||||
&:not(:last-child)
|
||||
+ltr-property("margin", 0.5rem)
|
||||
&:last-child
|
||||
margin-bottom: -0.5rem
|
||||
&:not(:last-child)
|
||||
margin-bottom: 1rem
|
||||
// Sizes
|
||||
&.are-medium
|
||||
.tag:not(.is-normal):not(.is-large)
|
||||
font-size: $size-normal
|
||||
&.are-large
|
||||
.tag:not(.is-normal):not(.is-medium)
|
||||
font-size: $size-medium
|
||||
&.is-centered
|
||||
justify-content: center
|
||||
.tag
|
||||
margin-right: 0.25rem
|
||||
margin-left: 0.25rem
|
||||
&.is-right
|
||||
justify-content: flex-end
|
||||
.tag
|
||||
&:not(:first-child)
|
||||
margin-left: 0.5rem
|
||||
&:not(:last-child)
|
||||
margin-right: 0
|
||||
&.has-addons
|
||||
.tag
|
||||
+ltr-property("margin", 0)
|
||||
&:not(:first-child)
|
||||
+ltr-property("margin", 0, false)
|
||||
+ltr
|
||||
border-top-left-radius: 0
|
||||
border-bottom-left-radius: 0
|
||||
+rtl
|
||||
border-top-right-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
&:not(:last-child)
|
||||
+ltr
|
||||
border-top-right-radius: 0
|
||||
border-bottom-right-radius: 0
|
||||
+rtl
|
||||
border-top-left-radius: 0
|
||||
border-bottom-left-radius: 0
|
||||
|
||||
.tag:not(body)
|
||||
align-items: center
|
||||
background-color: $tag-background-color
|
||||
border-radius: $tag-radius
|
||||
color: $tag-color
|
||||
display: inline-flex
|
||||
font-size: $size-small
|
||||
height: 2em
|
||||
justify-content: center
|
||||
line-height: 1.5
|
||||
padding-left: 0.75em
|
||||
padding-right: 0.75em
|
||||
white-space: nowrap
|
||||
.delete
|
||||
+ltr-property("margin", 0.25rem, false)
|
||||
+ltr-property("margin", -0.375rem)
|
||||
// Colors
|
||||
@each $name, $pair in $tag-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
// If a light and dark colors are provided
|
||||
@if length($pair) > 3
|
||||
$color-light: nth($pair, 3)
|
||||
$color-dark: nth($pair, 4)
|
||||
&.is-light
|
||||
background-color: $color-light
|
||||
color: $color-dark
|
||||
// Sizes
|
||||
&.is-normal
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-normal
|
||||
&.is-large
|
||||
font-size: $size-medium
|
||||
.icon
|
||||
&:first-child:not(:last-child)
|
||||
+ltr-property("margin", -0.375em, false)
|
||||
+ltr-property("margin", 0.1875em)
|
||||
&:last-child:not(:first-child)
|
||||
+ltr-property("margin", 0.1875em, false)
|
||||
+ltr-property("margin", -0.375em)
|
||||
&:first-child:last-child
|
||||
+ltr-property("margin", -0.375em, false)
|
||||
+ltr-property("margin", -0.375em)
|
||||
// Modifiers
|
||||
&.is-delete
|
||||
+ltr-property("margin", $tag-delete-margin, false)
|
||||
padding: 0
|
||||
position: relative
|
||||
width: 2em
|
||||
&::before,
|
||||
&::after
|
||||
background-color: currentColor
|
||||
content: ""
|
||||
display: block
|
||||
left: 50%
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform: translateX(-50%) translateY(-50%) rotate(45deg)
|
||||
transform-origin: center center
|
||||
&::before
|
||||
height: 1px
|
||||
width: 50%
|
||||
&::after
|
||||
height: 50%
|
||||
width: 1px
|
||||
&:hover,
|
||||
&:focus
|
||||
background-color: darken($tag-background-color, 5%)
|
||||
&:active
|
||||
background-color: darken($tag-background-color, 10%)
|
||||
&.is-rounded
|
||||
border-radius: $radius-rounded
|
||||
|
||||
a.tag
|
||||
&:hover
|
||||
text-decoration: underline
|
70
static/css/sass/bulma/elements/title.sass
Normal file
70
static/css/sass/bulma/elements/title.sass
Normal file
@ -0,0 +1,70 @@
|
||||
$title-color: $text-strong !default
|
||||
$title-family: false !default
|
||||
$title-size: $size-3 !default
|
||||
$title-weight: $weight-semibold !default
|
||||
$title-line-height: 1.125 !default
|
||||
$title-strong-color: inherit !default
|
||||
$title-strong-weight: inherit !default
|
||||
$title-sub-size: 0.75em !default
|
||||
$title-sup-size: 0.75em !default
|
||||
|
||||
$subtitle-color: $text !default
|
||||
$subtitle-family: false !default
|
||||
$subtitle-size: $size-5 !default
|
||||
$subtitle-weight: $weight-normal !default
|
||||
$subtitle-line-height: 1.25 !default
|
||||
$subtitle-strong-color: $text-strong !default
|
||||
$subtitle-strong-weight: $weight-semibold !default
|
||||
$subtitle-negative-margin: -1.25rem !default
|
||||
|
||||
.title,
|
||||
.subtitle
|
||||
@extend %block
|
||||
word-break: break-word
|
||||
em,
|
||||
span
|
||||
font-weight: inherit
|
||||
sub
|
||||
font-size: $title-sub-size
|
||||
sup
|
||||
font-size: $title-sup-size
|
||||
.tag
|
||||
vertical-align: middle
|
||||
|
||||
.title
|
||||
color: $title-color
|
||||
@if $title-family
|
||||
font-family: $title-family
|
||||
font-size: $title-size
|
||||
font-weight: $title-weight
|
||||
line-height: $title-line-height
|
||||
strong
|
||||
color: $title-strong-color
|
||||
font-weight: $title-strong-weight
|
||||
& + .highlight
|
||||
margin-top: -0.75rem
|
||||
&:not(.is-spaced) + .subtitle
|
||||
margin-top: $subtitle-negative-margin
|
||||
// Sizes
|
||||
@each $size in $sizes
|
||||
$i: index($sizes, $size)
|
||||
&.is-#{$i}
|
||||
font-size: $size
|
||||
|
||||
.subtitle
|
||||
color: $subtitle-color
|
||||
@if $subtitle-family
|
||||
font-family: $subtitle-family
|
||||
font-size: $subtitle-size
|
||||
font-weight: $subtitle-weight
|
||||
line-height: $subtitle-line-height
|
||||
strong
|
||||
color: $subtitle-strong-color
|
||||
font-weight: $subtitle-strong-weight
|
||||
&:not(.is-spaced) + .title
|
||||
margin-top: $subtitle-negative-margin
|
||||
// Sizes
|
||||
@each $size in $sizes
|
||||
$i: index($sizes, $size)
|
||||
&.is-#{$i}
|
||||
font-size: $size
|
9
static/css/sass/bulma/form/_all.sass
Normal file
9
static/css/sass/bulma/form/_all.sass
Normal file
@ -0,0 +1,9 @@
|
||||
/* Bulma Form */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "shared.sass"
|
||||
@import "input-textarea.sass"
|
||||
@import "checkbox-radio.sass"
|
||||
@import "select.sass"
|
||||
@import "file.sass"
|
||||
@import "tools.sass"
|
22
static/css/sass/bulma/form/checkbox-radio.sass
Normal file
22
static/css/sass/bulma/form/checkbox-radio.sass
Normal file
@ -0,0 +1,22 @@
|
||||
%checkbox-radio
|
||||
cursor: pointer
|
||||
display: inline-block
|
||||
line-height: 1.25
|
||||
position: relative
|
||||
input
|
||||
cursor: pointer
|
||||
&:hover
|
||||
color: $input-hover-color
|
||||
&[disabled],
|
||||
fieldset[disabled] &,
|
||||
input[disabled]
|
||||
color: $input-disabled-color
|
||||
cursor: not-allowed
|
||||
|
||||
.checkbox
|
||||
@extend %checkbox-radio
|
||||
|
||||
.radio
|
||||
@extend %checkbox-radio
|
||||
& + .radio
|
||||
+ltr-property("margin", 0.5em, false)
|
182
static/css/sass/bulma/form/file.sass
Normal file
182
static/css/sass/bulma/form/file.sass
Normal file
@ -0,0 +1,182 @@
|
||||
$file-border-color: $border !default
|
||||
$file-radius: $radius !default
|
||||
|
||||
$file-cta-background-color: $scheme-main-ter !default
|
||||
$file-cta-color: $text !default
|
||||
$file-cta-hover-color: $text-strong !default
|
||||
$file-cta-active-color: $text-strong !default
|
||||
|
||||
$file-name-border-color: $border !default
|
||||
$file-name-border-style: solid !default
|
||||
$file-name-border-width: 1px 1px 1px 0 !default
|
||||
$file-name-max-width: 16em !default
|
||||
|
||||
$file-colors: $form-colors !default
|
||||
|
||||
.file
|
||||
@extend %unselectable
|
||||
align-items: stretch
|
||||
display: flex
|
||||
justify-content: flex-start
|
||||
position: relative
|
||||
// Colors
|
||||
@each $name, $pair in $file-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
.file-cta
|
||||
background-color: $color
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
.file-cta
|
||||
background-color: bulmaDarken($color, 2.5%)
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
&:focus,
|
||||
&.is-focused
|
||||
.file-cta
|
||||
border-color: transparent
|
||||
box-shadow: 0 0 0.5em bulmaRgba($color, 0.25)
|
||||
color: $color-invert
|
||||
&:active,
|
||||
&.is-active
|
||||
.file-cta
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
border-color: transparent
|
||||
color: $color-invert
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
.file-icon
|
||||
.fa
|
||||
font-size: 21px
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
.file-icon
|
||||
.fa
|
||||
font-size: 28px
|
||||
// Modifiers
|
||||
&.has-name
|
||||
.file-cta
|
||||
border-bottom-right-radius: 0
|
||||
border-top-right-radius: 0
|
||||
.file-name
|
||||
border-bottom-left-radius: 0
|
||||
border-top-left-radius: 0
|
||||
&.is-empty
|
||||
.file-cta
|
||||
border-radius: $file-radius
|
||||
.file-name
|
||||
display: none
|
||||
&.is-boxed
|
||||
.file-label
|
||||
flex-direction: column
|
||||
.file-cta
|
||||
flex-direction: column
|
||||
height: auto
|
||||
padding: 1em 3em
|
||||
.file-name
|
||||
border-width: 0 1px 1px
|
||||
.file-icon
|
||||
height: 1.5em
|
||||
width: 1.5em
|
||||
.fa
|
||||
font-size: 21px
|
||||
&.is-small
|
||||
.file-icon .fa
|
||||
font-size: 14px
|
||||
&.is-medium
|
||||
.file-icon .fa
|
||||
font-size: 28px
|
||||
&.is-large
|
||||
.file-icon .fa
|
||||
font-size: 35px
|
||||
&.has-name
|
||||
.file-cta
|
||||
border-radius: $file-radius $file-radius 0 0
|
||||
.file-name
|
||||
border-radius: 0 0 $file-radius $file-radius
|
||||
border-width: 0 1px 1px
|
||||
&.is-centered
|
||||
justify-content: center
|
||||
&.is-fullwidth
|
||||
.file-label
|
||||
width: 100%
|
||||
.file-name
|
||||
flex-grow: 1
|
||||
max-width: none
|
||||
&.is-right
|
||||
justify-content: flex-end
|
||||
.file-cta
|
||||
border-radius: 0 $file-radius $file-radius 0
|
||||
.file-name
|
||||
border-radius: $file-radius 0 0 $file-radius
|
||||
border-width: 1px 0 1px 1px
|
||||
order: -1
|
||||
|
||||
.file-label
|
||||
align-items: stretch
|
||||
display: flex
|
||||
cursor: pointer
|
||||
justify-content: flex-start
|
||||
overflow: hidden
|
||||
position: relative
|
||||
&:hover
|
||||
.file-cta
|
||||
background-color: bulmaDarken($file-cta-background-color, 2.5%)
|
||||
color: $file-cta-hover-color
|
||||
.file-name
|
||||
border-color: bulmaDarken($file-name-border-color, 2.5%)
|
||||
&:active
|
||||
.file-cta
|
||||
background-color: bulmaDarken($file-cta-background-color, 5%)
|
||||
color: $file-cta-active-color
|
||||
.file-name
|
||||
border-color: bulmaDarken($file-name-border-color, 5%)
|
||||
|
||||
.file-input
|
||||
height: 100%
|
||||
left: 0
|
||||
opacity: 0
|
||||
outline: none
|
||||
position: absolute
|
||||
top: 0
|
||||
width: 100%
|
||||
|
||||
.file-cta,
|
||||
.file-name
|
||||
@extend %control
|
||||
border-color: $file-border-color
|
||||
border-radius: $file-radius
|
||||
font-size: 1em
|
||||
padding-left: 1em
|
||||
padding-right: 1em
|
||||
white-space: nowrap
|
||||
|
||||
.file-cta
|
||||
background-color: $file-cta-background-color
|
||||
color: $file-cta-color
|
||||
|
||||
.file-name
|
||||
border-color: $file-name-border-color
|
||||
border-style: $file-name-border-style
|
||||
border-width: $file-name-border-width
|
||||
display: block
|
||||
max-width: $file-name-max-width
|
||||
overflow: hidden
|
||||
text-align: inherit
|
||||
text-overflow: ellipsis
|
||||
|
||||
.file-icon
|
||||
align-items: center
|
||||
display: flex
|
||||
height: 1em
|
||||
justify-content: center
|
||||
+ltr-property("margin", 0.5em)
|
||||
width: 1em
|
||||
.fa
|
||||
font-size: 14px
|
66
static/css/sass/bulma/form/input-textarea.sass
Normal file
66
static/css/sass/bulma/form/input-textarea.sass
Normal file
@ -0,0 +1,66 @@
|
||||
$textarea-padding: $control-padding-horizontal !default
|
||||
$textarea-max-height: 40em !default
|
||||
$textarea-min-height: 8em !default
|
||||
|
||||
$textarea-colors: $form-colors !default
|
||||
|
||||
%input-textarea
|
||||
@extend %input
|
||||
box-shadow: $input-shadow
|
||||
max-width: 100%
|
||||
width: 100%
|
||||
&[readonly]
|
||||
box-shadow: none
|
||||
// Colors
|
||||
@each $name, $pair in $textarea-colors
|
||||
$color: nth($pair, 1)
|
||||
&.is-#{$name}
|
||||
border-color: $color
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active
|
||||
box-shadow: $input-focus-box-shadow-size bulmaRgba($color, 0.25)
|
||||
// Sizes
|
||||
&.is-small
|
||||
+control-small
|
||||
&.is-medium
|
||||
+control-medium
|
||||
&.is-large
|
||||
+control-large
|
||||
// Modifiers
|
||||
&.is-fullwidth
|
||||
display: block
|
||||
width: 100%
|
||||
&.is-inline
|
||||
display: inline
|
||||
width: auto
|
||||
|
||||
.input
|
||||
@extend %input-textarea
|
||||
&.is-rounded
|
||||
border-radius: $radius-rounded
|
||||
padding-left: calc(#{$control-padding-horizontal} + 0.375em)
|
||||
padding-right: calc(#{$control-padding-horizontal} + 0.375em)
|
||||
&.is-static
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
|
||||
.textarea
|
||||
@extend %input-textarea
|
||||
display: block
|
||||
max-width: 100%
|
||||
min-width: 100%
|
||||
padding: $textarea-padding
|
||||
resize: vertical
|
||||
&:not([rows])
|
||||
max-height: $textarea-max-height
|
||||
min-height: $textarea-min-height
|
||||
&[rows]
|
||||
height: initial
|
||||
// Modifiers
|
||||
&.has-fixed-size
|
||||
resize: none
|
87
static/css/sass/bulma/form/select.sass
Normal file
87
static/css/sass/bulma/form/select.sass
Normal file
@ -0,0 +1,87 @@
|
||||
$select-colors: $form-colors !default
|
||||
|
||||
.select
|
||||
display: inline-block
|
||||
max-width: 100%
|
||||
position: relative
|
||||
vertical-align: top
|
||||
&:not(.is-multiple)
|
||||
height: $input-height
|
||||
&:not(.is-multiple):not(.is-loading)
|
||||
&::after
|
||||
@extend %arrow
|
||||
border-color: $input-arrow
|
||||
+ltr-position(1.125em)
|
||||
z-index: 4
|
||||
&.is-rounded
|
||||
select
|
||||
border-radius: $radius-rounded
|
||||
+ltr-property("padding", 1em, false)
|
||||
select
|
||||
@extend %input
|
||||
cursor: pointer
|
||||
display: block
|
||||
font-size: 1em
|
||||
max-width: 100%
|
||||
outline: none
|
||||
&::-ms-expand
|
||||
display: none
|
||||
&[disabled]:hover,
|
||||
fieldset[disabled] &:hover
|
||||
border-color: $input-disabled-border-color
|
||||
&:not([multiple])
|
||||
+ltr-property("padding", 2.5em)
|
||||
&[multiple]
|
||||
height: auto
|
||||
padding: 0
|
||||
option
|
||||
padding: 0.5em 1em
|
||||
// States
|
||||
&:not(.is-multiple):not(.is-loading):hover
|
||||
&::after
|
||||
border-color: $input-hover-color
|
||||
// Colors
|
||||
@each $name, $pair in $select-colors
|
||||
$color: nth($pair, 1)
|
||||
&.is-#{$name}
|
||||
&:not(:hover)::after
|
||||
border-color: $color
|
||||
select
|
||||
border-color: $color
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
border-color: bulmaDarken($color, 5%)
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active
|
||||
box-shadow: $input-focus-box-shadow-size bulmaRgba($color, 0.25)
|
||||
// Sizes
|
||||
&.is-small
|
||||
+control-small
|
||||
&.is-medium
|
||||
+control-medium
|
||||
&.is-large
|
||||
+control-large
|
||||
// Modifiers
|
||||
&.is-disabled
|
||||
&::after
|
||||
border-color: $input-disabled-color
|
||||
&.is-fullwidth
|
||||
width: 100%
|
||||
select
|
||||
width: 100%
|
||||
&.is-loading
|
||||
&::after
|
||||
@extend %loader
|
||||
margin-top: 0
|
||||
position: absolute
|
||||
+ltr-position(0.625em)
|
||||
top: 0.625em
|
||||
transform: none
|
||||
&.is-small:after
|
||||
font-size: $size-small
|
||||
&.is-medium:after
|
||||
font-size: $size-medium
|
||||
&.is-large:after
|
||||
font-size: $size-large
|
57
static/css/sass/bulma/form/shared.sass
Normal file
57
static/css/sass/bulma/form/shared.sass
Normal file
@ -0,0 +1,57 @@
|
||||
$form-colors: $colors !default
|
||||
|
||||
$input-color: $text-strong !default
|
||||
$input-background-color: $scheme-main !default
|
||||
$input-border-color: $border !default
|
||||
$input-height: $control-height !default
|
||||
$input-shadow: inset 0 0.0625em 0.125em rgba($scheme-invert, 0.05) !default
|
||||
$input-placeholder-color: bulmaRgba($input-color, 0.3) !default
|
||||
|
||||
$input-hover-color: $text-strong !default
|
||||
$input-hover-border-color: $border-hover !default
|
||||
|
||||
$input-focus-color: $text-strong !default
|
||||
$input-focus-border-color: $link !default
|
||||
$input-focus-box-shadow-size: 0 0 0 0.125em !default
|
||||
$input-focus-box-shadow-color: bulmaRgba($link, 0.25) !default
|
||||
|
||||
$input-disabled-color: $text-light !default
|
||||
$input-disabled-background-color: $background !default
|
||||
$input-disabled-border-color: $background !default
|
||||
$input-disabled-placeholder-color: bulmaRgba($input-disabled-color, 0.3) !default
|
||||
|
||||
$input-arrow: $link !default
|
||||
|
||||
$input-icon-color: $border !default
|
||||
$input-icon-active-color: $text !default
|
||||
|
||||
$input-radius: $radius !default
|
||||
|
||||
=input
|
||||
@extend %control
|
||||
background-color: $input-background-color
|
||||
border-color: $input-border-color
|
||||
border-radius: $input-radius
|
||||
color: $input-color
|
||||
+placeholder
|
||||
color: $input-placeholder-color
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
border-color: $input-hover-border-color
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active
|
||||
border-color: $input-focus-border-color
|
||||
box-shadow: $input-focus-box-shadow-size $input-focus-box-shadow-color
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
background-color: $input-disabled-background-color
|
||||
border-color: $input-disabled-border-color
|
||||
box-shadow: none
|
||||
color: $input-disabled-color
|
||||
+placeholder
|
||||
color: $input-disabled-placeholder-color
|
||||
|
||||
%input
|
||||
+input
|
215
static/css/sass/bulma/form/tools.sass
Normal file
215
static/css/sass/bulma/form/tools.sass
Normal file
@ -0,0 +1,215 @@
|
||||
$label-color: $text-strong !default
|
||||
$label-weight: $weight-bold !default
|
||||
|
||||
$help-size: $size-small !default
|
||||
|
||||
$label-colors: $form-colors !default
|
||||
|
||||
.label
|
||||
color: $label-color
|
||||
display: block
|
||||
font-size: $size-normal
|
||||
font-weight: $label-weight
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0.5em
|
||||
// Sizes
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
|
||||
.help
|
||||
display: block
|
||||
font-size: $help-size
|
||||
margin-top: 0.25rem
|
||||
@each $name, $pair in $label-colors
|
||||
$color: nth($pair, 1)
|
||||
&.is-#{$name}
|
||||
color: $color
|
||||
|
||||
// Containers
|
||||
|
||||
.field
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0.75rem
|
||||
// Modifiers
|
||||
&.has-addons
|
||||
display: flex
|
||||
justify-content: flex-start
|
||||
.control
|
||||
&:not(:last-child)
|
||||
+ltr-property("margin", -1px)
|
||||
&:not(:first-child):not(:last-child)
|
||||
.button,
|
||||
.input,
|
||||
.select select
|
||||
border-radius: 0
|
||||
&:first-child:not(:only-child)
|
||||
.button,
|
||||
.input,
|
||||
.select select
|
||||
+ltr
|
||||
border-bottom-right-radius: 0
|
||||
border-top-right-radius: 0
|
||||
+rtl
|
||||
border-bottom-left-radius: 0
|
||||
border-top-left-radius: 0
|
||||
&:last-child:not(:only-child)
|
||||
.button,
|
||||
.input,
|
||||
.select select
|
||||
+ltr
|
||||
border-bottom-left-radius: 0
|
||||
border-top-left-radius: 0
|
||||
+rtl
|
||||
border-bottom-right-radius: 0
|
||||
border-top-right-radius: 0
|
||||
.button,
|
||||
.input,
|
||||
.select select
|
||||
&:not([disabled])
|
||||
&:hover,
|
||||
&.is-hovered
|
||||
z-index: 2
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active
|
||||
z-index: 3
|
||||
&:hover
|
||||
z-index: 4
|
||||
&.is-expanded
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
&.has-addons-centered
|
||||
justify-content: center
|
||||
&.has-addons-right
|
||||
justify-content: flex-end
|
||||
&.has-addons-fullwidth
|
||||
.control
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
&.is-grouped
|
||||
display: flex
|
||||
justify-content: flex-start
|
||||
& > .control
|
||||
flex-shrink: 0
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0
|
||||
+ltr-property("margin", 0.75rem)
|
||||
&.is-expanded
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
&.is-grouped-centered
|
||||
justify-content: center
|
||||
&.is-grouped-right
|
||||
justify-content: flex-end
|
||||
&.is-grouped-multiline
|
||||
flex-wrap: wrap
|
||||
& > .control
|
||||
&:last-child,
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0.75rem
|
||||
&:last-child
|
||||
margin-bottom: -0.75rem
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0
|
||||
&.is-horizontal
|
||||
+tablet
|
||||
display: flex
|
||||
|
||||
.field-label
|
||||
.label
|
||||
font-size: inherit
|
||||
+mobile
|
||||
margin-bottom: 0.5rem
|
||||
+tablet
|
||||
flex-basis: 0
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
+ltr-property("margin", 1.5rem)
|
||||
text-align: right
|
||||
&.is-small
|
||||
font-size: $size-small
|
||||
padding-top: 0.375em
|
||||
&.is-normal
|
||||
padding-top: 0.375em
|
||||
&.is-medium
|
||||
font-size: $size-medium
|
||||
padding-top: 0.375em
|
||||
&.is-large
|
||||
font-size: $size-large
|
||||
padding-top: 0.375em
|
||||
|
||||
.field-body
|
||||
.field .field
|
||||
margin-bottom: 0
|
||||
+tablet
|
||||
display: flex
|
||||
flex-basis: 0
|
||||
flex-grow: 5
|
||||
flex-shrink: 1
|
||||
.field
|
||||
margin-bottom: 0
|
||||
& > .field
|
||||
flex-shrink: 1
|
||||
&:not(.is-narrow)
|
||||
flex-grow: 1
|
||||
&:not(:last-child)
|
||||
+ltr-property("margin", 0.75rem)
|
||||
|
||||
.control
|
||||
box-sizing: border-box
|
||||
clear: both
|
||||
font-size: $size-normal
|
||||
position: relative
|
||||
text-align: inherit
|
||||
// Modifiers
|
||||
&.has-icons-left,
|
||||
&.has-icons-right
|
||||
.input,
|
||||
.select
|
||||
&:focus
|
||||
& ~ .icon
|
||||
color: $input-icon-active-color
|
||||
&.is-small ~ .icon
|
||||
font-size: $size-small
|
||||
&.is-medium ~ .icon
|
||||
font-size: $size-medium
|
||||
&.is-large ~ .icon
|
||||
font-size: $size-large
|
||||
.icon
|
||||
color: $input-icon-color
|
||||
height: $input-height
|
||||
pointer-events: none
|
||||
position: absolute
|
||||
top: 0
|
||||
width: $input-height
|
||||
z-index: 4
|
||||
&.has-icons-left
|
||||
.input,
|
||||
.select select
|
||||
padding-left: $input-height
|
||||
.icon.is-left
|
||||
left: 0
|
||||
&.has-icons-right
|
||||
.input,
|
||||
.select select
|
||||
padding-right: $input-height
|
||||
.icon.is-right
|
||||
right: 0
|
||||
&.is-loading
|
||||
&::after
|
||||
@extend %loader
|
||||
position: absolute !important
|
||||
+ltr-position(0.625em)
|
||||
top: 0.625em
|
||||
z-index: 4
|
||||
&.is-small:after
|
||||
font-size: $size-small
|
||||
&.is-medium:after
|
||||
font-size: $size-medium
|
||||
&.is-large:after
|
||||
font-size: $size-large
|
5
static/css/sass/bulma/grid/_all.sass
Normal file
5
static/css/sass/bulma/grid/_all.sass
Normal file
@ -0,0 +1,5 @@
|
||||
/* Bulma Grid */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "columns.sass"
|
||||
@import "tiles.sass"
|
504
static/css/sass/bulma/grid/columns.sass
Normal file
504
static/css/sass/bulma/grid/columns.sass
Normal file
@ -0,0 +1,504 @@
|
||||
$column-gap: 0.75rem !default
|
||||
|
||||
.column
|
||||
display: block
|
||||
flex-basis: 0
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
padding: $column-gap
|
||||
.columns.is-mobile > &.is-narrow
|
||||
flex: none
|
||||
.columns.is-mobile > &.is-full
|
||||
flex: none
|
||||
width: 100%
|
||||
.columns.is-mobile > &.is-three-quarters
|
||||
flex: none
|
||||
width: 75%
|
||||
.columns.is-mobile > &.is-two-thirds
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
.columns.is-mobile > &.is-half
|
||||
flex: none
|
||||
width: 50%
|
||||
.columns.is-mobile > &.is-one-third
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
.columns.is-mobile > &.is-one-quarter
|
||||
flex: none
|
||||
width: 25%
|
||||
.columns.is-mobile > &.is-one-fifth
|
||||
flex: none
|
||||
width: 20%
|
||||
.columns.is-mobile > &.is-two-fifths
|
||||
flex: none
|
||||
width: 40%
|
||||
.columns.is-mobile > &.is-three-fifths
|
||||
flex: none
|
||||
width: 60%
|
||||
.columns.is-mobile > &.is-four-fifths
|
||||
flex: none
|
||||
width: 80%
|
||||
.columns.is-mobile > &.is-offset-three-quarters
|
||||
margin-left: 75%
|
||||
.columns.is-mobile > &.is-offset-two-thirds
|
||||
margin-left: 66.6666%
|
||||
.columns.is-mobile > &.is-offset-half
|
||||
margin-left: 50%
|
||||
.columns.is-mobile > &.is-offset-one-third
|
||||
margin-left: 33.3333%
|
||||
.columns.is-mobile > &.is-offset-one-quarter
|
||||
margin-left: 25%
|
||||
.columns.is-mobile > &.is-offset-one-fifth
|
||||
margin-left: 20%
|
||||
.columns.is-mobile > &.is-offset-two-fifths
|
||||
margin-left: 40%
|
||||
.columns.is-mobile > &.is-offset-three-fifths
|
||||
margin-left: 60%
|
||||
.columns.is-mobile > &.is-offset-four-fifths
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
.columns.is-mobile > &.is-#{$i}
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
.columns.is-mobile > &.is-offset-#{$i}
|
||||
margin-left: percentage($i / 12)
|
||||
+mobile
|
||||
&.is-narrow-mobile
|
||||
flex: none
|
||||
&.is-full-mobile
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters-mobile
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds-mobile
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half-mobile
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third-mobile
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter-mobile
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth-mobile
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths-mobile
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths-mobile
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths-mobile
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters-mobile
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds-mobile
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half-mobile
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third-mobile
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter-mobile
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth-mobile
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths-mobile
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths-mobile
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths-mobile
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i}-mobile
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i}-mobile
|
||||
margin-left: percentage($i / 12)
|
||||
+tablet
|
||||
&.is-narrow,
|
||||
&.is-narrow-tablet
|
||||
flex: none
|
||||
&.is-full,
|
||||
&.is-full-tablet
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters,
|
||||
&.is-three-quarters-tablet
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds,
|
||||
&.is-two-thirds-tablet
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half,
|
||||
&.is-half-tablet
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third,
|
||||
&.is-one-third-tablet
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter,
|
||||
&.is-one-quarter-tablet
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth,
|
||||
&.is-one-fifth-tablet
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths,
|
||||
&.is-two-fifths-tablet
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths,
|
||||
&.is-three-fifths-tablet
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths,
|
||||
&.is-four-fifths-tablet
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters,
|
||||
&.is-offset-three-quarters-tablet
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds,
|
||||
&.is-offset-two-thirds-tablet
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half,
|
||||
&.is-offset-half-tablet
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third,
|
||||
&.is-offset-one-third-tablet
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter,
|
||||
&.is-offset-one-quarter-tablet
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth,
|
||||
&.is-offset-one-fifth-tablet
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths,
|
||||
&.is-offset-two-fifths-tablet
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths,
|
||||
&.is-offset-three-fifths-tablet
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths,
|
||||
&.is-offset-four-fifths-tablet
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i},
|
||||
&.is-#{$i}-tablet
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i},
|
||||
&.is-offset-#{$i}-tablet
|
||||
margin-left: percentage($i / 12)
|
||||
+touch
|
||||
&.is-narrow-touch
|
||||
flex: none
|
||||
&.is-full-touch
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters-touch
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds-touch
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half-touch
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third-touch
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter-touch
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth-touch
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths-touch
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths-touch
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths-touch
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters-touch
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds-touch
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half-touch
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third-touch
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter-touch
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth-touch
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths-touch
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths-touch
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths-touch
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i}-touch
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i}-touch
|
||||
margin-left: percentage($i / 12)
|
||||
+desktop
|
||||
&.is-narrow-desktop
|
||||
flex: none
|
||||
&.is-full-desktop
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters-desktop
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds-desktop
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half-desktop
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third-desktop
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter-desktop
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth-desktop
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths-desktop
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths-desktop
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths-desktop
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters-desktop
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds-desktop
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half-desktop
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third-desktop
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter-desktop
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth-desktop
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths-desktop
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths-desktop
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths-desktop
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i}-desktop
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i}-desktop
|
||||
margin-left: percentage($i / 12)
|
||||
+widescreen
|
||||
&.is-narrow-widescreen
|
||||
flex: none
|
||||
&.is-full-widescreen
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters-widescreen
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds-widescreen
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half-widescreen
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third-widescreen
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter-widescreen
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth-widescreen
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths-widescreen
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths-widescreen
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths-widescreen
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters-widescreen
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds-widescreen
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half-widescreen
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third-widescreen
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter-widescreen
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth-widescreen
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths-widescreen
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths-widescreen
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths-widescreen
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i}-widescreen
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i}-widescreen
|
||||
margin-left: percentage($i / 12)
|
||||
+fullhd
|
||||
&.is-narrow-fullhd
|
||||
flex: none
|
||||
&.is-full-fullhd
|
||||
flex: none
|
||||
width: 100%
|
||||
&.is-three-quarters-fullhd
|
||||
flex: none
|
||||
width: 75%
|
||||
&.is-two-thirds-fullhd
|
||||
flex: none
|
||||
width: 66.6666%
|
||||
&.is-half-fullhd
|
||||
flex: none
|
||||
width: 50%
|
||||
&.is-one-third-fullhd
|
||||
flex: none
|
||||
width: 33.3333%
|
||||
&.is-one-quarter-fullhd
|
||||
flex: none
|
||||
width: 25%
|
||||
&.is-one-fifth-fullhd
|
||||
flex: none
|
||||
width: 20%
|
||||
&.is-two-fifths-fullhd
|
||||
flex: none
|
||||
width: 40%
|
||||
&.is-three-fifths-fullhd
|
||||
flex: none
|
||||
width: 60%
|
||||
&.is-four-fifths-fullhd
|
||||
flex: none
|
||||
width: 80%
|
||||
&.is-offset-three-quarters-fullhd
|
||||
margin-left: 75%
|
||||
&.is-offset-two-thirds-fullhd
|
||||
margin-left: 66.6666%
|
||||
&.is-offset-half-fullhd
|
||||
margin-left: 50%
|
||||
&.is-offset-one-third-fullhd
|
||||
margin-left: 33.3333%
|
||||
&.is-offset-one-quarter-fullhd
|
||||
margin-left: 25%
|
||||
&.is-offset-one-fifth-fullhd
|
||||
margin-left: 20%
|
||||
&.is-offset-two-fifths-fullhd
|
||||
margin-left: 40%
|
||||
&.is-offset-three-fifths-fullhd
|
||||
margin-left: 60%
|
||||
&.is-offset-four-fifths-fullhd
|
||||
margin-left: 80%
|
||||
@for $i from 0 through 12
|
||||
&.is-#{$i}-fullhd
|
||||
flex: none
|
||||
width: percentage($i / 12)
|
||||
&.is-offset-#{$i}-fullhd
|
||||
margin-left: percentage($i / 12)
|
||||
|
||||
.columns
|
||||
margin-left: (-$column-gap)
|
||||
margin-right: (-$column-gap)
|
||||
margin-top: (-$column-gap)
|
||||
&:last-child
|
||||
margin-bottom: (-$column-gap)
|
||||
&:not(:last-child)
|
||||
margin-bottom: calc(1.5rem - #{$column-gap})
|
||||
// Modifiers
|
||||
&.is-centered
|
||||
justify-content: center
|
||||
&.is-gapless
|
||||
margin-left: 0
|
||||
margin-right: 0
|
||||
margin-top: 0
|
||||
& > .column
|
||||
margin: 0
|
||||
padding: 0 !important
|
||||
&:not(:last-child)
|
||||
margin-bottom: 1.5rem
|
||||
&:last-child
|
||||
margin-bottom: 0
|
||||
&.is-mobile
|
||||
display: flex
|
||||
&.is-multiline
|
||||
flex-wrap: wrap
|
||||
&.is-vcentered
|
||||
align-items: center
|
||||
// Responsiveness
|
||||
+tablet
|
||||
&:not(.is-desktop)
|
||||
display: flex
|
||||
+desktop
|
||||
// Modifiers
|
||||
&.is-desktop
|
||||
display: flex
|
||||
|
||||
@if $variable-columns
|
||||
.columns.is-variable
|
||||
--columnGap: 0.75rem
|
||||
margin-left: calc(-1 * var(--columnGap))
|
||||
margin-right: calc(-1 * var(--columnGap))
|
||||
.column
|
||||
padding-left: var(--columnGap)
|
||||
padding-right: var(--columnGap)
|
||||
@for $i from 0 through 8
|
||||
&.is-#{$i}
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+mobile
|
||||
&.is-#{$i}-mobile
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+tablet
|
||||
&.is-#{$i}-tablet
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+tablet-only
|
||||
&.is-#{$i}-tablet-only
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+touch
|
||||
&.is-#{$i}-touch
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+desktop
|
||||
&.is-#{$i}-desktop
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+desktop-only
|
||||
&.is-#{$i}-desktop-only
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+widescreen
|
||||
&.is-#{$i}-widescreen
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+widescreen-only
|
||||
&.is-#{$i}-widescreen-only
|
||||
--columnGap: #{$i * 0.25rem}
|
||||
+fullhd
|
||||
&.is-#{$i}-fullhd
|
||||
--columnGap: #{$i * 0.25rem}
|
34
static/css/sass/bulma/grid/tiles.sass
Normal file
34
static/css/sass/bulma/grid/tiles.sass
Normal file
@ -0,0 +1,34 @@
|
||||
$tile-spacing: 0.75rem !default
|
||||
|
||||
.tile
|
||||
align-items: stretch
|
||||
display: block
|
||||
flex-basis: 0
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
min-height: min-content
|
||||
// Modifiers
|
||||
&.is-ancestor
|
||||
margin-left: $tile-spacing * -1
|
||||
margin-right: $tile-spacing * -1
|
||||
margin-top: $tile-spacing * -1
|
||||
&:last-child
|
||||
margin-bottom: $tile-spacing * -1
|
||||
&:not(:last-child)
|
||||
margin-bottom: $tile-spacing
|
||||
&.is-child
|
||||
margin: 0 !important
|
||||
&.is-parent
|
||||
padding: $tile-spacing
|
||||
&.is-vertical
|
||||
flex-direction: column
|
||||
& > .tile.is-child:not(:last-child)
|
||||
margin-bottom: 1.5rem !important
|
||||
// Responsiveness
|
||||
+tablet
|
||||
&:not(.is-child)
|
||||
display: flex
|
||||
@for $i from 1 through 12
|
||||
&.is-#{$i}
|
||||
flex: none
|
||||
width: ($i / 12) * 100%
|
12
static/css/sass/bulma/helpers/_all.sass
Normal file
12
static/css/sass/bulma/helpers/_all.sass
Normal file
@ -0,0 +1,12 @@
|
||||
/* Bulma Helpers */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "color.sass"
|
||||
@import "flexbox.sass"
|
||||
@import "float.sass"
|
||||
@import "other.sass"
|
||||
@import "overflow.sass"
|
||||
@import "position.sass"
|
||||
@import "spacing.sass"
|
||||
@import "typography.sass"
|
||||
@import "visibility.sass"
|
37
static/css/sass/bulma/helpers/color.sass
Normal file
37
static/css/sass/bulma/helpers/color.sass
Normal file
@ -0,0 +1,37 @@
|
||||
@each $name, $pair in $colors
|
||||
$color: nth($pair, 1)
|
||||
.has-text-#{$name}
|
||||
color: $color !important
|
||||
a.has-text-#{$name}
|
||||
&:hover,
|
||||
&:focus
|
||||
color: bulmaDarken($color, 10%) !important
|
||||
.has-background-#{$name}
|
||||
background-color: $color !important
|
||||
@if length($pair) >= 4
|
||||
$color-light: nth($pair, 3)
|
||||
$color-dark: nth($pair, 4)
|
||||
// Light
|
||||
.has-text-#{$name}-light
|
||||
color: $color-light !important
|
||||
a.has-text-#{$name}-light
|
||||
&:hover,
|
||||
&:focus
|
||||
color: bulmaDarken($color-light, 10%) !important
|
||||
.has-background-#{$name}-light
|
||||
background-color: $color-light !important
|
||||
// Dark
|
||||
.has-text-#{$name}-dark
|
||||
color: $color-dark !important
|
||||
a.has-text-#{$name}-dark
|
||||
&:hover,
|
||||
&:focus
|
||||
color: bulmaLighten($color-dark, 10%) !important
|
||||
.has-background-#{$name}-dark
|
||||
background-color: $color-dark !important
|
||||
|
||||
@each $name, $shade in $shades
|
||||
.has-text-#{$name}
|
||||
color: $shade !important
|
||||
.has-background-#{$name}
|
||||
background-color: $shade !important
|
35
static/css/sass/bulma/helpers/flexbox.sass
Normal file
35
static/css/sass/bulma/helpers/flexbox.sass
Normal file
@ -0,0 +1,35 @@
|
||||
$flex-direction-values: row, row-reverse, column, column-reverse
|
||||
@each $value in $flex-direction-values
|
||||
.is-flex-direction-#{$value}
|
||||
flex-direction: $value !important
|
||||
|
||||
$flex-wrap-values: nowrap, wrap, wrap-reverse
|
||||
@each $value in $flex-wrap-values
|
||||
.is-flex-wrap-#{$value}
|
||||
flex-wrap: $value !important
|
||||
|
||||
$justify-content-values: flex-start, flex-end, center, space-between, space-around, space-evenly, start, end, left, right
|
||||
@each $value in $justify-content-values
|
||||
.is-justify-content-#{$value}
|
||||
justify-content: $value !important
|
||||
|
||||
$align-content-values: flex-start, flex-end, center, space-between, space-around, space-evenly, stretch, start, end, baseline
|
||||
@each $value in $align-content-values
|
||||
.is-align-content-#{$value}
|
||||
align-content: $value !important
|
||||
|
||||
$align-items-values: stretch, flex-start, flex-end, center, baseline, start, end, self-start, self-end
|
||||
@each $value in $align-items-values
|
||||
.is-align-items-#{$value}
|
||||
align-items: $value !important
|
||||
|
||||
$align-self-values: auto, flex-start, flex-end, center, baseline, stretch
|
||||
@each $value in $align-self-values
|
||||
.is-align-self-#{$value}
|
||||
align-self: $value !important
|
||||
|
||||
$flex-operators: grow, shrink
|
||||
@each $operator in $flex-operators
|
||||
@for $i from 0 through 5
|
||||
.is-flex-#{$operator}-#{$i}
|
||||
flex-#{$operator}: $i !important
|
8
static/css/sass/bulma/helpers/float.sass
Normal file
8
static/css/sass/bulma/helpers/float.sass
Normal file
@ -0,0 +1,8 @@
|
||||
.is-clearfix
|
||||
+clearfix
|
||||
|
||||
.is-pulled-left
|
||||
float: left !important
|
||||
|
||||
.is-pulled-right
|
||||
float: right !important
|
11
static/css/sass/bulma/helpers/other.sass
Normal file
11
static/css/sass/bulma/helpers/other.sass
Normal file
@ -0,0 +1,11 @@
|
||||
.is-radiusless
|
||||
border-radius: 0 !important
|
||||
|
||||
.is-shadowless
|
||||
box-shadow: none !important
|
||||
|
||||
.is-clickable
|
||||
cursor: pointer !important
|
||||
|
||||
.is-unselectable
|
||||
@extend %unselectable
|
2
static/css/sass/bulma/helpers/overflow.sass
Normal file
2
static/css/sass/bulma/helpers/overflow.sass
Normal file
@ -0,0 +1,2 @@
|
||||
.is-clipped
|
||||
overflow: hidden !important
|
5
static/css/sass/bulma/helpers/position.sass
Normal file
5
static/css/sass/bulma/helpers/position.sass
Normal file
@ -0,0 +1,5 @@
|
||||
.is-overlay
|
||||
@extend %overlay
|
||||
|
||||
.is-relative
|
||||
position: relative !important
|
31
static/css/sass/bulma/helpers/spacing.sass
Normal file
31
static/css/sass/bulma/helpers/spacing.sass
Normal file
@ -0,0 +1,31 @@
|
||||
.is-marginless
|
||||
margin: 0 !important
|
||||
|
||||
.is-paddingless
|
||||
padding: 0 !important
|
||||
|
||||
$spacing-shortcuts: ("margin": "m", "padding": "p") !default
|
||||
$spacing-directions: ("top": "t", "right": "r", "bottom": "b", "left": "l") !default
|
||||
$spacing-horizontal: "x" !default
|
||||
$spacing-vertical: "y" !default
|
||||
$spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5": 1.5rem, "6": 3rem) !default
|
||||
|
||||
@each $property, $shortcut in $spacing-shortcuts
|
||||
@each $name, $value in $spacing-values
|
||||
// All directions
|
||||
.#{$shortcut}-#{$name}
|
||||
#{$property}: $value !important
|
||||
// Cardinal directions
|
||||
@each $direction, $suffix in $spacing-directions
|
||||
.#{$shortcut}#{$suffix}-#{$name}
|
||||
#{$property}-#{$direction}: $value !important
|
||||
// Horizontal axis
|
||||
@if $spacing-horizontal != null
|
||||
.#{$shortcut}#{$spacing-horizontal}-#{$name}
|
||||
#{$property}-left: $value !important
|
||||
#{$property}-right: $value !important
|
||||
// Vertical axis
|
||||
@if $spacing-vertical != null
|
||||
.#{$shortcut}#{$spacing-vertical}-#{$name}
|
||||
#{$property}-top: $value !important
|
||||
#{$property}-bottom: $value !important
|
98
static/css/sass/bulma/helpers/typography.sass
Normal file
98
static/css/sass/bulma/helpers/typography.sass
Normal file
@ -0,0 +1,98 @@
|
||||
=typography-size($target:'')
|
||||
@each $size in $sizes
|
||||
$i: index($sizes, $size)
|
||||
.is-size-#{$i}#{if($target == '', '', '-' + $target)}
|
||||
font-size: $size !important
|
||||
|
||||
+typography-size()
|
||||
|
||||
+mobile
|
||||
+typography-size('mobile')
|
||||
|
||||
+tablet
|
||||
+typography-size('tablet')
|
||||
|
||||
+touch
|
||||
+typography-size('touch')
|
||||
|
||||
+desktop
|
||||
+typography-size('desktop')
|
||||
|
||||
+widescreen
|
||||
+typography-size('widescreen')
|
||||
|
||||
+fullhd
|
||||
+typography-size('fullhd')
|
||||
|
||||
$alignments: ('centered': 'center', 'justified': 'justify', 'left': 'left', 'right': 'right')
|
||||
|
||||
@each $alignment, $text-align in $alignments
|
||||
.has-text-#{$alignment}
|
||||
text-align: #{$text-align} !important
|
||||
|
||||
@each $alignment, $text-align in $alignments
|
||||
+mobile
|
||||
.has-text-#{$alignment}-mobile
|
||||
text-align: #{$text-align} !important
|
||||
+tablet
|
||||
.has-text-#{$alignment}-tablet
|
||||
text-align: #{$text-align} !important
|
||||
+tablet-only
|
||||
.has-text-#{$alignment}-tablet-only
|
||||
text-align: #{$text-align} !important
|
||||
+touch
|
||||
.has-text-#{$alignment}-touch
|
||||
text-align: #{$text-align} !important
|
||||
+desktop
|
||||
.has-text-#{$alignment}-desktop
|
||||
text-align: #{$text-align} !important
|
||||
+desktop-only
|
||||
.has-text-#{$alignment}-desktop-only
|
||||
text-align: #{$text-align} !important
|
||||
+widescreen
|
||||
.has-text-#{$alignment}-widescreen
|
||||
text-align: #{$text-align} !important
|
||||
+widescreen-only
|
||||
.has-text-#{$alignment}-widescreen-only
|
||||
text-align: #{$text-align} !important
|
||||
+fullhd
|
||||
.has-text-#{$alignment}-fullhd
|
||||
text-align: #{$text-align} !important
|
||||
|
||||
.is-capitalized
|
||||
text-transform: capitalize !important
|
||||
|
||||
.is-lowercase
|
||||
text-transform: lowercase !important
|
||||
|
||||
.is-uppercase
|
||||
text-transform: uppercase !important
|
||||
|
||||
.is-italic
|
||||
font-style: italic !important
|
||||
|
||||
.has-text-weight-light
|
||||
font-weight: $weight-light !important
|
||||
.has-text-weight-normal
|
||||
font-weight: $weight-normal !important
|
||||
.has-text-weight-medium
|
||||
font-weight: $weight-medium !important
|
||||
.has-text-weight-semibold
|
||||
font-weight: $weight-semibold !important
|
||||
.has-text-weight-bold
|
||||
font-weight: $weight-bold !important
|
||||
|
||||
.is-family-primary
|
||||
font-family: $family-primary !important
|
||||
|
||||
.is-family-secondary
|
||||
font-family: $family-secondary !important
|
||||
|
||||
.is-family-sans-serif
|
||||
font-family: $family-sans-serif !important
|
||||
|
||||
.is-family-monospace
|
||||
font-family: $family-monospace !important
|
||||
|
||||
.is-family-code
|
||||
font-family: $family-code !important
|
122
static/css/sass/bulma/helpers/visibility.sass
Normal file
122
static/css/sass/bulma/helpers/visibility.sass
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
|
||||
$displays: 'block' 'flex' 'inline' 'inline-block' 'inline-flex'
|
||||
|
||||
@each $display in $displays
|
||||
.is-#{$display}
|
||||
display: #{$display} !important
|
||||
+mobile
|
||||
.is-#{$display}-mobile
|
||||
display: #{$display} !important
|
||||
+tablet
|
||||
.is-#{$display}-tablet
|
||||
display: #{$display} !important
|
||||
+tablet-only
|
||||
.is-#{$display}-tablet-only
|
||||
display: #{$display} !important
|
||||
+touch
|
||||
.is-#{$display}-touch
|
||||
display: #{$display} !important
|
||||
+desktop
|
||||
.is-#{$display}-desktop
|
||||
display: #{$display} !important
|
||||
+desktop-only
|
||||
.is-#{$display}-desktop-only
|
||||
display: #{$display} !important
|
||||
+widescreen
|
||||
.is-#{$display}-widescreen
|
||||
display: #{$display} !important
|
||||
+widescreen-only
|
||||
.is-#{$display}-widescreen-only
|
||||
display: #{$display} !important
|
||||
+fullhd
|
||||
.is-#{$display}-fullhd
|
||||
display: #{$display} !important
|
||||
|
||||
.is-hidden
|
||||
display: none !important
|
||||
|
||||
.is-sr-only
|
||||
border: none !important
|
||||
clip: rect(0, 0, 0, 0) !important
|
||||
height: 0.01em !important
|
||||
overflow: hidden !important
|
||||
padding: 0 !important
|
||||
position: absolute !important
|
||||
white-space: nowrap !important
|
||||
width: 0.01em !important
|
||||
|
||||
+mobile
|
||||
.is-hidden-mobile
|
||||
display: none !important
|
||||
|
||||
+tablet
|
||||
.is-hidden-tablet
|
||||
display: none !important
|
||||
|
||||
+tablet-only
|
||||
.is-hidden-tablet-only
|
||||
display: none !important
|
||||
|
||||
+touch
|
||||
.is-hidden-touch
|
||||
display: none !important
|
||||
|
||||
+desktop
|
||||
.is-hidden-desktop
|
||||
display: none !important
|
||||
|
||||
+desktop-only
|
||||
.is-hidden-desktop-only
|
||||
display: none !important
|
||||
|
||||
+widescreen
|
||||
.is-hidden-widescreen
|
||||
display: none !important
|
||||
|
||||
+widescreen-only
|
||||
.is-hidden-widescreen-only
|
||||
display: none !important
|
||||
|
||||
+fullhd
|
||||
.is-hidden-fullhd
|
||||
display: none !important
|
||||
|
||||
.is-invisible
|
||||
visibility: hidden !important
|
||||
|
||||
+mobile
|
||||
.is-invisible-mobile
|
||||
visibility: hidden !important
|
||||
|
||||
+tablet
|
||||
.is-invisible-tablet
|
||||
visibility: hidden !important
|
||||
|
||||
+tablet-only
|
||||
.is-invisible-tablet-only
|
||||
visibility: hidden !important
|
||||
|
||||
+touch
|
||||
.is-invisible-touch
|
||||
visibility: hidden !important
|
||||
|
||||
+desktop
|
||||
.is-invisible-desktop
|
||||
visibility: hidden !important
|
||||
|
||||
+desktop-only
|
||||
.is-invisible-desktop-only
|
||||
visibility: hidden !important
|
||||
|
||||
+widescreen
|
||||
.is-invisible-widescreen
|
||||
visibility: hidden !important
|
||||
|
||||
+widescreen-only
|
||||
.is-invisible-widescreen-only
|
||||
visibility: hidden !important
|
||||
|
||||
+fullhd
|
||||
.is-invisible-fullhd
|
||||
visibility: hidden !important
|
6
static/css/sass/bulma/layout/_all.sass
Normal file
6
static/css/sass/bulma/layout/_all.sass
Normal file
@ -0,0 +1,6 @@
|
||||
/* Bulma Layout */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "hero.sass"
|
||||
@import "section.sass"
|
||||
@import "footer.sass"
|
9
static/css/sass/bulma/layout/footer.sass
Normal file
9
static/css/sass/bulma/layout/footer.sass
Normal file
@ -0,0 +1,9 @@
|
||||
$footer-background-color: $scheme-main-bis !default
|
||||
$footer-color: false !default
|
||||
$footer-padding: 3rem 1.5rem 6rem !default
|
||||
|
||||
.footer
|
||||
background-color: $footer-background-color
|
||||
padding: $footer-padding
|
||||
@if $footer-color
|
||||
color: $footer-color
|
147
static/css/sass/bulma/layout/hero.sass
Normal file
147
static/css/sass/bulma/layout/hero.sass
Normal file
@ -0,0 +1,147 @@
|
||||
$hero-body-padding: 3rem 1.5rem !default
|
||||
$hero-body-padding-small: 1.5rem !default
|
||||
$hero-body-padding-medium: 9rem 1.5rem !default
|
||||
$hero-body-padding-large: 18rem 1.5rem !default
|
||||
|
||||
$hero-colors: $colors !default
|
||||
|
||||
// Main container
|
||||
.hero
|
||||
align-items: stretch
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: space-between
|
||||
.navbar
|
||||
background: none
|
||||
.tabs
|
||||
ul
|
||||
border-bottom: none
|
||||
// Colors
|
||||
@each $name, $pair in $hero-colors
|
||||
$color: nth($pair, 1)
|
||||
$color-invert: nth($pair, 2)
|
||||
&.is-#{$name}
|
||||
background-color: $color
|
||||
color: $color-invert
|
||||
a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),
|
||||
strong
|
||||
color: inherit
|
||||
.title
|
||||
color: $color-invert
|
||||
.subtitle
|
||||
color: bulmaRgba($color-invert, 0.9)
|
||||
a:not(.button),
|
||||
strong
|
||||
color: $color-invert
|
||||
.navbar-menu
|
||||
+touch
|
||||
background-color: $color
|
||||
.navbar-item,
|
||||
.navbar-link
|
||||
color: bulmaRgba($color-invert, 0.7)
|
||||
a.navbar-item,
|
||||
.navbar-link
|
||||
&:hover,
|
||||
&.is-active
|
||||
background-color: bulmaDarken($color, 5%)
|
||||
color: $color-invert
|
||||
.tabs
|
||||
a
|
||||
color: $color-invert
|
||||
opacity: 0.9
|
||||
&:hover
|
||||
opacity: 1
|
||||
li
|
||||
&.is-active a
|
||||
opacity: 1
|
||||
&.is-boxed,
|
||||
&.is-toggle
|
||||
a
|
||||
color: $color-invert
|
||||
&:hover
|
||||
background-color: bulmaRgba($scheme-invert, 0.1)
|
||||
li.is-active a
|
||||
&,
|
||||
&:hover
|
||||
background-color: $color-invert
|
||||
border-color: $color-invert
|
||||
color: $color
|
||||
// Modifiers
|
||||
@if type-of($color) == 'color'
|
||||
&.is-bold
|
||||
$gradient-top-left: darken(saturate(adjust-hue($color, -10deg), 10%), 10%)
|
||||
$gradient-bottom-right: lighten(saturate(adjust-hue($color, 10deg), 5%), 5%)
|
||||
background-image: linear-gradient(141deg, $gradient-top-left 0%, $color 71%, $gradient-bottom-right 100%)
|
||||
+mobile
|
||||
.navbar-menu
|
||||
background-image: linear-gradient(141deg, $gradient-top-left 0%, $color 71%, $gradient-bottom-right 100%)
|
||||
// Sizes
|
||||
&.is-small
|
||||
.hero-body
|
||||
padding: $hero-body-padding-small
|
||||
&.is-medium
|
||||
+tablet
|
||||
.hero-body
|
||||
padding: $hero-body-padding-medium
|
||||
&.is-large
|
||||
+tablet
|
||||
.hero-body
|
||||
padding: $hero-body-padding-large
|
||||
&.is-halfheight,
|
||||
&.is-fullheight,
|
||||
&.is-fullheight-with-navbar
|
||||
.hero-body
|
||||
align-items: center
|
||||
display: flex
|
||||
& > .container
|
||||
flex-grow: 1
|
||||
flex-shrink: 1
|
||||
&.is-halfheight
|
||||
min-height: 50vh
|
||||
&.is-fullheight
|
||||
min-height: 100vh
|
||||
|
||||
// Components
|
||||
|
||||
.hero-video
|
||||
@extend %overlay
|
||||
overflow: hidden
|
||||
video
|
||||
left: 50%
|
||||
min-height: 100%
|
||||
min-width: 100%
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform: translate3d(-50%, -50%, 0)
|
||||
// Modifiers
|
||||
&.is-transparent
|
||||
opacity: 0.3
|
||||
// Responsiveness
|
||||
+mobile
|
||||
display: none
|
||||
|
||||
.hero-buttons
|
||||
margin-top: 1.5rem
|
||||
// Responsiveness
|
||||
+mobile
|
||||
.button
|
||||
display: flex
|
||||
&:not(:last-child)
|
||||
margin-bottom: 0.75rem
|
||||
+tablet
|
||||
display: flex
|
||||
justify-content: center
|
||||
.button:not(:last-child)
|
||||
+ltr-property("margin", 1.5rem)
|
||||
|
||||
// Containers
|
||||
|
||||
.hero-head,
|
||||
.hero-foot
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
|
||||
.hero-body
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
padding: $hero-body-padding
|
13
static/css/sass/bulma/layout/section.sass
Normal file
13
static/css/sass/bulma/layout/section.sass
Normal file
@ -0,0 +1,13 @@
|
||||
$section-padding: 3rem 1.5rem !default
|
||||
$section-padding-medium: 9rem 1.5rem !default
|
||||
$section-padding-large: 18rem 1.5rem !default
|
||||
|
||||
.section
|
||||
padding: $section-padding
|
||||
// Responsiveness
|
||||
+desktop
|
||||
// Sizes
|
||||
&.is-medium
|
||||
padding: $section-padding-medium
|
||||
&.is-large
|
||||
padding: $section-padding-large
|
9
static/css/sass/bulma/utilities/_all.sass
Normal file
9
static/css/sass/bulma/utilities/_all.sass
Normal file
@ -0,0 +1,9 @@
|
||||
/* Bulma Utilities */
|
||||
@charset "utf-8"
|
||||
|
||||
@import "initial-variables.sass"
|
||||
@import "functions.sass"
|
||||
@import "derived-variables.sass"
|
||||
@import "animations.sass"
|
||||
@import "mixins.sass"
|
||||
@import "controls.sass"
|
5
static/css/sass/bulma/utilities/animations.sass
Normal file
5
static/css/sass/bulma/utilities/animations.sass
Normal file
@ -0,0 +1,5 @@
|
||||
@keyframes spinAround
|
||||
from
|
||||
transform: rotate(0deg)
|
||||
to
|
||||
transform: rotate(359deg)
|
50
static/css/sass/bulma/utilities/controls.sass
Normal file
50
static/css/sass/bulma/utilities/controls.sass
Normal file
@ -0,0 +1,50 @@
|
||||
$control-radius: $radius !default
|
||||
$control-radius-small: $radius-small !default
|
||||
|
||||
$control-border-width: 1px !default
|
||||
|
||||
$control-height: 2.5em !default
|
||||
$control-line-height: 1.5 !default
|
||||
|
||||
$control-padding-vertical: calc(0.5em - #{$control-border-width}) !default
|
||||
$control-padding-horizontal: calc(0.75em - #{$control-border-width}) !default
|
||||
|
||||
=control
|
||||
-moz-appearance: none
|
||||
-webkit-appearance: none
|
||||
align-items: center
|
||||
border: $control-border-width solid transparent
|
||||
border-radius: $control-radius
|
||||
box-shadow: none
|
||||
display: inline-flex
|
||||
font-size: $size-normal
|
||||
height: $control-height
|
||||
justify-content: flex-start
|
||||
line-height: $control-line-height
|
||||
padding-bottom: $control-padding-vertical
|
||||
padding-left: $control-padding-horizontal
|
||||
padding-right: $control-padding-horizontal
|
||||
padding-top: $control-padding-vertical
|
||||
position: relative
|
||||
vertical-align: top
|
||||
// States
|
||||
&:focus,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&.is-active
|
||||
outline: none
|
||||
&[disabled],
|
||||
fieldset[disabled] &
|
||||
cursor: not-allowed
|
||||
|
||||
%control
|
||||
+control
|
||||
|
||||
// The controls sizes use mixins so they can be used at different breakpoints
|
||||
=control-small
|
||||
border-radius: $control-radius-small
|
||||
font-size: $size-small
|
||||
=control-medium
|
||||
font-size: $size-medium
|
||||
=control-large
|
||||
font-size: $size-large
|
107
static/css/sass/bulma/utilities/derived-variables.sass
Normal file
107
static/css/sass/bulma/utilities/derived-variables.sass
Normal file
@ -0,0 +1,107 @@
|
||||
$primary: $turquoise !default
|
||||
|
||||
$info: $cyan !default
|
||||
$success: $green !default
|
||||
$warning: $yellow !default
|
||||
$danger: $red !default
|
||||
|
||||
$light: $white-ter !default
|
||||
$dark: $grey-darker !default
|
||||
|
||||
// Invert colors
|
||||
|
||||
$orange-invert: findColorInvert($orange) !default
|
||||
$yellow-invert: findColorInvert($yellow) !default
|
||||
$green-invert: findColorInvert($green) !default
|
||||
$turquoise-invert: findColorInvert($turquoise) !default
|
||||
$cyan-invert: findColorInvert($cyan) !default
|
||||
$blue-invert: findColorInvert($blue) !default
|
||||
$purple-invert: findColorInvert($purple) !default
|
||||
$red-invert: findColorInvert($red) !default
|
||||
|
||||
$primary-invert: findColorInvert($primary) !default
|
||||
$primary-light: findLightColor($primary) !default
|
||||
$primary-dark: findDarkColor($primary) !default
|
||||
$info-invert: findColorInvert($info) !default
|
||||
$info-light: findLightColor($info) !default
|
||||
$info-dark: findDarkColor($info) !default
|
||||
$success-invert: findColorInvert($success) !default
|
||||
$success-light: findLightColor($success) !default
|
||||
$success-dark: findDarkColor($success) !default
|
||||
$warning-invert: findColorInvert($warning) !default
|
||||
$warning-light: findLightColor($warning) !default
|
||||
$warning-dark: findDarkColor($warning) !default
|
||||
$danger-invert: findColorInvert($danger) !default
|
||||
$danger-light: findLightColor($danger) !default
|
||||
$danger-dark: findDarkColor($danger) !default
|
||||
$light-invert: findColorInvert($light) !default
|
||||
$dark-invert: findColorInvert($dark) !default
|
||||
|
||||
// General colors
|
||||
|
||||
$scheme-main: $white !default
|
||||
$scheme-main-bis: $white-bis !default
|
||||
$scheme-main-ter: $white-ter !default
|
||||
$scheme-invert: $black !default
|
||||
$scheme-invert-bis: $black-bis !default
|
||||
$scheme-invert-ter: $black-ter !default
|
||||
|
||||
$background: $white-ter !default
|
||||
|
||||
$border: $grey-lighter !default
|
||||
$border-hover: $grey-light !default
|
||||
$border-light: $grey-lightest !default
|
||||
$border-light-hover: $grey-light !default
|
||||
|
||||
// Text colors
|
||||
|
||||
$text: $grey-dark !default
|
||||
$text-invert: findColorInvert($text) !default
|
||||
$text-light: $grey !default
|
||||
$text-strong: $grey-darker !default
|
||||
|
||||
// Code colors
|
||||
|
||||
$code: darken($red, 15%) !default
|
||||
$code-background: $background !default
|
||||
|
||||
$pre: $text !default
|
||||
$pre-background: $background !default
|
||||
|
||||
// Link colors
|
||||
|
||||
$link: $blue !default
|
||||
$link-invert: findColorInvert($link) !default
|
||||
$link-light: findLightColor($link) !default
|
||||
$link-dark: findDarkColor($link) !default
|
||||
$link-visited: $purple !default
|
||||
|
||||
$link-hover: $grey-darker !default
|
||||
$link-hover-border: $grey-light !default
|
||||
|
||||
$link-focus: $grey-darker !default
|
||||
$link-focus-border: $blue !default
|
||||
|
||||
$link-active: $grey-darker !default
|
||||
$link-active-border: $grey-dark !default
|
||||
|
||||
// Typography
|
||||
|
||||
$family-primary: $family-sans-serif !default
|
||||
$family-secondary: $family-sans-serif !default
|
||||
$family-code: $family-monospace !default
|
||||
|
||||
$size-small: $size-7 !default
|
||||
$size-normal: $size-6 !default
|
||||
$size-medium: $size-5 !default
|
||||
$size-large: $size-4 !default
|
||||
|
||||
// Lists and maps
|
||||
$custom-colors: null !default
|
||||
$custom-shades: null !default
|
||||
|
||||
$colors: mergeColorMaps(("white": ($white, $black), "black": ($black, $white), "light": ($light, $light-invert), "dark": ($dark, $dark-invert), "primary": ($primary, $primary-invert, $primary-light, $primary-dark), "link": ($link, $link-invert, $link-light, $link-dark), "info": ($info, $info-invert, $info-light, $info-dark), "success": ($success, $success-invert, $success-light, $success-dark), "warning": ($warning, $warning-invert, $warning-light, $warning-dark), "danger": ($danger, $danger-invert, $danger-light, $danger-dark)), $custom-colors) !default
|
||||
|
||||
$shades: mergeColorMaps(("black-bis": $black-bis, "black-ter": $black-ter, "grey-darker": $grey-darker, "grey-dark": $grey-dark, "grey": $grey, "grey-light": $grey-light, "grey-lighter": $grey-lighter, "white-ter": $white-ter, "white-bis": $white-bis), $custom-shades) !default
|
||||
|
||||
$sizes: $size-1 $size-2 $size-3 $size-4 $size-5 $size-6 $size-7 !default
|
115
static/css/sass/bulma/utilities/functions.sass
Normal file
115
static/css/sass/bulma/utilities/functions.sass
Normal file
@ -0,0 +1,115 @@
|
||||
@function mergeColorMaps($bulma-colors, $custom-colors)
|
||||
// We return at least Bulma's hard-coded colors
|
||||
$merged-colors: $bulma-colors
|
||||
|
||||
// We want a map as input
|
||||
@if type-of($custom-colors) == 'map'
|
||||
@each $name, $components in $custom-colors
|
||||
// The color name should be a string
|
||||
// and the components either a single color
|
||||
// or a colors list with at least one element
|
||||
@if type-of($name) == 'string' and (type-of($components) == 'list' or type-of($components) == 'color') and length($components) >= 1
|
||||
$color-base: null
|
||||
$color-invert: null
|
||||
$color-light: null
|
||||
$color-dark: null
|
||||
$value: null
|
||||
|
||||
// The param can either be a single color
|
||||
// or a list of 2 colors
|
||||
@if type-of($components) == 'color'
|
||||
$color-base: $components
|
||||
$color-invert: findColorInvert($color-base)
|
||||
$color-light: findLightColor($color-base)
|
||||
$color-dark: findDarkColor($color-base)
|
||||
@else if type-of($components) == 'list'
|
||||
$color-base: nth($components, 1)
|
||||
// If Invert, Light and Dark are provided
|
||||
@if length($components) > 3
|
||||
$color-invert: nth($components, 2)
|
||||
$color-light: nth($components, 3)
|
||||
$color-dark: nth($components, 4)
|
||||
// If only Invert and Light are provided
|
||||
@else if length($components) > 2
|
||||
$color-invert: nth($components, 2)
|
||||
$color-light: nth($components, 3)
|
||||
$color-dark: findDarkColor($color-base)
|
||||
// If only Invert is provided
|
||||
@else
|
||||
$color-invert: nth($components, 2)
|
||||
$color-light: findLightColor($color-base)
|
||||
$color-dark: findDarkColor($color-base)
|
||||
|
||||
$value: ($color-base, $color-invert, $color-light, $color-dark)
|
||||
|
||||
// We only want to merge the map if the color base is an actual color
|
||||
@if type-of($color-base) == 'color'
|
||||
// We merge this colors elements as map with Bulma's colors map
|
||||
// (we can override them this way, no multiple definition for the same name)
|
||||
// $merged-colors: map_merge($merged-colors, ($name: ($color-base, $color-invert, $color-light, $color-dark)))
|
||||
$merged-colors: map_merge($merged-colors, ($name: $value))
|
||||
|
||||
@return $merged-colors
|
||||
|
||||
@function powerNumber($number, $exp)
|
||||
$value: 1
|
||||
@if $exp > 0
|
||||
@for $i from 1 through $exp
|
||||
$value: $value * $number
|
||||
@else if $exp < 0
|
||||
@for $i from 1 through -$exp
|
||||
$value: $value / $number
|
||||
@return $value
|
||||
|
||||
@function colorLuminance($color)
|
||||
@if type-of($color) != 'color'
|
||||
@return 0.55
|
||||
$color-rgb: ('red': red($color),'green': green($color),'blue': blue($color))
|
||||
@each $name, $value in $color-rgb
|
||||
$adjusted: 0
|
||||
$value: $value / 255
|
||||
@if $value < 0.03928
|
||||
$value: $value / 12.92
|
||||
@else
|
||||
$value: ($value + .055) / 1.055
|
||||
$value: powerNumber($value, 2)
|
||||
$color-rgb: map-merge($color-rgb, ($name: $value))
|
||||
@return (map-get($color-rgb, 'red') * .2126) + (map-get($color-rgb, 'green') * .7152) + (map-get($color-rgb, 'blue') * .0722)
|
||||
|
||||
@function findColorInvert($color)
|
||||
@if (colorLuminance($color) > 0.55)
|
||||
@return rgba(#000, 0.7)
|
||||
@else
|
||||
@return #fff
|
||||
|
||||
@function findLightColor($color)
|
||||
@if type-of($color) == 'color'
|
||||
$l: 96%
|
||||
@if lightness($color) > 96%
|
||||
$l: lightness($color)
|
||||
@return change-color($color, $lightness: $l)
|
||||
@return $background
|
||||
|
||||
@function findDarkColor($color)
|
||||
@if type-of($color) == 'color'
|
||||
$base-l: 29%
|
||||
$luminance: colorLuminance($color)
|
||||
$luminance-delta: (0.53 - $luminance)
|
||||
$target-l: round($base-l + ($luminance-delta * 53))
|
||||
@return change-color($color, $lightness: max($base-l, $target-l))
|
||||
@return $text-strong
|
||||
|
||||
@function bulmaRgba($color, $alpha)
|
||||
@if type-of($color) != 'color'
|
||||
@return $color
|
||||
@return rgba($color, $alpha)
|
||||
|
||||
@function bulmaDarken($color, $amount)
|
||||
@if type-of($color) != 'color'
|
||||
@return $color
|
||||
@return darken($color, $amount)
|
||||
|
||||
@function bulmaLighten($color, $amount)
|
||||
@if type-of($color) != 'color'
|
||||
@return $color
|
||||
@return lighten($color, $amount)
|
78
static/css/sass/bulma/utilities/initial-variables.sass
Normal file
78
static/css/sass/bulma/utilities/initial-variables.sass
Normal file
@ -0,0 +1,78 @@
|
||||
// Colors
|
||||
|
||||
$black: hsl(0, 0%, 4%) !default
|
||||
$black-bis: hsl(0, 0%, 7%) !default
|
||||
$black-ter: hsl(0, 0%, 14%) !default
|
||||
|
||||
$grey-darker: hsl(0, 0%, 21%) !default
|
||||
$grey-dark: hsl(0, 0%, 29%) !default
|
||||
$grey: hsl(0, 0%, 48%) !default
|
||||
$grey-light: hsl(0, 0%, 71%) !default
|
||||
$grey-lighter: hsl(0, 0%, 86%) !default
|
||||
$grey-lightest: hsl(0, 0%, 93%) !default
|
||||
|
||||
$white-ter: hsl(0, 0%, 96%) !default
|
||||
$white-bis: hsl(0, 0%, 98%) !default
|
||||
$white: hsl(0, 0%, 100%) !default
|
||||
|
||||
$orange: hsl(14, 100%, 53%) !default
|
||||
$yellow: hsl(48, 100%, 67%) !default
|
||||
$green: hsl(141, 53%, 53%) !default
|
||||
$turquoise: hsl(171, 100%, 41%) !default
|
||||
$cyan: hsl(204, 71%, 53%) !default
|
||||
$blue: hsl(217, 71%, 53%) !default
|
||||
$purple: hsl(271, 100%, 71%) !default
|
||||
$red: hsl(348, 86%, 61%) !default
|
||||
|
||||
// Typography
|
||||
|
||||
$family-sans-serif: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !default
|
||||
$family-monospace: monospace !default
|
||||
$render-mode: optimizeLegibility !default
|
||||
|
||||
$size-1: 3rem !default
|
||||
$size-2: 2.5rem !default
|
||||
$size-3: 2rem !default
|
||||
$size-4: 1.5rem !default
|
||||
$size-5: 1.25rem !default
|
||||
$size-6: 1rem !default
|
||||
$size-7: 0.75rem !default
|
||||
|
||||
$weight-light: 300 !default
|
||||
$weight-normal: 400 !default
|
||||
$weight-medium: 500 !default
|
||||
$weight-semibold: 600 !default
|
||||
$weight-bold: 700 !default
|
||||
|
||||
// Spacing
|
||||
|
||||
$block-spacing: 1.5rem !default
|
||||
|
||||
// Responsiveness
|
||||
|
||||
// The container horizontal gap, which acts as the offset for breakpoints
|
||||
$gap: 32px !default
|
||||
// 960, 1152, and 1344 have been chosen because they are divisible by both 12 and 16
|
||||
$tablet: 769px !default
|
||||
// 960px container + 4rem
|
||||
$desktop: 960px + (2 * $gap) !default
|
||||
// 1152px container + 4rem
|
||||
$widescreen: 1152px + (2 * $gap) !default
|
||||
$widescreen-enabled: true !default
|
||||
// 1344px container + 4rem
|
||||
$fullhd: 1344px + (2 * $gap) !default
|
||||
$fullhd-enabled: true !default
|
||||
|
||||
// Miscellaneous
|
||||
|
||||
$easing: ease-out !default
|
||||
$radius-small: 2px !default
|
||||
$radius: 4px !default
|
||||
$radius-large: 6px !default
|
||||
$radius-rounded: 290486px !default
|
||||
$speed: 86ms !default
|
||||
|
||||
// Flags
|
||||
|
||||
$variable-columns: true !default
|
||||
$rtl: false !default
|
285
static/css/sass/bulma/utilities/mixins.sass
Normal file
285
static/css/sass/bulma/utilities/mixins.sass
Normal file
@ -0,0 +1,285 @@
|
||||
@import "initial-variables"
|
||||
|
||||
=clearfix
|
||||
&::after
|
||||
clear: both
|
||||
content: " "
|
||||
display: table
|
||||
|
||||
=center($width, $height: 0)
|
||||
position: absolute
|
||||
@if $height != 0
|
||||
left: calc(50% - (#{$width} / 2))
|
||||
top: calc(50% - (#{$height} / 2))
|
||||
@else
|
||||
left: calc(50% - (#{$width} / 2))
|
||||
top: calc(50% - (#{$width} / 2))
|
||||
|
||||
=fa($size, $dimensions)
|
||||
display: inline-block
|
||||
font-size: $size
|
||||
height: $dimensions
|
||||
line-height: $dimensions
|
||||
text-align: center
|
||||
vertical-align: top
|
||||
width: $dimensions
|
||||
|
||||
=hamburger($dimensions)
|
||||
cursor: pointer
|
||||
display: block
|
||||
height: $dimensions
|
||||
position: relative
|
||||
width: $dimensions
|
||||
span
|
||||
background-color: currentColor
|
||||
display: block
|
||||
height: 1px
|
||||
left: calc(50% - 8px)
|
||||
position: absolute
|
||||
transform-origin: center
|
||||
transition-duration: $speed
|
||||
transition-property: background-color, opacity, transform
|
||||
transition-timing-function: $easing
|
||||
width: 16px
|
||||
&:nth-child(1)
|
||||
top: calc(50% - 6px)
|
||||
&:nth-child(2)
|
||||
top: calc(50% - 1px)
|
||||
&:nth-child(3)
|
||||
top: calc(50% + 4px)
|
||||
&:hover
|
||||
background-color: bulmaRgba(black, 0.05)
|
||||
// Modifers
|
||||
&.is-active
|
||||
span
|
||||
&:nth-child(1)
|
||||
transform: translateY(5px) rotate(45deg)
|
||||
&:nth-child(2)
|
||||
opacity: 0
|
||||
&:nth-child(3)
|
||||
transform: translateY(-5px) rotate(-45deg)
|
||||
|
||||
=overflow-touch
|
||||
-webkit-overflow-scrolling: touch
|
||||
|
||||
=placeholder
|
||||
$placeholders: ':-moz' ':-webkit-input' '-moz' '-ms-input'
|
||||
@each $placeholder in $placeholders
|
||||
&:#{$placeholder}-placeholder
|
||||
@content
|
||||
|
||||
// Responsiveness
|
||||
|
||||
=from($device)
|
||||
@media screen and (min-width: $device)
|
||||
@content
|
||||
|
||||
=until($device)
|
||||
@media screen and (max-width: $device - 1px)
|
||||
@content
|
||||
|
||||
=mobile
|
||||
@media screen and (max-width: $tablet - 1px)
|
||||
@content
|
||||
|
||||
=tablet
|
||||
@media screen and (min-width: $tablet), print
|
||||
@content
|
||||
|
||||
=tablet-only
|
||||
@media screen and (min-width: $tablet) and (max-width: $desktop - 1px)
|
||||
@content
|
||||
|
||||
=touch
|
||||
@media screen and (max-width: $desktop - 1px)
|
||||
@content
|
||||
|
||||
=desktop
|
||||
@media screen and (min-width: $desktop)
|
||||
@content
|
||||
|
||||
=desktop-only
|
||||
@if $widescreen-enabled
|
||||
@media screen and (min-width: $desktop) and (max-width: $widescreen - 1px)
|
||||
@content
|
||||
|
||||
=until-widescreen
|
||||
@if $widescreen-enabled
|
||||
@media screen and (max-width: $widescreen - 1px)
|
||||
@content
|
||||
|
||||
=widescreen
|
||||
@if $widescreen-enabled
|
||||
@media screen and (min-width: $widescreen)
|
||||
@content
|
||||
|
||||
=widescreen-only
|
||||
@if $widescreen-enabled and $fullhd-enabled
|
||||
@media screen and (min-width: $widescreen) and (max-width: $fullhd - 1px)
|
||||
@content
|
||||
|
||||
=until-fullhd
|
||||
@if $fullhd-enabled
|
||||
@media screen and (max-width: $fullhd - 1px)
|
||||
@content
|
||||
|
||||
=fullhd
|
||||
@if $fullhd-enabled
|
||||
@media screen and (min-width: $fullhd)
|
||||
@content
|
||||
|
||||
=ltr
|
||||
@if not $rtl
|
||||
@content
|
||||
|
||||
=rtl
|
||||
@if $rtl
|
||||
@content
|
||||
|
||||
=ltr-property($property, $spacing, $right: true)
|
||||
$normal: if($right, "right", "left")
|
||||
$opposite: if($right, "left", "right")
|
||||
@if $rtl
|
||||
#{$property}-#{$opposite}: $spacing
|
||||
@else
|
||||
#{$property}-#{$normal}: $spacing
|
||||
|
||||
=ltr-position($spacing, $right: true)
|
||||
$normal: if($right, "right", "left")
|
||||
$opposite: if($right, "left", "right")
|
||||
@if $rtl
|
||||
#{$opposite}: $spacing
|
||||
@else
|
||||
#{$normal}: $spacing
|
||||
|
||||
// Placeholders
|
||||
|
||||
=unselectable
|
||||
-webkit-touch-callout: none
|
||||
-webkit-user-select: none
|
||||
-moz-user-select: none
|
||||
-ms-user-select: none
|
||||
user-select: none
|
||||
|
||||
%unselectable
|
||||
+unselectable
|
||||
|
||||
=arrow($color: transparent)
|
||||
border: 3px solid $color
|
||||
border-radius: 2px
|
||||
border-right: 0
|
||||
border-top: 0
|
||||
content: " "
|
||||
display: block
|
||||
height: 0.625em
|
||||
margin-top: -0.4375em
|
||||
pointer-events: none
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform: rotate(-45deg)
|
||||
transform-origin: center
|
||||
width: 0.625em
|
||||
|
||||
%arrow
|
||||
+arrow
|
||||
|
||||
=block($spacing: $block-spacing)
|
||||
&:not(:last-child)
|
||||
margin-bottom: $spacing
|
||||
|
||||
%block
|
||||
+block
|
||||
|
||||
=delete
|
||||
@extend %unselectable
|
||||
-moz-appearance: none
|
||||
-webkit-appearance: none
|
||||
background-color: bulmaRgba($scheme-invert, 0.2)
|
||||
border: none
|
||||
border-radius: $radius-rounded
|
||||
cursor: pointer
|
||||
pointer-events: auto
|
||||
display: inline-block
|
||||
flex-grow: 0
|
||||
flex-shrink: 0
|
||||
font-size: 0
|
||||
height: 20px
|
||||
max-height: 20px
|
||||
max-width: 20px
|
||||
min-height: 20px
|
||||
min-width: 20px
|
||||
outline: none
|
||||
position: relative
|
||||
vertical-align: top
|
||||
width: 20px
|
||||
&::before,
|
||||
&::after
|
||||
background-color: $scheme-main
|
||||
content: ""
|
||||
display: block
|
||||
left: 50%
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform: translateX(-50%) translateY(-50%) rotate(45deg)
|
||||
transform-origin: center center
|
||||
&::before
|
||||
height: 2px
|
||||
width: 50%
|
||||
&::after
|
||||
height: 50%
|
||||
width: 2px
|
||||
&:hover,
|
||||
&:focus
|
||||
background-color: bulmaRgba($scheme-invert, 0.3)
|
||||
&:active
|
||||
background-color: bulmaRgba($scheme-invert, 0.4)
|
||||
// Sizes
|
||||
&.is-small
|
||||
height: 16px
|
||||
max-height: 16px
|
||||
max-width: 16px
|
||||
min-height: 16px
|
||||
min-width: 16px
|
||||
width: 16px
|
||||
&.is-medium
|
||||
height: 24px
|
||||
max-height: 24px
|
||||
max-width: 24px
|
||||
min-height: 24px
|
||||
min-width: 24px
|
||||
width: 24px
|
||||
&.is-large
|
||||
height: 32px
|
||||
max-height: 32px
|
||||
max-width: 32px
|
||||
min-height: 32px
|
||||
min-width: 32px
|
||||
width: 32px
|
||||
|
||||
%delete
|
||||
+delete
|
||||
|
||||
=loader
|
||||
animation: spinAround 500ms infinite linear
|
||||
border: 2px solid $grey-lighter
|
||||
border-radius: $radius-rounded
|
||||
border-right-color: transparent
|
||||
border-top-color: transparent
|
||||
content: ""
|
||||
display: block
|
||||
height: 1em
|
||||
position: relative
|
||||
width: 1em
|
||||
|
||||
%loader
|
||||
+loader
|
||||
|
||||
=overlay($offset: 0)
|
||||
bottom: $offset
|
||||
left: $offset
|
||||
position: absolute
|
||||
right: $offset
|
||||
top: $offset
|
||||
|
||||
%overlay
|
||||
+overlay
|
87
static/css/sass/labertasche.scss
Normal file
87
static/css/sass/labertasche.scss
Normal file
@ -0,0 +1,87 @@
|
||||
@charset "utf-8";
|
||||
|
||||
$family-sans-serif: "Open Sans", sans-serif;
|
||||
$family-code: "Fira Code", monospace;
|
||||
|
||||
$body-color: white;
|
||||
$strong-color: white;
|
||||
|
||||
$link: #feda5a;
|
||||
$link-hover: white;
|
||||
|
||||
$input-icon-color: #1d1e22;
|
||||
$input-icon-active-color: black;
|
||||
|
||||
$section-padding-large: 10rem 1.5rem;
|
||||
|
||||
$navbar-background-color: #feda6a;
|
||||
$navbar-item-color: black;
|
||||
$navbar-item-hover-color: white;
|
||||
$navbar-item-hover-background-color: #feda6a;
|
||||
$navbar-burger-color: black;
|
||||
|
||||
$footer-background-color: #393f4d;
|
||||
$footer-color: true;
|
||||
|
||||
$card-header-color: white;
|
||||
|
||||
$table-head-background-color: #feda6a;
|
||||
$table-body-background-color: white;
|
||||
|
||||
$box-background-color: #feda6a;
|
||||
$box-padding: 0.25rem;
|
||||
|
||||
$media-border-color: #feda6a;
|
||||
|
||||
$menu-item-color: white;
|
||||
$menu-item-hover-color: black;
|
||||
$menu-item-hover-background-color: #feda6a;
|
||||
$menu-label-font-size: 1em;
|
||||
|
||||
@import "bulma/utilities/_all";
|
||||
@import "bulma/base/_all";
|
||||
@import "bulma/elements/_all";
|
||||
@import "bulma/form/_all";
|
||||
@import "bulma/components/_all";
|
||||
@import "bulma/grid/_all";
|
||||
@import "bulma/helpers/_all";
|
||||
@import "bulma/layout/_all";
|
||||
|
||||
/* open-sans-regular - latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'),
|
||||
url('/static/css/open-sans-v18-latin-regular.woff2') format('woff2'); /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
}
|
||||
|
||||
canvas{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.bg-yayellow{
|
||||
background-color: #feda6a;
|
||||
}
|
||||
|
||||
.bg-deepmatte{
|
||||
background-color: #393f4d;
|
||||
}
|
||||
|
||||
.bg-darkslate{
|
||||
background-color: #1d1e22;
|
||||
}
|
||||
|
||||
.brdr-yayellow{
|
||||
border: 2px solid #feda6a;
|
||||
}
|
||||
|
||||
.bg-compliment{
|
||||
background-color: #384667;
|
||||
}
|
||||
|
||||
.fg-yellow{
|
||||
color: #feda6a;
|
||||
}
|
1
static/css/sass/sass-watch.cmd
Normal file
1
static/css/sass/sass-watch.cmd
Normal file
@ -0,0 +1 @@
|
||||
sass labertasche.scss ../labertasche.css --color --watch --no-source-map
|
86
static/css/sass/triangle.scss
Normal file
86
static/css/sass/triangle.scss
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
@mixin triangle ($size, $color, $direction) {
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
$width: nth($size, 1);
|
||||
$height: nth($size, length($size));
|
||||
|
||||
$foreground-color: nth($color, 1);
|
||||
$background-color: transparent !default;
|
||||
@if (length($color) == 2) {
|
||||
$background-color: nth($color, 2);
|
||||
}
|
||||
|
||||
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
|
||||
|
||||
$width: $width / 2;
|
||||
|
||||
@if $direction == up {
|
||||
border-left: $width solid $background-color;
|
||||
border-right: $width solid $background-color;
|
||||
border-bottom: $height solid $foreground-color;
|
||||
|
||||
} @else if $direction == right {
|
||||
border-top: $width solid $background-color;
|
||||
border-bottom: $width solid $background-color;
|
||||
border-left: $height solid $foreground-color;
|
||||
|
||||
} @else if $direction == down {
|
||||
border-left: $width solid $background-color;
|
||||
border-right: $width solid $background-color;
|
||||
border-top: $height solid $foreground-color;
|
||||
|
||||
} @else if $direction == left {
|
||||
border-top: $width solid $background-color;
|
||||
border-bottom: $width solid $background-color;
|
||||
border-right: $height solid $foreground-color;
|
||||
}
|
||||
}
|
||||
|
||||
@else if ($direction == up-right) or ($direction == up-left) {
|
||||
border-top: $height solid $foreground-color;
|
||||
|
||||
@if $direction == up-right {
|
||||
border-left: $width solid $background-color;
|
||||
|
||||
} @else if $direction == up-left {
|
||||
border-right: $width solid $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
@else if ($direction == down-right) or ($direction == down-left) {
|
||||
border-bottom: $height solid $foreground-color;
|
||||
|
||||
@if $direction == down-right {
|
||||
border-left: $width solid $background-color;
|
||||
|
||||
} @else if $direction == down-left {
|
||||
border-right: $width solid $background-color;
|
||||
}
|
||||
}
|
||||
|
||||
@else if ($direction == inset-up) {
|
||||
border-width: $height $width;
|
||||
border-style: solid;
|
||||
border-color: $background-color $background-color $foreground-color;
|
||||
}
|
||||
|
||||
@else if ($direction == inset-down) {
|
||||
border-width: $height $width;
|
||||
border-style: solid;
|
||||
border-color: $foreground-color $background-color $background-color;
|
||||
}
|
||||
|
||||
@else if ($direction == inset-right) {
|
||||
border-width: $width $height;
|
||||
border-style: solid;
|
||||
border-color: $background-color $background-color $background-color $foreground-color;
|
||||
}
|
||||
|
||||
@else if ($direction == inset-left) {
|
||||
border-width: $width $height;
|
||||
border-style: solid;
|
||||
border-color: $background-color $foreground-color $background-color $background-color;
|
||||
}
|
||||
}
|
7
static/js/Chart.bundle.min.js
vendored
Normal file
7
static/js/Chart.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
21
static/js/dashboard.js
Normal file
21
static/js/dashboard.js
Normal file
@ -0,0 +1,21 @@
|
||||
// # /**********************************************************************************
|
||||
// # * _author : Domeniko Gentner
|
||||
// # * _mail : code@tuxstash.de
|
||||
// # * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
// # * _license : This project is under MIT License
|
||||
// # *********************************************************************************/
|
||||
|
||||
function dashboard_mailsearch(search_txt)
|
||||
{
|
||||
let el = document.getElementById('mail-table');
|
||||
let children = el.children;
|
||||
for (let i = 0; i < children.length; i++ )
|
||||
{
|
||||
children[i].style.display = "none";
|
||||
let iTxt = children[i].innerText.replace(/(\r\n|\n|\r)/gm, "").trim();
|
||||
|
||||
if ( search_txt.value === iTxt.slice(0, search_txt.value.length)){
|
||||
children[i].style.display = "table-row";
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user