commit d4ae47a7462538b0d61f595f7478a8d0ae7295b2 Author: Jaap Joris Vens Date: Wed Mar 27 16:49:14 2019 +0100 first commit :) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d646835 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +__pycache__/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d20434 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +Django Simple CMS +================= + +Simple CMS app with models that should suit everyone's small website needs. + +Installation +------------ + + pip install git+https://github.com/rtts/django-simplecms.git + +Configuration +------------- + +Add the following to your Django settings: + + INSTALLED_APPS += [ + 'cms', + 'ckeditor', + 'embed_video', + 'easy_thumbnails', + ] + + SECTION_TYPES = [ + ('normal', 'Normaal'), + ] + + SECTION_COLORS = [ + (1, 'Licht'), + (2, 'Donker'), + ] + +And add the following to your URL patterns: + + urlpatterns += [ + path('accounts/', include('django.contrib.auth.urls')), + path('', include('cms.urls', namespace='cms')), + ] diff --git a/cms/__init__.py b/cms/__init__.py new file mode 100644 index 0000000..fbe6e55 --- /dev/null +++ b/cms/__init__.py @@ -0,0 +1 @@ +default_app_config = 'cms.apps.CmsConfig' diff --git a/cms/admin.py b/cms/admin.py new file mode 100644 index 0000000..f30f82e --- /dev/null +++ b/cms/admin.py @@ -0,0 +1,29 @@ +from django.contrib import admin +from django.utils.text import Truncator +from django.utils.safestring import mark_safe +from django.utils.translation import gettext_lazy as _ +from .models import Page, Section, Config + +class InlineSectionAdmin(admin.StackedInline): + model = Section + extra = 0 + +@admin.register(Page) +class PageAdmin(admin.ModelAdmin): + prepopulated_fields = {'slug': ('title',)} + inlines = [InlineSectionAdmin] + +@admin.register(Config) +class ConfigAdmin(admin.ModelAdmin): + list_display = ['__str__', 'get_content'] + exclude = ['parameter'] + + def get_content(self, obj): + return mark_safe(Truncator(obj.content).words(50, html=True)) + get_content.short_description = _('content') + + def has_add_permission(self, request): + return False + + def has_delete_permission(self, *args, **kwargs): + return False diff --git a/cms/apps.py b/cms/apps.py new file mode 100644 index 0000000..b4604bd --- /dev/null +++ b/cms/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + +class CmsConfig(AppConfig): + name = 'cms' + verbose_name = _('Content Management System') diff --git a/cms/forms.py b/cms/forms.py new file mode 100644 index 0000000..9f74e08 --- /dev/null +++ b/cms/forms.py @@ -0,0 +1,9 @@ +from django import forms +from .models import Page, Section + +class PageForm(forms.ModelForm): + class Meta: + model = Page + fields = '__all__' + +SectionFormSet = forms.inlineformset_factory(Page, Section, exclude='__all__', extra=0) diff --git a/cms/locale/nl/LC_MESSAGES/django.mo b/cms/locale/nl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..89d1cd7 Binary files /dev/null and b/cms/locale/nl/LC_MESSAGES/django.mo differ diff --git a/cms/locale/nl/LC_MESSAGES/django.po b/cms/locale/nl/LC_MESSAGES/django.po new file mode 100644 index 0000000..fdd44f7 --- /dev/null +++ b/cms/locale/nl/LC_MESSAGES/django.po @@ -0,0 +1,111 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-03-27 12:21+0000\n" +"PO-Revision-Date: 2019-03-27 13:24+0100\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: admin.py:23 models.py:37 +msgid "content" +msgstr "inhoud" + +#: apps.py:6 +msgid "Content Management System" +msgstr "Content Beheer" + +#: models.py:11 models.py:32 +msgid "position" +msgstr "positie" + +#: models.py:12 models.py:33 +msgid "title" +msgstr "titel" + +#: models.py:13 +msgid "slug" +msgstr "slug" + +#: models.py:13 +msgid "A short identifier to use in URLs" +msgstr "Een korte identifier voor gebruik in URL’s" + +#: models.py:14 +msgid "visible in menu" +msgstr "zichtbaar in het menu" + +#: models.py:26 templates/cms/edit.html:10 +msgid "Page" +msgstr "Pagina" + +#: models.py:27 +msgid "Pages" +msgstr "Pagina’s" + +#: models.py:31 +msgid "page" +msgstr "pagina" + +#: models.py:34 +msgid "section type" +msgstr "sectie type" + +#: models.py:35 +msgid "color" +msgstr "kleur" + +#: models.py:38 +msgid "image" +msgstr "afbeelding" + +#: models.py:39 +msgid "video" +msgstr "video" + +#: models.py:40 +msgid "button text" +msgstr "button tekst" + +#: models.py:41 +msgid "button link" +msgstr "button link" + +#: models.py:50 +msgid "section" +msgstr "sectie" + +#: models.py:51 +msgid "sections" +msgstr "secties" + +#: models.py:56 +msgid "Footer" +msgstr "Footer" + +#: models.py:66 +msgid "configuration parameter" +msgstr "configuratieparameter" + +#: models.py:67 +msgid "configuration parameters" +msgstr "configuratieparameters" + +#: templates/cms/edit.html:20 +msgid "Section" +msgstr "Sectie" + +#: templates/cms/edit.html:27 +msgid "Save" +msgstr "Opslaan" diff --git a/cms/migrations/0001_initial.py b/cms/migrations/0001_initial.py new file mode 100644 index 0000000..55a67b9 --- /dev/null +++ b/cms/migrations/0001_initial.py @@ -0,0 +1,66 @@ +# Generated by Django 2.1.7 on 2019-03-20 13:53 + +import ckeditor.fields +from django.db import migrations, models +import django.db.models.deletion +import embed_video.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Config', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('parameter', models.PositiveIntegerField(choices=[(10, 'Footer')], unique=True)), + ('content', ckeditor.fields.RichTextField(blank=True, verbose_name='Inhoud')), + ], + options={ + 'verbose_name': 'configuration parameter', + 'verbose_name_plural': 'configuration parameters', + 'ordering': ['parameter'], + }, + ), + migrations.CreateModel( + name='Page', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('position', models.PositiveIntegerField(blank=True, verbose_name='position')), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')), + ('menu', models.BooleanField(default=True, verbose_name='visible in menu')), + ], + options={ + 'verbose_name': 'Page', + 'verbose_name_plural': 'Pages', + 'ordering': ['position'], + }, + ), + migrations.CreateModel( + name='Section', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('position', models.PositiveIntegerField(blank=True, verbose_name='position')), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')), + ('color', models.PositiveIntegerField(choices=[(1, 'Licht'), (2, 'Donker')], default=1, verbose_name='color')), + ('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')), + ('image', models.ImageField(blank=True, upload_to='', verbose_name='image')), + ('video', embed_video.fields.EmbedVideoField(blank=True, help_text='Paste a YouTube, Vimeo, or SoundCloud link', verbose_name='video')), + ('button_text', models.CharField(blank=True, max_length=255, verbose_name='button text')), + ('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')), + ('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='cms.Page', verbose_name='page')), + ], + options={ + 'verbose_name': 'section', + 'verbose_name_plural': 'sections', + 'ordering': ['position'], + }, + ), + ] diff --git a/cms/migrations/__init__.py b/cms/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cms/models.py b/cms/models.py new file mode 100644 index 0000000..3e3ab68 --- /dev/null +++ b/cms/models.py @@ -0,0 +1,68 @@ +from django.db import models +from django.urls import reverse +from django.conf import settings +from django.utils.translation import gettext_lazy as _ + +from ckeditor.fields import RichTextField +from embed_video.fields import EmbedVideoField +from numberedmodel.models import NumberedModel + +class Page(NumberedModel): + position = models.PositiveIntegerField(_('position'), blank=True) + title = models.CharField(_('title'), max_length=255) + slug = models.SlugField(_('slug'), help_text=_('A short identifier to use in URLs'), blank=True, unique=True) + menu = models.BooleanField(_('visible in menu'), default=True) + + def __str__(self): + return '{}. {}'.format(self.position, self.title) + + def get_absolute_url(self): + if self.slug: + return reverse('cms:page', args=[self.slug]) + else: + return reverse('cms:homepage') + + class Meta: + verbose_name = _('Page') + verbose_name_plural = _('Pages') + ordering = ['position'] + +class Section(NumberedModel): + page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT) + position = models.PositiveIntegerField(_('position'), blank=True) + title = models.CharField(_('title'), max_length=255) + type = models.CharField(_('section type'), max_length=16, default=settings.SECTION_TYPES[0][0], choices=settings.SECTION_TYPES) + color = models.PositiveIntegerField(_('color'), default=1, choices=settings.SECTION_COLORS) + + content = RichTextField(_('content'), blank=True) + image = models.ImageField(_('image'), blank=True) + video = EmbedVideoField(_('video'), blank=True, help_text='Paste a YouTube, Vimeo, or SoundCloud link') + button_text = models.CharField(_('button text'), max_length=255, blank=True) + button_link = models.CharField(_('button link'), max_length=255, blank=True) + + def number_with_respect_to(self): + return self.page.sections.all() + + def __str__(self): + return '{}. {}'.format(self.position, self.title) + + class Meta: + verbose_name = _('section') + verbose_name_plural = _('sections') + ordering = ['position'] + +class Config(models.Model): + TYPES = [ + (10, _('Footer')), + ] + + parameter = models.PositiveIntegerField(choices=TYPES, unique=True) + content = RichTextField('Inhoud', blank=True) + + def __str__(self): + return "{}. {}".format(self.parameter, self.get_parameter_display()) + + class Meta: + verbose_name = _('configuration parameter') + verbose_name_plural = _('configuration parameters') + ordering = ['parameter'] diff --git a/cms/static/cms/cms.scss b/cms/static/cms/cms.scss new file mode 100644 index 0000000..1f27206 --- /dev/null +++ b/cms/static/cms/cms.scss @@ -0,0 +1,277 @@ +$font: sans-serif; +$small: 500px; + +html, body { + font-family: $font; + margin: 0; + padding: 0; +} + +div.wrapper { + max-width: 700px; + margin: auto; +} + +header { + padding: 1rem; +} + +nav { + @media(min-width: $small) { + button#hamburger { + display: none; + } + ul#menu { + list-style: none; + margin: 0; + padding: 0; + text-align: center; + + li { + margin: 1em; + padding: 0; + display: inline-block; + + a { + transition: .1s ease; + display: inline-block; + text-decoration: none; + color: inherit; + font-weight: bold; + font-size: 1.25em; + + &:hover, &.current { + transform: scale(1.2); + transform-origin: bottom; + } + } + } + } + } + + @media(max-width: $small) { + button#hamburger { + position: absolute; + z-index: 1; + top: 0; + right: 0; + + .hamburger-inner, .hamburger-inner:before, .hamburger-inner:after { + background: black !important; + } + &.is-active { + position: fixed; + } + &:hover { + opacity: 1 !important; + } + &:focus { + outline: none !important; + } + } + + ul#menu { + position: fixed; + z-index: 1; + margin: 0; + padding: 0; + padding-top: 2em; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: white; + list-style: none; + + li { + padding: 1em; + margin: 0 1em; + border-bottom: 1px solid #ddd; + line-height: 1.5; + text-align: center; + + a { + color: black; + text-decoration: none; + font-size: 34px; + } + } + + transition: .5s ease; + transform: translatex(100%); + &.visible { + transform: translatex(0); + } + } + } +} + +article { + section { + padding: 1rem; + } +} + + +div.edit { + position: fixed; + left: 1em; + top: 1em; + font-size: 0.8em; + color: red; + + a, button { + color: inherit; + border: none; + display: inline; + background: none; + cursor: pointer; + margin: 0; + padding: 0; + + &:before { + content: '[ '; + } + &:after { + content: ' ]'; + } + } +} + +a.edit { + color: red !important; +} + +div.video { + padding: 0; + margin: -10px 0; + + div.iframe { + width: 100%; + padding-bottom: 56%; + position: relative; + + iframe { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + } + } +} + +/* Form elements */ + +form { + fieldset { + padding: 2em; + margin-bottom: 2em; + border: 0.5px solid black; + border-radius: 3px; + + + legend { + font-size: 1.15em; + } + } + + div.formfield { + margin: 5px 0; + padding: 10px 0; + font-size: 0; + } + div.formfield > * { + font-size: 1rem; + } + div.formfield.error { + border: 1px solid red; + border-radius: 10px; + div.errors ul li:before { + content: "Oeps! "; + } + } + div.formfield.required { + div.label { + font-weight: 700; + } + input, select, textarea { + border: 1px solid black; + } + } + + div.label { + font-size: 0.8rem; + font-weight: 400; + } + + div.input { + overflow: hidden; + margin: 5px 0; + } + + div.helptext, span.required { + color: #666; + font-size: 12px !important; + font-weight: 400 !important; + } + + span.required { + font-style: italic; + } + + input, select, textarea { + background: white; + color: black; + border: 1px solid #aaa; + font-size: 1rem; + diplay: inline-block; + width: 100%; + box-sizing: border-box; + margin: 0; + padding: 5px; + } + + div.django-ckeditor-widget { + display: block !important; + } + div.cke_chrome { + box-sizing: border-box !important; + border: 1px solid #aaa !important; + } + + input[type=checkbox] { + width: auto; + } + + select { + background: white; + } + + div.filefield { + border: 1px solid #aaa; + background: white; + padding: 4px; + + input { border: none } + } + + ul.errorlist { + margin: 0; + padding: 0; + list-style: none; + color: red; + font-size: 12px !important; + + li { + margin: 0; + padding: 0; + } + } + + .errors { + color: red; + font-weight: bold; + } +} + diff --git a/cms/static/cms/cms.scss.css b/cms/static/cms/cms.scss.css new file mode 100644 index 0000000..89c29f0 --- /dev/null +++ b/cms/static/cms/cms.scss.css @@ -0,0 +1,206 @@ +html, body { + font-family: sans-serif; + margin: 0; + padding: 0; } + +div.wrapper { + max-width: 700px; + margin: auto; } + +header { + padding: 1rem; } + +@media (min-width: 500px) { + nav button#hamburger { + display: none; } + nav ul#menu { + list-style: none; + margin: 0; + padding: 0; + text-align: center; } + nav ul#menu li { + margin: 1em; + padding: 0; + display: inline-block; } + nav ul#menu li a { + transition: .1s ease; + display: inline-block; + text-decoration: none; + color: inherit; + font-weight: bold; + font-size: 1.25em; } + nav ul#menu li a:hover, nav ul#menu li a.current { + transform: scale(1.2); + transform-origin: bottom; } } + +@media (max-width: 500px) { + nav button#hamburger { + position: absolute; + z-index: 1; + top: 0; + right: 0; } + nav button#hamburger .hamburger-inner, nav button#hamburger .hamburger-inner:before, nav button#hamburger .hamburger-inner:after { + background: black !important; } + nav button#hamburger.is-active { + position: fixed; } + nav button#hamburger:hover { + opacity: 1 !important; } + nav button#hamburger:focus { + outline: none !important; } + nav ul#menu { + position: fixed; + z-index: 1; + margin: 0; + padding: 0; + padding-top: 2em; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: white; + list-style: none; + transition: .5s ease; + transform: translatex(100%); } + nav ul#menu li { + padding: 1em; + margin: 0 1em; + border-bottom: 1px solid #ddd; + line-height: 1.5; + text-align: center; } + nav ul#menu li a { + color: black; + text-decoration: none; + font-size: 34px; } + nav ul#menu.visible { + transform: translatex(0); } } + +article section { + padding: 1rem; } + +div.edit { + position: fixed; + left: 1em; + top: 1em; + font-size: 0.8em; + color: red; } + div.edit a, div.edit button { + color: inherit; + border: none; + display: inline; + background: none; + cursor: pointer; + margin: 0; + padding: 0; } + div.edit a:before, div.edit button:before { + content: '[ '; } + div.edit a:after, div.edit button:after { + content: ' ]'; } + +a.edit { + color: red !important; } + +div.video { + padding: 0; + margin: -10px 0; } + div.video div.iframe { + width: 100%; + padding-bottom: 56%; + position: relative; } + div.video div.iframe iframe { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; } + +/* Form elements */ +form fieldset { + padding: 2em; + margin-bottom: 2em; + border: 0.5px solid black; + border-radius: 3px; } + form fieldset legend { + font-size: 1.15em; } + +form div.formfield { + margin: 5px 0; + padding: 10px 0; + font-size: 0; } + +form div.formfield > * { + font-size: 1rem; } + +form div.formfield.error { + border: 1px solid red; + border-radius: 10px; } + form div.formfield.error div.errors ul li:before { + content: "Oeps! "; } + +form div.formfield.required div.label { + font-weight: 700; } + +form div.formfield.required input, form div.formfield.required select, form div.formfield.required textarea { + border: 1px solid black; } + +form div.label { + font-size: 0.8rem; + font-weight: 400; } + +form div.input { + overflow: hidden; + margin: 5px 0; } + +form div.helptext, form span.required { + color: #666; + font-size: 12px !important; + font-weight: 400 !important; } + +form span.required { + font-style: italic; } + +form input, form select, form textarea { + background: white; + color: black; + border: 1px solid #aaa; + font-size: 1rem; + diplay: inline-block; + width: 100%; + box-sizing: border-box; + margin: 0; + padding: 5px; } + +form div.django-ckeditor-widget { + display: block !important; } + +form div.cke_chrome { + box-sizing: border-box !important; + border: 1px solid #aaa !important; } + +form input[type=checkbox] { + width: auto; } + +form select { + background: white; } + +form div.filefield { + border: 1px solid #aaa; + background: white; + padding: 4px; } + form div.filefield input { + border: none; } + +form ul.errorlist { + margin: 0; + padding: 0; + list-style: none; + color: red; + font-size: 12px !important; } + form ul.errorlist li { + margin: 0; + padding: 0; } + +form .errors { + color: red; + font-weight: bold; } + +/*# sourceMappingURL=cms.scss.css.map */ \ No newline at end of file diff --git a/cms/static/cms/cms.scss.css.map b/cms/static/cms/cms.scss.css.map new file mode 100644 index 0000000..31e67b2 --- /dev/null +++ b/cms/static/cms/cms.scss.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "file": "cms.css", + "sources": [ + "cms.scss" + ], + "names": [], + "mappings": "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" +} \ No newline at end of file diff --git a/cms/static/cms/hamburgers.css b/cms/static/cms/hamburgers.css new file mode 100644 index 0000000..ef19159 --- /dev/null +++ b/cms/static/cms/hamburgers.css @@ -0,0 +1,700 @@ +/*! + * Hamburgers + * @description Tasty CSS-animated hamburgers + * @author Jonathan Suh @jonsuh + * @site https://jonsuh.com/hamburgers + * @link https://github.com/jonsuh/hamburgers + */ +.hamburger { + padding: 15px 15px; + display: inline-block; + cursor: pointer; + transition-property: opacity, filter; + transition-duration: 0.15s; + transition-timing-function: linear; + font: inherit; + color: inherit; + text-transform: none; + background-color: transparent; + border: 0; + margin: 0; + overflow: visible; } + .hamburger:hover { + opacity: 0.7; } + +.hamburger-box { + width: 40px; + height: 24px; + display: inline-block; + position: relative; } + +.hamburger-inner { + display: block; + top: 50%; + margin-top: -2px; } + .hamburger-inner, .hamburger-inner::before, .hamburger-inner::after { + width: 40px; + height: 4px; + background-color: #000; + border-radius: 4px; + position: absolute; + transition-property: transform; + transition-duration: 0.15s; + transition-timing-function: ease; } + .hamburger-inner::before, .hamburger-inner::after { + content: ""; + display: block; } + .hamburger-inner::before { + top: -10px; } + .hamburger-inner::after { + bottom: -10px; } + +/* + * 3DX + */ +.hamburger--3dx .hamburger-box { + perspective: 80px; } + +.hamburger--3dx .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dx .hamburger-inner::before, .hamburger--3dx .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dx.is-active .hamburger-inner { + background-color: transparent; + transform: rotateY(180deg); } + .hamburger--3dx.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dx.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * 3DX Reverse + */ +.hamburger--3dx-r .hamburger-box { + perspective: 80px; } + +.hamburger--3dx-r .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dx-r .hamburger-inner::before, .hamburger--3dx-r .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dx-r.is-active .hamburger-inner { + background-color: transparent; + transform: rotateY(-180deg); } + .hamburger--3dx-r.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dx-r.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * 3DY + */ +.hamburger--3dy .hamburger-box { + perspective: 80px; } + +.hamburger--3dy .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dy .hamburger-inner::before, .hamburger--3dy .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dy.is-active .hamburger-inner { + background-color: transparent; + transform: rotateX(-180deg); } + .hamburger--3dy.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dy.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * 3DY Reverse + */ +.hamburger--3dy-r .hamburger-box { + perspective: 80px; } + +.hamburger--3dy-r .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dy-r .hamburger-inner::before, .hamburger--3dy-r .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dy-r.is-active .hamburger-inner { + background-color: transparent; + transform: rotateX(180deg); } + .hamburger--3dy-r.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dy-r.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * 3DXY + */ +.hamburger--3dxy .hamburger-box { + perspective: 80px; } + +.hamburger--3dxy .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dxy .hamburger-inner::before, .hamburger--3dxy .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dxy.is-active .hamburger-inner { + background-color: transparent; + transform: rotateX(180deg) rotateY(180deg); } + .hamburger--3dxy.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dxy.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * 3DXY Reverse + */ +.hamburger--3dxy-r .hamburger-box { + perspective: 80px; } + +.hamburger--3dxy-r .hamburger-inner { + transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1), background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + .hamburger--3dxy-r .hamburger-inner::before, .hamburger--3dxy-r .hamburger-inner::after { + transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); } + +.hamburger--3dxy-r.is-active .hamburger-inner { + background-color: transparent; + transform: rotateX(180deg) rotateY(180deg) rotateZ(-180deg); } + .hamburger--3dxy-r.is-active .hamburger-inner::before { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--3dxy-r.is-active .hamburger-inner::after { + transform: translate3d(0, -10px, 0) rotate(-45deg); } + +/* + * Arrow + */ +.hamburger--arrow.is-active .hamburger-inner::before { + transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1); } + +.hamburger--arrow.is-active .hamburger-inner::after { + transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1); } + +/* + * Arrow Right + */ +.hamburger--arrow-r.is-active .hamburger-inner::before { + transform: translate3d(8px, 0, 0) rotate(45deg) scale(0.7, 1); } + +.hamburger--arrow-r.is-active .hamburger-inner::after { + transform: translate3d(8px, 0, 0) rotate(-45deg) scale(0.7, 1); } + +/* + * Arrow Alt + */ +.hamburger--arrowalt .hamburger-inner::before { + transition: top 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1); } + +.hamburger--arrowalt .hamburger-inner::after { + transition: bottom 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1); } + +.hamburger--arrowalt.is-active .hamburger-inner::before { + top: 0; + transform: translate3d(-8px, -10px, 0) rotate(-45deg) scale(0.7, 1); + transition: top 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22); } + +.hamburger--arrowalt.is-active .hamburger-inner::after { + bottom: 0; + transform: translate3d(-8px, 10px, 0) rotate(45deg) scale(0.7, 1); + transition: bottom 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22); } + +/* + * Arrow Alt Right + */ +.hamburger--arrowalt-r .hamburger-inner::before { + transition: top 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1); } + +.hamburger--arrowalt-r .hamburger-inner::after { + transition: bottom 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1); } + +.hamburger--arrowalt-r.is-active .hamburger-inner::before { + top: 0; + transform: translate3d(8px, -10px, 0) rotate(45deg) scale(0.7, 1); + transition: top 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22); } + +.hamburger--arrowalt-r.is-active .hamburger-inner::after { + bottom: 0; + transform: translate3d(8px, 10px, 0) rotate(-45deg) scale(0.7, 1); + transition: bottom 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22); } + +/* + * Arrow Turn + */ +.hamburger--arrowturn.is-active .hamburger-inner { + transform: rotate(-180deg); } + .hamburger--arrowturn.is-active .hamburger-inner::before { + transform: translate3d(8px, 0, 0) rotate(45deg) scale(0.7, 1); } + .hamburger--arrowturn.is-active .hamburger-inner::after { + transform: translate3d(8px, 0, 0) rotate(-45deg) scale(0.7, 1); } + +/* + * Arrow Turn Right + */ +.hamburger--arrowturn-r.is-active .hamburger-inner { + transform: rotate(-180deg); } + .hamburger--arrowturn-r.is-active .hamburger-inner::before { + transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1); } + .hamburger--arrowturn-r.is-active .hamburger-inner::after { + transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1); } + +/* + * Boring + */ +.hamburger--boring .hamburger-inner, .hamburger--boring .hamburger-inner::before, .hamburger--boring .hamburger-inner::after { + transition-property: none; } + +.hamburger--boring.is-active .hamburger-inner { + transform: rotate(45deg); } + .hamburger--boring.is-active .hamburger-inner::before { + top: 0; + opacity: 0; } + .hamburger--boring.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(-90deg); } + +/* + * Collapse + */ +.hamburger--collapse .hamburger-inner { + top: auto; + bottom: 0; + transition-duration: 0.13s; + transition-delay: 0.13s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--collapse .hamburger-inner::after { + top: -20px; + transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0.1s linear; } + .hamburger--collapse .hamburger-inner::before { + transition: top 0.12s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--collapse.is-active .hamburger-inner { + transform: translate3d(0, -10px, 0) rotate(-45deg); + transition-delay: 0.22s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--collapse.is-active .hamburger-inner::after { + top: 0; + opacity: 0; + transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0.1s 0.22s linear; } + .hamburger--collapse.is-active .hamburger-inner::before { + top: 0; + transform: rotate(-90deg); + transition: top 0.1s 0.16s cubic-bezier(0.33333, 0, 0.66667, 0.33333), transform 0.13s 0.25s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Collapse Reverse + */ +.hamburger--collapse-r .hamburger-inner { + top: auto; + bottom: 0; + transition-duration: 0.13s; + transition-delay: 0.13s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--collapse-r .hamburger-inner::after { + top: -20px; + transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0.1s linear; } + .hamburger--collapse-r .hamburger-inner::before { + transition: top 0.12s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--collapse-r.is-active .hamburger-inner { + transform: translate3d(0, -10px, 0) rotate(45deg); + transition-delay: 0.22s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--collapse-r.is-active .hamburger-inner::after { + top: 0; + opacity: 0; + transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0.1s 0.22s linear; } + .hamburger--collapse-r.is-active .hamburger-inner::before { + top: 0; + transform: rotate(90deg); + transition: top 0.1s 0.16s cubic-bezier(0.33333, 0, 0.66667, 0.33333), transform 0.13s 0.25s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Elastic + */ +.hamburger--elastic .hamburger-inner { + top: 2px; + transition-duration: 0.275s; + transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } + .hamburger--elastic .hamburger-inner::before { + top: 10px; + transition: opacity 0.125s 0.275s ease; } + .hamburger--elastic .hamburger-inner::after { + top: 20px; + transition: transform 0.275s cubic-bezier(0.68, -0.55, 0.265, 1.55); } + +.hamburger--elastic.is-active .hamburger-inner { + transform: translate3d(0, 10px, 0) rotate(135deg); + transition-delay: 0.075s; } + .hamburger--elastic.is-active .hamburger-inner::before { + transition-delay: 0s; + opacity: 0; } + .hamburger--elastic.is-active .hamburger-inner::after { + transform: translate3d(0, -20px, 0) rotate(-270deg); + transition-delay: 0.075s; } + +/* + * Elastic Reverse + */ +.hamburger--elastic-r .hamburger-inner { + top: 2px; + transition-duration: 0.275s; + transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } + .hamburger--elastic-r .hamburger-inner::before { + top: 10px; + transition: opacity 0.125s 0.275s ease; } + .hamburger--elastic-r .hamburger-inner::after { + top: 20px; + transition: transform 0.275s cubic-bezier(0.68, -0.55, 0.265, 1.55); } + +.hamburger--elastic-r.is-active .hamburger-inner { + transform: translate3d(0, 10px, 0) rotate(-135deg); + transition-delay: 0.075s; } + .hamburger--elastic-r.is-active .hamburger-inner::before { + transition-delay: 0s; + opacity: 0; } + .hamburger--elastic-r.is-active .hamburger-inner::after { + transform: translate3d(0, -20px, 0) rotate(270deg); + transition-delay: 0.075s; } + +/* + * Emphatic + */ +.hamburger--emphatic { + overflow: hidden; } + .hamburger--emphatic .hamburger-inner { + transition: background-color 0.125s 0.175s ease-in; } + .hamburger--emphatic .hamburger-inner::before { + left: 0; + transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear, left 0.125s 0.175s ease-in; } + .hamburger--emphatic .hamburger-inner::after { + top: 10px; + right: 0; + transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear, right 0.125s 0.175s ease-in; } + .hamburger--emphatic.is-active .hamburger-inner { + transition-delay: 0s; + transition-timing-function: ease-out; + background-color: transparent; } + .hamburger--emphatic.is-active .hamburger-inner::before { + left: -80px; + top: -80px; + transform: translate3d(80px, 80px, 0) rotate(45deg); + transition: left 0.125s ease-out, top 0.05s 0.125s linear, transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1); } + .hamburger--emphatic.is-active .hamburger-inner::after { + right: -80px; + top: -80px; + transform: translate3d(-80px, 80px, 0) rotate(-45deg); + transition: right 0.125s ease-out, top 0.05s 0.125s linear, transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1); } + +/* + * Emphatic Reverse + */ +.hamburger--emphatic-r { + overflow: hidden; } + .hamburger--emphatic-r .hamburger-inner { + transition: background-color 0.125s 0.175s ease-in; } + .hamburger--emphatic-r .hamburger-inner::before { + left: 0; + transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear, left 0.125s 0.175s ease-in; } + .hamburger--emphatic-r .hamburger-inner::after { + top: 10px; + right: 0; + transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear, right 0.125s 0.175s ease-in; } + .hamburger--emphatic-r.is-active .hamburger-inner { + transition-delay: 0s; + transition-timing-function: ease-out; + background-color: transparent; } + .hamburger--emphatic-r.is-active .hamburger-inner::before { + left: -80px; + top: 80px; + transform: translate3d(80px, -80px, 0) rotate(-45deg); + transition: left 0.125s ease-out, top 0.05s 0.125s linear, transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1); } + .hamburger--emphatic-r.is-active .hamburger-inner::after { + right: -80px; + top: 80px; + transform: translate3d(-80px, -80px, 0) rotate(45deg); + transition: right 0.125s ease-out, top 0.05s 0.125s linear, transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1); } + +/* + * Minus + */ +.hamburger--minus .hamburger-inner::before, .hamburger--minus .hamburger-inner::after { + transition: bottom 0.08s 0s ease-out, top 0.08s 0s ease-out, opacity 0s linear; } + +.hamburger--minus.is-active .hamburger-inner::before, .hamburger--minus.is-active .hamburger-inner::after { + opacity: 0; + transition: bottom 0.08s ease-out, top 0.08s ease-out, opacity 0s 0.08s linear; } + +.hamburger--minus.is-active .hamburger-inner::before { + top: 0; } + +.hamburger--minus.is-active .hamburger-inner::after { + bottom: 0; } + +/* + * Slider + */ +.hamburger--slider .hamburger-inner { + top: 2px; } + .hamburger--slider .hamburger-inner::before { + top: 10px; + transition-property: transform, opacity; + transition-timing-function: ease; + transition-duration: 0.15s; } + .hamburger--slider .hamburger-inner::after { + top: 20px; } + +.hamburger--slider.is-active .hamburger-inner { + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--slider.is-active .hamburger-inner::before { + transform: rotate(-45deg) translate3d(-5.71429px, -6px, 0); + opacity: 0; } + .hamburger--slider.is-active .hamburger-inner::after { + transform: translate3d(0, -20px, 0) rotate(-90deg); } + +/* + * Slider Reverse + */ +.hamburger--slider-r .hamburger-inner { + top: 2px; } + .hamburger--slider-r .hamburger-inner::before { + top: 10px; + transition-property: transform, opacity; + transition-timing-function: ease; + transition-duration: 0.15s; } + .hamburger--slider-r .hamburger-inner::after { + top: 20px; } + +.hamburger--slider-r.is-active .hamburger-inner { + transform: translate3d(0, 10px, 0) rotate(-45deg); } + .hamburger--slider-r.is-active .hamburger-inner::before { + transform: rotate(45deg) translate3d(5.71429px, -6px, 0); + opacity: 0; } + .hamburger--slider-r.is-active .hamburger-inner::after { + transform: translate3d(0, -20px, 0) rotate(90deg); } + +/* + * Spin + */ +.hamburger--spin .hamburger-inner { + transition-duration: 0.22s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--spin .hamburger-inner::before { + transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in; } + .hamburger--spin .hamburger-inner::after { + transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--spin.is-active .hamburger-inner { + transform: rotate(225deg); + transition-delay: 0.12s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--spin.is-active .hamburger-inner::before { + top: 0; + opacity: 0; + transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; } + .hamburger--spin.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(-90deg); + transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Spin Reverse + */ +.hamburger--spin-r .hamburger-inner { + transition-duration: 0.22s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--spin-r .hamburger-inner::before { + transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in; } + .hamburger--spin-r .hamburger-inner::after { + transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--spin-r.is-active .hamburger-inner { + transform: rotate(-225deg); + transition-delay: 0.12s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--spin-r.is-active .hamburger-inner::before { + top: 0; + opacity: 0; + transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; } + .hamburger--spin-r.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(90deg); + transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Spring + */ +.hamburger--spring .hamburger-inner { + top: 2px; + transition: background-color 0s 0.13s linear; } + .hamburger--spring .hamburger-inner::before { + top: 10px; + transition: top 0.1s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--spring .hamburger-inner::after { + top: 20px; + transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--spring.is-active .hamburger-inner { + transition-delay: 0.22s; + background-color: transparent; } + .hamburger--spring.is-active .hamburger-inner::before { + top: 0; + transition: top 0.1s 0.15s cubic-bezier(0.33333, 0, 0.66667, 0.33333), transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1); + transform: translate3d(0, 10px, 0) rotate(45deg); } + .hamburger--spring.is-active .hamburger-inner::after { + top: 0; + transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1); + transform: translate3d(0, 10px, 0) rotate(-45deg); } + +/* + * Spring Reverse + */ +.hamburger--spring-r .hamburger-inner { + top: auto; + bottom: 0; + transition-duration: 0.13s; + transition-delay: 0s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--spring-r .hamburger-inner::after { + top: -20px; + transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0s linear; } + .hamburger--spring-r .hamburger-inner::before { + transition: top 0.1s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--spring-r.is-active .hamburger-inner { + transform: translate3d(0, -10px, 0) rotate(-45deg); + transition-delay: 0.22s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--spring-r.is-active .hamburger-inner::after { + top: 0; + opacity: 0; + transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0s 0.22s linear; } + .hamburger--spring-r.is-active .hamburger-inner::before { + top: 0; + transform: rotate(90deg); + transition: top 0.1s 0.15s cubic-bezier(0.33333, 0, 0.66667, 0.33333), transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Stand + */ +.hamburger--stand .hamburger-inner { + transition: transform 0.075s 0.15s cubic-bezier(0.55, 0.055, 0.675, 0.19), background-color 0s 0.075s linear; } + .hamburger--stand .hamburger-inner::before { + transition: top 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--stand .hamburger-inner::after { + transition: bottom 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--stand.is-active .hamburger-inner { + transform: rotate(90deg); + background-color: transparent; + transition: transform 0.075s 0s cubic-bezier(0.215, 0.61, 0.355, 1), background-color 0s 0.15s linear; } + .hamburger--stand.is-active .hamburger-inner::before { + top: 0; + transform: rotate(-45deg); + transition: top 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--stand.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(45deg); + transition: bottom 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Stand Reverse + */ +.hamburger--stand-r .hamburger-inner { + transition: transform 0.075s 0.15s cubic-bezier(0.55, 0.055, 0.675, 0.19), background-color 0s 0.075s linear; } + .hamburger--stand-r .hamburger-inner::before { + transition: top 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--stand-r .hamburger-inner::after { + transition: bottom 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--stand-r.is-active .hamburger-inner { + transform: rotate(-90deg); + background-color: transparent; + transition: transform 0.075s 0s cubic-bezier(0.215, 0.61, 0.355, 1), background-color 0s 0.15s linear; } + .hamburger--stand-r.is-active .hamburger-inner::before { + top: 0; + transform: rotate(-45deg); + transition: top 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--stand-r.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(45deg); + transition: bottom 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Squeeze + */ +.hamburger--squeeze .hamburger-inner { + transition-duration: 0.075s; + transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } + .hamburger--squeeze .hamburger-inner::before { + transition: top 0.075s 0.12s ease, opacity 0.075s ease; } + .hamburger--squeeze .hamburger-inner::after { + transition: bottom 0.075s 0.12s ease, transform 0.075s cubic-bezier(0.55, 0.055, 0.675, 0.19); } + +.hamburger--squeeze.is-active .hamburger-inner { + transform: rotate(45deg); + transition-delay: 0.12s; + transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } + .hamburger--squeeze.is-active .hamburger-inner::before { + top: 0; + opacity: 0; + transition: top 0.075s ease, opacity 0.075s 0.12s ease; } + .hamburger--squeeze.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(-90deg); + transition: bottom 0.075s ease, transform 0.075s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1); } + +/* + * Vortex + */ +.hamburger--vortex .hamburger-inner { + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); } + .hamburger--vortex .hamburger-inner::before, .hamburger--vortex .hamburger-inner::after { + transition-duration: 0s; + transition-delay: 0.1s; + transition-timing-function: linear; } + .hamburger--vortex .hamburger-inner::before { + transition-property: top, opacity; } + .hamburger--vortex .hamburger-inner::after { + transition-property: bottom, transform; } + +.hamburger--vortex.is-active .hamburger-inner { + transform: rotate(765deg); + transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); } + .hamburger--vortex.is-active .hamburger-inner::before, .hamburger--vortex.is-active .hamburger-inner::after { + transition-delay: 0s; } + .hamburger--vortex.is-active .hamburger-inner::before { + top: 0; + opacity: 0; } + .hamburger--vortex.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(90deg); } + +/* + * Vortex Reverse + */ +.hamburger--vortex-r .hamburger-inner { + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); } + .hamburger--vortex-r .hamburger-inner::before, .hamburger--vortex-r .hamburger-inner::after { + transition-duration: 0s; + transition-delay: 0.1s; + transition-timing-function: linear; } + .hamburger--vortex-r .hamburger-inner::before { + transition-property: top, opacity; } + .hamburger--vortex-r .hamburger-inner::after { + transition-property: bottom, transform; } + +.hamburger--vortex-r.is-active .hamburger-inner { + transform: rotate(-765deg); + transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); } + .hamburger--vortex-r.is-active .hamburger-inner::before, .hamburger--vortex-r.is-active .hamburger-inner::after { + transition-delay: 0s; } + .hamburger--vortex-r.is-active .hamburger-inner::before { + top: 0; + opacity: 0; } + .hamburger--vortex-r.is-active .hamburger-inner::after { + bottom: 0; + transform: rotate(-90deg); } diff --git a/cms/templates/base.html b/cms/templates/base.html new file mode 100644 index 0000000..a63cdac --- /dev/null +++ b/cms/templates/base.html @@ -0,0 +1 @@ +{% extends 'cms/base.html' %} diff --git a/cms/templates/cms/base.html b/cms/templates/cms/base.html new file mode 100644 index 0000000..717a1b2 --- /dev/null +++ b/cms/templates/cms/base.html @@ -0,0 +1,90 @@ +{% load static %} +{% load i18n %} + + + + + {% block title %}{% endblock %} + + + + + + {% block extrahead %}{% endblock %} + + + +
+ {% block main %} + +
+
+ {% block header %} + {% endblock %} +
+
+ + + +
+ {% block content %} + {% endblock %} +
+ +
+
+ {% block footer %} + {% endblock %} +
+
+ + {% endblock %} +
+ + + {% block extrabody %}{% endblock %} + + diff --git a/cms/templates/cms/edit.html b/cms/templates/cms/edit.html new file mode 100644 index 0000000..2292b20 --- /dev/null +++ b/cms/templates/cms/edit.html @@ -0,0 +1,35 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block content %} +
+ {% csrf_token %} + {{form.media}} + +
+ {% for field in form %} + {% include 'cms/formfield.html' with field=field %} + {% endfor %} +
+ + {{formset.management_form}} + {% for form in formset %} + {{form.media}} + {% for field in form.hidden_fields %} + {{field}} + {% endfor %} +
+
+

