initial commit
This commit is contained in:
commit
a528892ac8
46 changed files with 2152 additions and 0 deletions
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
__pycache__/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
|
||||||
|
instance/*
|
||||||
|
|
||||||
|
static/uploads/*
|
||||||
|
static/gen/*
|
||||||
|
static/.webassets-cache*
|
373
LICENSE
Normal file
373
LICENSE
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
21
Pipfile
Normal file
21
Pipfile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[[source]]
|
||||||
|
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
|
||||||
|
flask = "*"
|
||||||
|
peewee = "*"
|
||||||
|
flask-uploads = "*"
|
||||||
|
flask-login = "*"
|
||||||
|
flask-wtf = "*"
|
||||||
|
markdown = "*"
|
||||||
|
nodeenv = "*"
|
||||||
|
webassets = {git = "https://github.com/miracle2k/webassets.git", ref = "master"}
|
||||||
|
flask-assets = "*"
|
||||||
|
|
||||||
|
|
||||||
|
[dev-packages]
|
128
Pipfile.lock
generated
Normal file
128
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "2de5ec90d8ee6f01b6383c466d82f6361f2326579862ae1b3c4014efd9e52fc8"
|
||||||
|
},
|
||||||
|
"host-environment-markers": {
|
||||||
|
"implementation_name": "cpython",
|
||||||
|
"implementation_version": "3.6.4",
|
||||||
|
"os_name": "posix",
|
||||||
|
"platform_machine": "x86_64",
|
||||||
|
"platform_python_implementation": "CPython",
|
||||||
|
"platform_release": "4.14.12-1-ARCH",
|
||||||
|
"platform_system": "Linux",
|
||||||
|
"platform_version": "#1 SMP PREEMPT Fri Jan 5 18:19:34 UTC 2018",
|
||||||
|
"python_full_version": "3.6.4",
|
||||||
|
"python_version": "3.6",
|
||||||
|
"sys_platform": "linux"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.python.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
|
||||||
|
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
|
||||||
|
],
|
||||||
|
"version": "==6.7"
|
||||||
|
},
|
||||||
|
"flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856",
|
||||||
|
"sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1"
|
||||||
|
],
|
||||||
|
"version": "==0.12.2"
|
||||||
|
},
|
||||||
|
"flask-assets": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6031527b89fb3509d1581d932affa5a79dd348cfffb58d0aef99a43461d47847"
|
||||||
|
],
|
||||||
|
"version": "==0.12"
|
||||||
|
},
|
||||||
|
"flask-login": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c815c1ac7b3e35e2081685e389a665f2c74d7e077cb93cecabaea352da4752ec"
|
||||||
|
],
|
||||||
|
"version": "==0.4.1"
|
||||||
|
},
|
||||||
|
"flask-uploads": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:53ecbd6033667d50ae02b63adebbaa33c7fc56c09e5293025810cf9d841ecb02"
|
||||||
|
],
|
||||||
|
"version": "==0.2.1"
|
||||||
|
},
|
||||||
|
"flask-wtf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac",
|
||||||
|
"sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36"
|
||||||
|
],
|
||||||
|
"version": "==0.14.2"
|
||||||
|
},
|
||||||
|
"itsdangerous": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
|
||||||
|
],
|
||||||
|
"version": "==0.24"
|
||||||
|
},
|
||||||
|
"jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||||
|
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||||
|
],
|
||||||
|
"version": "==2.10"
|
||||||
|
},
|
||||||
|
"markdown": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:9ba587db9daee7ec761cfc656272be6aabe2ed300fece21208e4aab2e457bc8f",
|
||||||
|
"sha256:a856869c7ff079ad84a3e19cd87a64998350c2b94e9e08e44270faef33400f81"
|
||||||
|
],
|
||||||
|
"version": "==2.6.11"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
|
||||||
|
],
|
||||||
|
"version": "==1.0"
|
||||||
|
},
|
||||||
|
"nodeenv": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:98835dab727f94a713eacc7234e3db6777a55cafb60f391485011899e5c818df"
|
||||||
|
],
|
||||||
|
"version": "==1.2.0"
|
||||||
|
},
|
||||||
|
"peewee": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2342067f48a779e35956a44cd547df883dda35153daa9fe994d970585aaec281"
|
||||||
|
],
|
||||||
|
"version": "==2.10.2"
|
||||||
|
},
|
||||||
|
"webassets": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:e7d9c8887343123fd5b32309b33167428cb1318cdda97ece12d0907fd69d38db"
|
||||||
|
],
|
||||||
|
"version": "==0.12.1"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
|
||||||
|
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
|
||||||
|
],
|
||||||
|
"version": "==0.14.1"
|
||||||
|
},
|
||||||
|
"wtforms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ffdf10bd1fa565b8233380cb77a304cd36fd55c73023e91d4b803c96bc11d46f"
|
||||||
|
],
|
||||||
|
"version": "==2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
4
README.md
Normal file
4
README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Website
|
||||||
|
|
||||||
|
This is my personal website. Made with Flask and other stuff I like (and some
|
||||||
|
I don't like, unfortunatly).
|
295
app.py
Normal file
295
app.py
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
import datetime
|
||||||
|
from urllib.parse import urlparse, urljoin
|
||||||
|
|
||||||
|
import flask
|
||||||
|
import flask_assets
|
||||||
|
import flask_login
|
||||||
|
import flask_uploads
|
||||||
|
import flask_wtf
|
||||||
|
import flask_wtf.file
|
||||||
|
import markdown
|
||||||
|
import peewee as pw
|
||||||
|
import werkzeug
|
||||||
|
import wtforms
|
||||||
|
|
||||||
|
from playhouse import flask_utils as pw_util
|
||||||
|
|
||||||
|
app = flask.Flask(__name__, instance_relative_config=True)
|
||||||
|
app.config.from_object('config')
|
||||||
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
db_wrapper = pw_util.FlaskDB(app)
|
||||||
|
|
||||||
|
bundles = {
|
||||||
|
'common_css': flask_assets.Bundle(
|
||||||
|
'css/lib/normalize.css',
|
||||||
|
'css/fonts.css',
|
||||||
|
'css/style.css',
|
||||||
|
output='gen/common.css',
|
||||||
|
filters=['autoprefixer6', 'cleancss'],
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
assets = flask_assets.Environment(app)
|
||||||
|
assets.register(bundles)
|
||||||
|
|
||||||
|
login_manager = flask_login.LoginManager()
|
||||||
|
login_manager.init_app(app)
|
||||||
|
login_manager.login_view = '.login'
|
||||||
|
login_manager.login_message_category = 'info'
|
||||||
|
|
||||||
|
photo_set = flask_uploads.UploadSet('photos', flask_uploads.IMAGES)
|
||||||
|
flask_uploads.configure_uploads(app, photo_set)
|
||||||
|
|
||||||
|
|
||||||
|
def photo_resize_url(photo, size):
|
||||||
|
if app.debug:
|
||||||
|
return photo_set.url(photo.filename)
|
||||||
|
|
||||||
|
return f"{photo_set.config.base_url}img{size}/{photo.filename}"
|
||||||
|
|
||||||
|
|
||||||
|
def image_resize_url(image, size):
|
||||||
|
if app.debug:
|
||||||
|
return f'static/images/{image}'
|
||||||
|
|
||||||
|
return f"/static/images/img{size}/{image}"
|
||||||
|
|
||||||
|
|
||||||
|
app.jinja_env.globals['photo_resize_url'] = photo_resize_url
|
||||||
|
app.jinja_env.globals['image_resize_url'] = image_resize_url
|
||||||
|
|
||||||
|
|
||||||
|
class Photo(db_wrapper.Model):
|
||||||
|
filename = pw.CharField()
|
||||||
|
title = pw.CharField(null=True)
|
||||||
|
description = pw.TextField(null=True)
|
||||||
|
timestamp = pw.DateTimeField(default=datetime.datetime.now)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def html_description(self):
|
||||||
|
return markdown.markdown(self.description, output_format='html5')
|
||||||
|
|
||||||
|
|
||||||
|
class User(flask_login.UserMixin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoginForm(flask_wtf.FlaskForm):
|
||||||
|
password = wtforms.fields.PasswordField('Password')
|
||||||
|
|
||||||
|
|
||||||
|
class UploadPhotoForm(flask_wtf.FlaskForm):
|
||||||
|
photo = wtforms.fields.FileField('Photo', validators=[
|
||||||
|
flask_wtf.file.FileRequired(),
|
||||||
|
flask_wtf.file.FileAllowed(photo_set, 'Images only!')
|
||||||
|
])
|
||||||
|
title = wtforms.fields.StringField('Title')
|
||||||
|
description = wtforms.fields.TextAreaField('Description')
|
||||||
|
|
||||||
|
|
||||||
|
class EditPhotoForm(flask_wtf.FlaskForm):
|
||||||
|
photo = wtforms.fields.FileField('Photo', validators=[
|
||||||
|
flask_wtf.file.FileAllowed(photo_set, 'Images only!')
|
||||||
|
])
|
||||||
|
title = wtforms.fields.StringField('Title')
|
||||||
|
description = wtforms.fields.TextAreaField('Description')
|
||||||
|
|
||||||
|
|
||||||
|
class ConfirmForm(flask_wtf.FlaskForm):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def flash_errors(form):
|
||||||
|
"""Flash all errors in a form."""
|
||||||
|
for field in form:
|
||||||
|
for error in field.errors:
|
||||||
|
flask.flash(("Error in {} field: {}"
|
||||||
|
.format(field.label.text, error)),
|
||||||
|
'error'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(user_id):
|
||||||
|
if user_id != app.config['LOGIN']:
|
||||||
|
return
|
||||||
|
|
||||||
|
user = User()
|
||||||
|
user.id = user_id
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def is_safe_url(target):
|
||||||
|
ref_url = urlparse(flask.request.host_url)
|
||||||
|
test_url = urlparse(urljoin(flask.request.host_url, target))
|
||||||
|
return test_url.scheme in ('http', 'https') and \
|
||||||
|
ref_url.netloc == test_url.netloc
|
||||||
|
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def not_found(e):
|
||||||
|
return flask.render_template('error/{}.html'.format(e.code)), e.code
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return flask.render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/photo/', defaults={'page': 1})
|
||||||
|
@app.route('/photo/page/<int:page>')
|
||||||
|
def photography(page):
|
||||||
|
photos = Photo.select().order_by(Photo.timestamp.desc()).paginate(page, 9)
|
||||||
|
return flask.render_template('photography.html', photos=photos)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/photo/<int:photo_id>')
|
||||||
|
def view_photo(photo_id):
|
||||||
|
query = Photo.select().order_by(Photo.timestamp.desc())
|
||||||
|
|
||||||
|
photo = pw_util.get_object_or_404(query, Photo.id == photo_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
prev = query.where(Photo.timestamp < photo.timestamp).get()
|
||||||
|
|
||||||
|
except Photo.DoesNotExist:
|
||||||
|
prev = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
next = (query.order_by(Photo.timestamp.asc())
|
||||||
|
.where(Photo.timestamp > photo.timestamp).get())
|
||||||
|
|
||||||
|
except Photo.DoesNotExist:
|
||||||
|
next = None
|
||||||
|
|
||||||
|
return flask.render_template('view_photo.html',
|
||||||
|
photo=photo,
|
||||||
|
prev=prev,
|
||||||
|
next=next)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/me')
|
||||||
|
def me():
|
||||||
|
return flask.render_template('me.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/login', methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
form = LoginForm()
|
||||||
|
|
||||||
|
if flask_login.current_user.is_authenticated:
|
||||||
|
return flask.redirect(flask.url_for('.admin'))
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
if form.password.data == app.config['LOGIN']:
|
||||||
|
user = User()
|
||||||
|
user.id = app.config['LOGIN']
|
||||||
|
flask_login.login_user(user)
|
||||||
|
|
||||||
|
next = flask.request.args.get('next')
|
||||||
|
|
||||||
|
if not is_safe_url(next):
|
||||||
|
return flask.abort(400)
|
||||||
|
|
||||||
|
flask.flash('Login successful!', 'success')
|
||||||
|
return flask.redirect(next or flask.url_for('.admin'))
|
||||||
|
|
||||||
|
else:
|
||||||
|
flask.flash('Wrong password.', 'error')
|
||||||
|
|
||||||
|
return flask.render_template('login.html', form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
if flask_login.current_user.is_authenticated:
|
||||||
|
flask_login.logout_user()
|
||||||
|
else:
|
||||||
|
flask.flash('You have to be logged in to log out! ಠ_ಠ', 'error')
|
||||||
|
|
||||||
|
return flask.redirect(flask.url_for('.index'))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/')
|
||||||
|
@flask_login.login_required
|
||||||
|
def admin():
|
||||||
|
return flask.render_template('admin/admin.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/photos/')
|
||||||
|
@flask_login.login_required
|
||||||
|
def admin_photos():
|
||||||
|
photos = Photo.select().order_by(Photo.timestamp.desc())
|
||||||
|
return flask.render_template('admin/photos.html', photos=photos)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/photos/<int:photo_id>', methods=['GET', 'POST'])
|
||||||
|
@flask_login.login_required
|
||||||
|
def admin_edit_photo(photo_id):
|
||||||
|
photo = pw_util.get_object_or_404(Photo, Photo.id == photo_id)
|
||||||
|
|
||||||
|
form = EditPhotoForm(
|
||||||
|
werkzeug.datastructures.CombinedMultiDict((flask.request.files,
|
||||||
|
flask.request.form)),
|
||||||
|
obj=photo
|
||||||
|
)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
if form.photo.data:
|
||||||
|
photo.filename = photo_set.save(form.photo.data)
|
||||||
|
|
||||||
|
photo.title = form.title.data
|
||||||
|
photo.description = form.description.data
|
||||||
|
|
||||||
|
photo.save()
|
||||||
|
|
||||||
|
flask.flash('Photo updated!', 'success')
|
||||||
|
|
||||||
|
else:
|
||||||
|
flash_errors(form)
|
||||||
|
|
||||||
|
return flask.render_template('admin/photo.html', form=form, photo=photo)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/photos/new', methods=['GET', 'POST'])
|
||||||
|
@flask_login.login_required
|
||||||
|
def admin_new_photo():
|
||||||
|
form = UploadPhotoForm()
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
filename = photo_set.save(form.photo.data)
|
||||||
|
photo = Photo.create(filename=filename,
|
||||||
|
title=form.title.data or None,
|
||||||
|
description=form.description.data or None
|
||||||
|
)
|
||||||
|
|
||||||
|
flask.flash('Photo uploaded successfully!', 'success')
|
||||||
|
return flask.redirect(flask.url_for('admin_edit_photo',
|
||||||
|
photo_id=photo.id))
|
||||||
|
|
||||||
|
else:
|
||||||
|
flash_errors(form)
|
||||||
|
|
||||||
|
return flask.render_template('admin/new_photo.html', form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admin/photos/remove/<int:photo_id>', methods=['GET', 'POST'])
|
||||||
|
@flask_login.login_required
|
||||||
|
def admin_remove_photo(photo_id):
|
||||||
|
photo = pw_util.get_object_or_404(Photo, Photo.id == photo_id)
|
||||||
|
|
||||||
|
form = ConfirmForm()
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
photo.delete_instance()
|
||||||
|
flask.flash('Photo removed.', 'success')
|
||||||
|
return flask.redirect(flask.url_for('admin_photos'))
|
||||||
|
|
||||||
|
else:
|
||||||
|
flash_errors(form)
|
||||||
|
|
||||||
|
return flask.render_template('admin/remove_photo.html',
|
||||||
|
form=form,
|
||||||
|
photo=photo)
|
11
config.py
Normal file
11
config.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
SECRET_KEY = 'secret!'
|
||||||
|
TEMPLATES_AUTO_RELOAD = True
|
||||||
|
|
||||||
|
LOGIN = 'supersecretpassword'
|
||||||
|
|
||||||
|
DATABASE = 'sqlite:///instance/db.sqlite'
|
||||||
|
|
||||||
|
UPLOADS_DEFAULT_DEST = 'static/uploads'
|
||||||
|
UPLOADS_DEFAULT_URL = 'http://localhost:5000/static/uploads/'
|
||||||
|
|
||||||
|
AUTOPREFIXER_BIN = 'postcss'
|
3
npm-requirements.txt
Normal file
3
npm-requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
postcss-cli@4.1.1
|
||||||
|
autoprefixer@7.2.4
|
||||||
|
clean-css-cli@4.1.10
|
66
static/css/fonts.css
Normal file
66
static/css/fonts.css
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-Roman.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-Roman.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-Italic.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-Italic.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-SemiBold.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-SemiBold.woff') format('woff');
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-SemiBoldItalic.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-SemiBoldItalic.woff') format('woff');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-Bold.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-Bold.woff') format('woff');
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Crimson Text";
|
||||||
|
src: url('/static/fonts/crimsontext/Crimson-BoldItalic.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/crimsontext/Crimson-BoldItalic.woff') format('woff');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Fira Mono";
|
||||||
|
src: url('/static/fonts/firamono/FiraMono-Regular.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/firamono/FiraMono-Regular.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Fira Mono";
|
||||||
|
src: url('/static/fonts/firamono/FiraMono-Bold.woff2') format('woff2'),
|
||||||
|
url('/static/fonts/firamono/FiraMono-Bold.woff') format('woff');
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
447
static/css/lib/normalize.css
vendored
Normal file
447
static/css/lib/normalize.css
vendored
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in
|
||||||
|
* IE on Windows Phone and in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-ms-text-size-adjust: 100%; /* 2 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers (opinionated).
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
nav,
|
||||||
|
section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
main { /* 1 */
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct margin in IE 8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the gray background on active links in IE 10.
|
||||||
|
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent; /* 1 */
|
||||||
|
-webkit-text-decoration-skip: objects; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font style in Android 4.3-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct background and color in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in iOS 4-7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the overflow in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers (opinionated).
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: sans-serif; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||||
|
* controls in Android 4.
|
||||||
|
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"], /* 1 */
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct display in IE 9-.
|
||||||
|
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: inline-block; /* 1 */
|
||||||
|
vertical-align: baseline; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10-.
|
||||||
|
* 2. Remove the padding in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details, /* 1 */
|
||||||
|
menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scripting
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hidden
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
178
static/css/style.css
Normal file
178
static/css/style.css
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word; /* legacy */
|
||||||
|
word-break: break-word; /* for WebKit/Chrome */
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper > * {
|
||||||
|
/* Fixes overflowing content (anything other than "overflow: visible")
|
||||||
|
* in grid. Won't overflow without this. */
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family: "Crimson Text", serif;
|
||||||
|
text-decoration-skip: ink;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 1rem;
|
||||||
|
grid-template-columns: minmax(0, 40rem);
|
||||||
|
padding: 1rem 1rem 5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code, .email {
|
||||||
|
font-family: "Fira Mono", monospace;
|
||||||
|
font-size: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sitenav {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: #666;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 1rem;
|
||||||
|
grid-template-columns: repeat(auto-fill, 200px);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid img {
|
||||||
|
max-height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-image {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-image img {
|
||||||
|
max-height: 700px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-image nav {
|
||||||
|
align-self: center;
|
||||||
|
margin-top: 2rem;
|
||||||
|
max-width: 24rem;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-image form {
|
||||||
|
margin-top: 2rem;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prev {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
margin: 1rem 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field > label:first-child {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 30rem;
|
||||||
|
height: 15rem;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flashes {
|
||||||
|
justify-self: center;
|
||||||
|
text-align: center;
|
||||||
|
list-style: none;
|
||||||
|
margin: .5rem 1rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.flash {
|
||||||
|
min-width: 15em;
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
margin: .5rem auto;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
background-color: #c9f7dd;
|
||||||
|
border: 1px solid #62d895;
|
||||||
|
color: #004d21;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
background-color: #cbdef5;
|
||||||
|
border: 1px solid #6797d0;
|
||||||
|
color: #042246;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
background-color: #ffd9d0;
|
||||||
|
border: 1px solid #ff9073;
|
||||||
|
color: #6c1600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 60rem) {
|
||||||
|
.wrapper {
|
||||||
|
grid-template-columns: 14rem 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
justify-content: left;
|
||||||
|
}
|
||||||
|
}
|
BIN
static/fonts/crimsontext/Crimson-Bold.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-Bold.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Bold.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-Bold.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-BoldItalic.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-BoldItalic.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-BoldItalic.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Italic.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-Italic.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Italic.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-Italic.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Roman-webfont.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-Roman-webfont.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Roman.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-Roman.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-Roman.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-Roman.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-SemiBold.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-SemiBold.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-SemiBold.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-SemiBold.woff2
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-SemiBoldItalic.woff
Normal file
BIN
static/fonts/crimsontext/Crimson-SemiBoldItalic.woff
Normal file
Binary file not shown.
BIN
static/fonts/crimsontext/Crimson-SemiBoldItalic.woff2
Normal file
BIN
static/fonts/crimsontext/Crimson-SemiBoldItalic.woff2
Normal file
Binary file not shown.
93
static/fonts/crimsontext/LICENSE.txt
Normal file
93
static/fonts/crimsontext/LICENSE.txt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright (c) 2012-2014, The Crimson Project Developers.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
static/fonts/firamono/FiraMono-Bold.woff
Normal file
BIN
static/fonts/firamono/FiraMono-Bold.woff
Normal file
Binary file not shown.
BIN
static/fonts/firamono/FiraMono-Bold.woff2
Normal file
BIN
static/fonts/firamono/FiraMono-Bold.woff2
Normal file
Binary file not shown.
BIN
static/fonts/firamono/FiraMono-Regular.woff
Normal file
BIN
static/fonts/firamono/FiraMono-Regular.woff
Normal file
Binary file not shown.
BIN
static/fonts/firamono/FiraMono-Regular.woff2
Normal file
BIN
static/fonts/firamono/FiraMono-Regular.woff2
Normal file
Binary file not shown.
94
static/fonts/firamono/LICENSE
Normal file
94
static/fonts/firamono/LICENSE
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||||
|
with Reserved Font Name < Fira >,
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
8
static/js/emaildecode.js
Normal file
8
static/js/emaildecode.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
var emails = document.getElementsByClassName("email");
|
||||||
|
|
||||||
|
for (var i = 0; i < emails.length; i++) {
|
||||||
|
var b64 = emails[i].innerHTML;
|
||||||
|
var decoded = window.atob(b64);
|
||||||
|
emails[i].innerHTML = decoded;
|
||||||
|
emails[i].href = "mailto:" + decoded;
|
||||||
|
}
|
112
static/rupusreinefjord_pubkey.asc
Normal file
112
static/rupusreinefjord_pubkey.asc
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=g3+W
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
12
templates/admin/admin.html
Normal file
12
templates/admin/admin.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% set navbar = [
|
||||||
|
(url_for('admin_new_photo'), 'new_photo', 'Upload new photo'),
|
||||||
|
(url_for('admin_photos'), 'photos', 'View photos'),
|
||||||
|
(url_for('logout'), 'logout', 'Logout')
|
||||||
|
] %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
<h1><a href="{{ url_for('admin') }}" class="nav-item">administration</a></h1>
|
||||||
|
{% endblock %}
|
26
templates/admin/new_photo.html
Normal file
26
templates/admin/new_photo.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends 'admin/admin.html' %}
|
||||||
|
|
||||||
|
{% set title = 'New photo' %}
|
||||||
|
|
||||||
|
{% set active_page = 'new_photo' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<div class="field">
|
||||||
|
{{ form.photo.label }}
|
||||||
|
{{ form.photo }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
{{ form.title.label }}
|
||||||
|
{{ form.title }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
{{ form.description.label }}
|
||||||
|
{{ form.description }}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
34
templates/admin/photo.html
Normal file
34
templates/admin/photo.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{% extends 'admin/admin.html' %}
|
||||||
|
|
||||||
|
{% set title = photo.title or 'Unnamed photo' %}
|
||||||
|
|
||||||
|
{% set active_page = 'photos' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main class="view-image">
|
||||||
|
<img src="{{ photo_resize_url(photo, 800) }}">
|
||||||
|
|
||||||
|
<h2>{{ photo.title or 'Unnamed photo' }}</h2>
|
||||||
|
{{ photo.description or 'No description'}}
|
||||||
|
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<div class="field">
|
||||||
|
{{ form.photo.label }}
|
||||||
|
{{ form.photo }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
{{ form.title.label }}
|
||||||
|
{{ form.title }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
{{ form.description.label }}
|
||||||
|
{{ form.description }}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
<div class="field">
|
||||||
|
<a href="{{ url_for('admin_remove_photo', photo_id=photo.id) }}">Remove</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
18
templates/admin/photos.html
Normal file
18
templates/admin/photos.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends 'admin/admin.html' %}
|
||||||
|
|
||||||
|
{% set title = 'Photos' %}
|
||||||
|
|
||||||
|
{% set active_page = 'photos' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<h2>Photos</h2>
|
||||||
|
{% if photos %}
|
||||||
|
<ul>
|
||||||
|
{% for photo in photos %}
|
||||||
|
<li><a href="{{ url_for('admin_edit_photo', photo_id=photo.id) }}">{{ photo.timestamp.strftime("%Y-%m-%d %H:%M:%S") }} - {{ photo.title or photo.filename }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
26
templates/admin/remove_photo.html
Normal file
26
templates/admin/remove_photo.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends 'admin/admin.html' %}
|
||||||
|
|
||||||
|
{% set title = 'Remove ' + (photo.title or 'unnamed photo') %}
|
||||||
|
|
||||||
|
{% set active_page = 'photos' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main class="view-image">
|
||||||
|
<img src="{{ photo_resize_url(photo, 800) }}">
|
||||||
|
|
||||||
|
<h2>{{ photo.title or 'Unnamed photo' }}</h2>
|
||||||
|
{{ photo.description or 'No description'}}
|
||||||
|
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<h2>Remove photo?</h2>
|
||||||
|
<p>Are you sure?</p>
|
||||||
|
<div class="field">
|
||||||
|
<button type="submit">Remove</button>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<a href="{{ url_for('admin_edit_photo', photo_id=photo.id) }}">No, take me away from here</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
44
templates/base.html
Normal file
44
templates/base.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<title>{{ title }} | reinefjord</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<!--
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
|
||||||
|
-->
|
||||||
|
|
||||||
|
{% assets 'common_css' %}
|
||||||
|
<link rel="stylesheet" href="{{ ASSET_URL }}">
|
||||||
|
{% endassets %}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<header>
|
||||||
|
{% block header %}{% endblock %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
{% for href, id, caption in navbar %}
|
||||||
|
<li><a href="{{ href|e }}" class="nav-item {% if id == active_page %}active{% endif %}">{{ caption|e }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
|
{% if messages %}
|
||||||
|
<ul class="flashes">
|
||||||
|
{% for category, message in messages %}
|
||||||
|
<li class="flash {{ category }}">{{ message|safe }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
templates/error/404.html
Normal file
10
templates/error/404.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% set title = "404 - Not found" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<h2>404 — Not found</h2>
|
||||||
|
<p>The page you were looking for was not found :(</p>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
11
templates/error/500.html
Normal file
11
templates/error/500.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% set title = "500 - Internal Server Error" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<h2>500 — Internal Server Error</h2>
|
||||||
|
<p>It seems like something broke on the server end. Sorry! :S</p>
|
||||||
|
<p>Try again or try something else.</p>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
13
templates/index.html
Normal file
13
templates/index.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% set active_page = 'index' %}
|
||||||
|
{% set title = '^_^' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h2>Welcome</h2>
|
||||||
|
<p>... to my fancy webpage!</p>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{% endblock %}
|
11
templates/layout.html
Normal file
11
templates/layout.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% set navbar = [
|
||||||
|
(url_for('index'), 'index', 'Home'),
|
||||||
|
(url_for('photography'), 'photo', 'Photography'),
|
||||||
|
(url_for('me'), 'me', 'Find me')
|
||||||
|
] %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
<h1><a href="{{ url_for('index') }}" class="nav-item">rupus reinefjord</a></h1>
|
||||||
|
{% endblock %}
|
20
templates/login.html
Normal file
20
templates/login.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% set active_page = None %}
|
||||||
|
{% set title = 'Login' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h2>Login</h2>
|
||||||
|
<form method="POST">
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
<div class="field">
|
||||||
|
{{ form.password.label }}
|
||||||
|
{{ form.password }}
|
||||||
|
</div>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{% endblock %}
|
31
templates/me.html
Normal file
31
templates/me.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% set active_page = 'me' %}
|
||||||
|
{% set title = 'Find me' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<h2>Find me</h2>
|
||||||
|
<dl>
|
||||||
|
<dt>GitHub:</dt>
|
||||||
|
<dd><a href="https://github.com/reinefjord">reinefjord</a></dd>
|
||||||
|
<dt>Instagram:</dt>
|
||||||
|
<dd><a href="https://www.instagram.com/rupusreinefjord/">@rupusreinefjord</a></dd>
|
||||||
|
<dt>Flickr:</dt>
|
||||||
|
<dd><a href="https://www.flickr.com/photos/koltrast_">koltrast_</a></dd>
|
||||||
|
<dt>Keybase:</dt>
|
||||||
|
<dd><a href="https://keybase.io/rupus">rupus</a></dd>
|
||||||
|
</dl>
|
||||||
|
<h2>Contact me</h2>
|
||||||
|
<dl>
|
||||||
|
<dt>Email:</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="mailto:firstname(at)lastname(dot)net" class="email">cnVwdXNAa2x0cnN0LnNl</a>
|
||||||
|
<noscript><p>Please activate javascript to see the address. Hint: it is <span class="email">firstname(at)lastname(dot)net</span></p></noscript>
|
||||||
|
</dd>
|
||||||
|
<dt>PGP:</dt>
|
||||||
|
<dd><a href="{{ url_for('static', filename='rupusreinefjord_pubkey.asc') }}"><code>E275 C3F0 8765 EBC3 C906 66F4 E918 999B E668 8BD2</code></a></dd>
|
||||||
|
</dl>
|
||||||
|
<script src="{{ url_for('static', filename='js/emaildecode.js') }}"></script>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
20
templates/photography.html
Normal file
20
templates/photography.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% set active_page = 'photo' %}
|
||||||
|
{% set title = 'Photography' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main>
|
||||||
|
<h2>Photography</h2>
|
||||||
|
<div class="photo-grid">
|
||||||
|
{% for photo in photos %}
|
||||||
|
<a href="{{ url_for('view_photo', photo_id=photo.id) }}">
|
||||||
|
<img srcset="{{ photo_resize_url(photo, 200) }},
|
||||||
|
{{ photo_resize_url(photo, 300) }} 1.5x,
|
||||||
|
{{ photo_resize_url(photo, 400) }} 2x"
|
||||||
|
src="{{ photo_resize_url(photo, 200) }}">
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
32
templates/view_photo.html
Normal file
32
templates/view_photo.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% set active_page = 'photo' %}
|
||||||
|
{% set title = 'Photography' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main class="view-image">
|
||||||
|
<img srcset="{{ photo_resize_url(photo, 800) }},
|
||||||
|
{{ photo_resize_url(photo, 1200) }} 1.5x,
|
||||||
|
{{ photo_resize_url(photo, 1600) }} 2x"
|
||||||
|
src="{{ photo_resize_url(photo, 800) }}">
|
||||||
|
|
||||||
|
<article>
|
||||||
|
{% if photo.title %}
|
||||||
|
<h2>{{ photo.title }}</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% if photo.description %}
|
||||||
|
{{ photo.html_description|safe }}
|
||||||
|
{% endif %}
|
||||||
|
{% if next or prev %}
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
{% if next %}
|
||||||
|
<a href="{{ url_for('view_photo', photo_id=next.id) }}" class="nav-item next">← Next</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if prev %}
|
||||||
|
<a href="{{ url_for('view_photo', photo_id=prev.id) }}" class="nav-item prev">Previous →</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
Reference in a new issue