{% trans 'Section' %}: {{form.instance.title}}

+ {% for field in form.visible_fields %} + {% include 'cms/formfield.html' with field=field %} + {% endfor %} +
+
+ {% endfor %} + +
+ +
+
+{% endblock %} diff --git a/cms/templates/cms/formfield.html b/cms/templates/cms/formfield.html new file mode 100644 index 0000000..28e7275 --- /dev/null +++ b/cms/templates/cms/formfield.html @@ -0,0 +1,14 @@ +
+
+ {{field.errors}} +
+
+ {{field.label_tag}} +
+
+ {{field}} +
+
+ {{field.help_text}} +
+
diff --git a/cms/templates/cms/page.html b/cms/templates/cms/page.html new file mode 100644 index 0000000..40e19ad --- /dev/null +++ b/cms/templates/cms/page.html @@ -0,0 +1,26 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{{block.super}} - {{object.title}}{% endblock %} + +{% block content %} +
+ {% if user.is_staff %} + {% if object.slug %} + {% trans 'edit this page' %} + {% else %} + {% trans 'edit this page' %} + {% endif %} + {% else %} + {% trans 'login' %} + {% endif %} +
+ + {% for section in object.sections.all %} +
+
+ {% include 'cms/sections/'|add:section.type|add:'.html' %} +
+
+ {% endfor %} +{% endblock %} diff --git a/cms/templates/cms/sections/base.html b/cms/templates/cms/sections/base.html new file mode 100644 index 0000000..5c2cf15 --- /dev/null +++ b/cms/templates/cms/sections/base.html @@ -0,0 +1,27 @@ +{% load thumbnail embed_video_tags %} + +{% if section.image %} +
+ +
+{% endif %} + +
+

+ {{section.title}} +

+
+ +{% if section.content %} +
+ {{section.content|safe}} +
+{% endif %} + +{% if section.video %} +
+
+ {% video section.video '800x600' %} +
+
+{% endif %} diff --git a/cms/templates/cms/sections/normal.html b/cms/templates/cms/sections/normal.html new file mode 100644 index 0000000..0aa4fc6 --- /dev/null +++ b/cms/templates/cms/sections/normal.html @@ -0,0 +1 @@ +{% extends 'cms/sections/base.html' %} diff --git a/cms/templates/cms/sections/pages.html b/cms/templates/cms/sections/pages.html new file mode 100644 index 0000000..a3c078d --- /dev/null +++ b/cms/templates/cms/sections/pages.html @@ -0,0 +1,22 @@ +{% load thumbnail %} + +
    + {% for p in pages %} + {% if p.slug %} +
  • + +
    +
    + +
    +

    {{p.title}}

    + {{p.content|safe}} + {% if user.is_staff %} + [ bewerken ] + {% endif %} + Lees meer » +
    +
  • + {% endif %} + {% endfor %} +
diff --git a/cms/templates/cms/sections/photo.html b/cms/templates/cms/sections/photo.html new file mode 100644 index 0000000..0aa4fc6 --- /dev/null +++ b/cms/templates/cms/sections/photo.html @@ -0,0 +1 @@ +{% extends 'cms/sections/base.html' %} diff --git a/cms/templates/cms/sections/video.html b/cms/templates/cms/sections/video.html new file mode 100644 index 0000000..0aa4fc6 --- /dev/null +++ b/cms/templates/cms/sections/video.html @@ -0,0 +1 @@ +{% extends 'cms/sections/base.html' %} diff --git a/cms/templates/registration/login.html b/cms/templates/registration/login.html new file mode 100644 index 0000000..bc4ec27 --- /dev/null +++ b/cms/templates/registration/login.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +
+ {% csrf_token %} +
+ {% trans 'Log in' %} + {{form.non_field_errors}} + {% for field in form %} + {% include 'cms/formfield.html' with field=field %} + {% endfor %} +
+ +
+{% endblock %} diff --git a/cms/tests.py b/cms/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/cms/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cms/urls.py b/cms/urls.py new file mode 100644 index 0000000..6ef4f11 --- /dev/null +++ b/cms/urls.py @@ -0,0 +1,13 @@ +from django.urls import path +from .views import PageView, UpdatePage, CreatePage, CreateSection + +app_name = 'cms' + +urlpatterns = [ + path('', PageView.as_view(), {'slug': ''}, name='homepage'), + path('/', PageView.as_view(), name='page'), + path('cms/homepage/', UpdatePage.as_view(), {'slug': ''}, name='updatehomepage'), + path('cms/page//', UpdatePage.as_view(), name='updatepage'), + path('cms/newpage/', CreatePage.as_view(), name='createpage'), + #path('cms/page//createsection/', CreateSection.as_view(), name='createsection'), +] diff --git a/cms/utils.py b/cms/utils.py new file mode 100644 index 0000000..2aa6325 --- /dev/null +++ b/cms/utils.py @@ -0,0 +1,10 @@ +from .models import Config + +def get_config(parameter): + '''Gets or creates the requested parameter. + + ''' + if parameter not in [t[0] for t in Config.TYPES]: + raise ValueError('Invalid configuration parameter requested') + (c, created) = Config.objects.get_or_create(parameter=parameter) + return c.content diff --git a/cms/views.py b/cms/views.py new file mode 100644 index 0000000..4d28a89 --- /dev/null +++ b/cms/views.py @@ -0,0 +1,66 @@ +from django.views.generic import DetailView, UpdateView, CreateView +from django.views.generic.detail import SingleObjectMixin +from django.shortcuts import redirect, get_object_or_404 +from django.contrib.auth.mixins import UserPassesTestMixin +from .models import * +from .forms import * +from .utils import * + +class StaffRequiredMixin(UserPassesTestMixin): + def test_func(self): + return self.request.user.is_staff + +class MenuMixin(object): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + pages = Page.objects.filter(menu=True) + footer = get_config(10) + context.update({ + 'pages': pages, + 'footer': footer, + }) + return context + +class PageView(MenuMixin, DetailView): + model = Page + template_name = 'cms/page.html' + +class EditPageMixin: + model = Page + form_class = PageForm + template_name = 'cms/edit.html' + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.get_form() + formset = SectionFormSet(request.POST, instance=self.object) + if form.is_valid() and formset.is_valid(): + return self.form_valid(form, formset) + else: + return self.form_invalid(form, formset) + + def form_valid(self, form, formset): + form.save() + formset.save() + return redirect(form.instance.get_absolute_url()) + + def form_invalid(self, form, formset): + return self.render_to_response(self.get_context_data(form=form, formset=formset)) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + if 'formset' not in context: + formset = SectionFormSet(instance=self.object) + context.update({ + 'formset': formset, + }) + return context + +class UpdatePage(StaffRequiredMixin, MenuMixin, EditPageMixin, UpdateView): + pass +class CreatePage(StaffRequiredMixin, MenuMixin, EditPageMixin, CreateView): + def get_object(self): + pass + +class CreateSection: + pass diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..450d884 --- /dev/null +++ b/setup.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +from setuptools import setup + +setup( + name = 'django-simplecms', + version = '0.0.1', + url = 'https://github.com/rtts/django-simplecms', + author = 'Jaap Joris Vens', + author_email = 'jj@rtts.eu', + license = 'GPL3', + packages = ['cms'], + install_requires = [ + 'django', + 'django-ckeditor', + 'django-embed-video', + 'easy-thumbnails', + 'git+https://github.com/JaapJoris/django-simplecms.git', + ], +)