commit 03fe7d1af7f743f6a6973d08f1d1d643025519ce Author: Ada Werefox Date: Sun Nov 19 21:53:05 2023 -0600 Initial commit. Templated from void-werefox-cafe. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..520684a --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Generated by Cargo +# will have compiled files and executables +**/target/** + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# Added by Dioxus +**/dist/** + +# Don't sync the NodeJS files. +**/node_modules/** +**/package-lock.json +**/package.json \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..51dc85f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "void-werefox-cafe" +version = "0.1.0" +authors = ["Ada Werefox "] +edition = "2021" + +[workspace] +members = [ + "void-fe", + "void-be", +] + +[workspace.dependencies] +rocket = "=0.5.0-rc.3" +dioxus = "0.3.2" +markdown = "1.0.0-alpha.7" +dioxus-ssr = "0.3.0" +rust-embed = { version = "6.6.1" } +once_cell = "1.17.1" + +[dependencies] +void-be = { path = "./void-be" } +rocket = { workspace = true } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..16609e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM rust:alpine + +WORKDIR /usr/src/app + +RUN apk add git musl-dev + +COPY public/ public/ +COPY void-be/ void-be/ + +# We don't need all the front end directory files +RUN mkdir void-fe +COPY void-fe/src/ void-fe/src/ +COPY void-fe/data/ void-fe/data/ +COPY void-fe/Cargo.toml void-fe/Cargo.toml + +COPY src/ src/ +COPY templates/ templates/ +COPY Cargo.toml . +COPY Rocket.toml . + +RUN cargo install --config "net.git-fetch-with-cli=true" --path . + +ENV RUST_ADDRESS=0.0.0.0 + +CMD ["cargo", "run", "--release"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f387a57 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# [void.werefox.cafe](https://void.werefox.cafe) + +> This will be used to replace my *"A Letter To The Void"* collection of poems on [write.as](https://write.as) for hosting my poetry. + +## Usage + +> This project works by using a Cargo workspace with two projects `void-fe` and `void-be` + +### Backend + +You can develop the backend by simply running the project from the root directory + +``` +cargo run +``` + +Generally, any commands you'd use for any other standard Rust project will work for this. + + +Ex: +``` +cargo build +``` + +### Frontend + +If you want to develop the Dioxus frontend, you'll need to do the following: + +- [From the official Dioxus docs](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/web), ensure you have `dioxus-cli` and the `wasm32-unknown-unknown` target installed + +``` +cargo install dioxus-cli +``` +``` +rustup target add wasm32-unknown-unknown +``` +- Additionally, you *may* need to have the [Tauri prerequisites](https://tauri.app/v1/guides/getting-started/prerequisites/) installed. + +Then, you should be able to run the development server after moving into the `rust-letter-fe` directory. + +(Linux example) +``` +cd rust-letter-fe && dioxus serve +``` + +If you'd link to know about how to use `dioxus-cli`, you should run `dioxus --help` or [reference the official documentation.*](https://github.com/DioxusLabs/cli) + +\* At the time of writing this, the link to the documentation is broken. If you'd like to see what I normally use to run the project, here's an example: `dioxus serve --hot-reload --port [port #]` + +## Running + +> Here are some ways you can run the project + +### Cargo + +You can either do the standard `run --release` + +``` +cargo run --release +``` + +Or, referencing the Dockerfile, you can install and then run. + +``` +cargo install --path . +``` +``` +rust-letter +``` + + +## Project Structure + +``` +.dioxus-letter-werefox-cafe +|- data # text files that will be read to for data in the app +|- public # save the assets you want include in your project. +|- void-be +|\ +||- src # source code folder for backend +|- void-fe +|\ +||- src # source code folder for frontend +||\ +|||- utils # save some public function +|||- components # save some custom components +|- src # code for running the workspace +|- templates # put template files here, right now just using handlebar +``` diff --git a/Rocket.toml b/Rocket.toml new file mode 100644 index 0000000..55e9da0 --- /dev/null +++ b/Rocket.toml @@ -0,0 +1,33 @@ +[default] +port = 8345 +# workers = 16 +# max_blocking = 512 +# keep_alive = 5 +ident = "void-werefox-cafe" +# ip_header = "X-Real-IP" # set to `false` to disable +# log_level = "normal" +# temp_dir = "/tmp" +# cli_colors = true + +[debug] +port = 8234 + +[release] +address = "0.0.0.0" +secret_key = "yqXUwxWOGD6X7yZaMbRnOXsNjiDMicveyC2imK48KbM=" + +# [default.limits] +# form = "64 kB" +# json = "1 MiB" +# msgpack = "2 MiB" +# "file/jpg" = "5 MiB" + +# [default.tls] +# certs = "path/to/cert-chain.pem" +# key = "path/to/key.pem" + +# [default.shutdown] +# ctrlc = true +# signals = ["term", "hup"] +# grace = 5 +# mercy = 5 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..726e408 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +--- +version: "3" + +services: + app: + image: void-werefox-cafe:latest + build: + context: . + ports: + - "8345:8345" diff --git a/public/fonts/DejaVuSansMono.ttf b/public/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..10c879b Binary files /dev/null and b/public/fonts/DejaVuSansMono.ttf differ diff --git a/public/fonts/OpenDyslexic-Bold.otf b/public/fonts/OpenDyslexic-Bold.otf new file mode 100644 index 0000000..4c492e2 Binary files /dev/null and b/public/fonts/OpenDyslexic-Bold.otf differ diff --git a/public/fonts/OpenDyslexic-BoldItalic.otf b/public/fonts/OpenDyslexic-BoldItalic.otf new file mode 100644 index 0000000..f71b430 Binary files /dev/null and b/public/fonts/OpenDyslexic-BoldItalic.otf differ diff --git a/public/fonts/OpenDyslexic-Italic.otf b/public/fonts/OpenDyslexic-Italic.otf new file mode 100644 index 0000000..fdead4d Binary files /dev/null and b/public/fonts/OpenDyslexic-Italic.otf differ diff --git a/public/fonts/OpenDyslexic-Regular.otf b/public/fonts/OpenDyslexic-Regular.otf new file mode 100644 index 0000000..1226d2a Binary files /dev/null and b/public/fonts/OpenDyslexic-Regular.otf differ diff --git a/public/images/black_square_button.png b/public/images/black_square_button.png new file mode 100644 index 0000000..45b1d40 Binary files /dev/null and b/public/images/black_square_button.png differ diff --git a/public/images/white_square_button.png b/public/images/white_square_button.png new file mode 100644 index 0000000..a34b731 Binary files /dev/null and b/public/images/white_square_button.png differ diff --git a/public/styles/tailwind.min.css b/public/styles/tailwind.min.css new file mode 100644 index 0000000..d5f8c01 --- /dev/null +++ b/public/styles/tailwind.min.css @@ -0,0 +1 @@ +/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%;margin-right:auto;margin-left:auto;padding-right:1rem;padding-left:1rem}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px;padding-right:0;padding-left:0}}@media (min-width:1536px){.container{max-width:1536px}}.mx-auto{margin-left:auto;margin-right:auto}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.flex{display:flex}.hidden{display:none}.min-h-screen{min-height:100vh}.max-w-3xl{max-width:48rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-full{max-width:100%}.basis-full{flex-basis:100%}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.justify-center{justify-content:center}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.bg-alice-werefox-grey{--tw-bg-opacity:1;background-color:rgb(36 36 36/var(--tw-bg-opacity))}.bg-alice-werefox-grey-dark{--tw-bg-opacity:1;background-color:rgb(18 18 18/var(--tw-bg-opacity))}.bg-alice-werefox-grey-light{--tw-bg-opacity:1;background-color:rgb(204 204 204/var(--tw-bg-opacity))}.bg-alice-werefox-grey-lightest{--tw-bg-opacity:1;background-color:rgb(238 238 238/var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-4{padding:1rem}.py-4{padding-top:1rem}.pb-4,.py-4{padding-bottom:1rem}.pt-4{padding-top:1rem}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-nerd{font-family:DejaVuSansMono}.font-open{font-family:OpenDyslexic}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-alice-werefox-grey-dark{--tw-text-opacity:1;color:rgb(18 18 18/var(--tw-text-opacity))}.text-alice-werefox-grey-light{--tw-text-opacity:1;color:rgb(204 204 204/var(--tw-text-opacity))}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-2,.ring-4{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-4{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-alice-werefox-red{--tw-ring-opacity:1;--tw-ring-color:rgb(201 52 57/var(--tw-ring-opacity))}.ring-alice-werefox-red-dark{--tw-ring-opacity:1;--tw-ring-color:rgb(128 0 8/var(--tw-ring-opacity))}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@font-face{font-family:OpenDyslexic;src:url(/fonts/OpenDyslexic-Regular.otf)}@font-face{font-family:DejaVuSansMono;src:url(/fonts/DejaVuSansMono.ttf)}.before\:content-\[\'Open\'\]:before{--tw-content:"Open";content:var(--tw-content)}@keyframes yip{0%,to{transform:scale(1)}50%{transform:scale(1.01)}}.hover\:animate-yip:hover{animation:yip .1s ease-in-out}.hover\:text-alice-werefox-blue-dark:hover{--tw-text-opacity:1;color:rgb(51 0 255/var(--tw-text-opacity))}.hover\:text-alice-werefox-blue-light:hover{--tw-text-opacity:1;color:rgb(145 151 243/var(--tw-text-opacity))}.hover\:ring-alice-werefox-blue:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(27 41 224/var(--tw-ring-opacity))}.group[open] .group-open\:before\:content-\[\'Close\'\]:before{--tw-content:"Close";content:var(--tw-content)}@media (prefers-color-scheme:dark){.dark\:bg-alice-werefox-grey{--tw-bg-opacity:1;background-color:rgb(36 36 36/var(--tw-bg-opacity))}.dark\:bg-alice-werefox-grey-dark{--tw-bg-opacity:1;background-color:rgb(18 18 18/var(--tw-bg-opacity))}.dark\:text-alice-werefox-grey-light{--tw-text-opacity:1;color:rgb(204 204 204/var(--tw-text-opacity))}.dark\:ring-alice-werefox-red{--tw-ring-opacity:1;--tw-ring-color:rgb(201 52 57/var(--tw-ring-opacity))}.dark\:hover\:text-alice-werefox-blue-light:hover{--tw-text-opacity:1;color:rgb(145 151 243/var(--tw-text-opacity))}.dark\:hover\:ring-alice-werefox-blue:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(27 41 224/var(--tw-ring-opacity))}}@media (min-width:768px){.md\:flex-row{flex-direction:row}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0px*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px*var(--tw-space-y-reverse))}.md\:pl-8{padding-left:2rem}.md\:pr-8{padding-right:2rem}} \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..539d93c --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,76 @@ +max_width = 100 +hard_tabs = false +tab_spaces = 4 +newline_style = "Auto" +indent_style = "Block" +use_small_heuristics = "Default" +fn_call_width = 60 +attr_fn_like_width = 70 +struct_lit_width = 18 +struct_variant_width = 35 +array_width = 60 +chain_width = 60 +single_line_if_else_max_width = 50 +wrap_comments = false +format_code_in_doc_comments = false +doc_comment_code_block_width = 100 +comment_width = 80 +normalize_comments = false +normalize_doc_attributes = false +format_strings = false +format_macro_matchers = false +format_macro_bodies = true +hex_literal_case = "Preserve" +empty_item_single_line = true +struct_lit_single_line = true +fn_single_line = false +where_single_line = false +imports_indent = "Block" +imports_layout = "Mixed" +imports_granularity = "Preserve" +group_imports = "Preserve" +reorder_imports = true +reorder_modules = true +reorder_impl_items = false +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +short_array_element_width_threshold = 10 +overflow_delimited_expr = false +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = true +match_arm_leading_pipes = "Never" +force_multiline_blocks = false +# fn_params_layout = "Tall" +brace_style = "SameLineWhere" +control_brace_style = "AlwaysSameLine" +trailing_semicolon = true +trailing_comma = "Vertical" +match_block_trailing_comma = false +blank_lines_upper_bound = 1 +blank_lines_lower_bound = 0 +edition = "2021" +version = "One" +inline_attribute_width = 0 +format_generated_files = true +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true +condense_wildcard_suffixes = false +color = "Auto" +# required_version = "1.5.1" +unstable_features = true +disable_all_formatting = false +skip_children = false +hide_parse_errors = false +error_on_line_overflow = false +error_on_unformatted = false +ignore = [] +emit_mode = "Files" +make_backup = false diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5b166aa --- /dev/null +++ b/src/main.rs @@ -0,0 +1,7 @@ +use void_be::web_app_backend; + +#[rocket::main] +async fn main() -> Result<(), rocket::Error> { + let _rocket = web_app_backend::build_rocket().await.launch().await; + Ok(()) +} diff --git a/templates/index.html.hbs b/templates/index.html.hbs new file mode 100644 index 0000000..8342d7c --- /dev/null +++ b/templates/index.html.hbs @@ -0,0 +1,15 @@ + + + + {{app_title}} + + + + + + {{{style_include}}} + + +
{{{test}}}
+ + \ No newline at end of file diff --git a/void-be/Cargo.toml b/void-be/Cargo.toml new file mode 100644 index 0000000..04a94c5 --- /dev/null +++ b/void-be/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "void-be" +version = "0.1.0" +authors = ["Ada Werefox "] +edition = "2021" + +[dependencies] +void-fe = { path = "../void-fe" } +dioxus-ssr = { workspace = true } +once_cell = { workspace = true } + +# If you're unsure about why we're depending on a release candidate, +# check the Rocket documentation: +# https://rocket.rs/v0.5-rc/guide/upgrading/ +rocket = { workspace = true } + +# Needed to enable handlebar template support +[dependencies.rocket_dyn_templates] +version = "=0.1.0-rc.3" +features = ["handlebars"] diff --git a/void-be/src/lib.rs b/void-be/src/lib.rs new file mode 100644 index 0000000..badca77 --- /dev/null +++ b/void-be/src/lib.rs @@ -0,0 +1,194 @@ +//! # Rust Letter Backend +//! +//! `rust_letter_be` handles the backend execution using Rocket. + +#[macro_use] +extern crate rocket; + +/// A module that handles the backend for the site. +pub mod web_app_backend { + + use once_cell::sync::OnceCell; + use rocket::fs::FileServer; + use rocket::http::{Cookie, CookieJar}; + use rocket::response::Redirect; + use rocket::{Build, Rocket}; + use rocket_dyn_templates::{context, Template}; + use void_fe::utils::prop_structs::{PoemDatabase, VoidProps}; + use void_fe::utils::user_prefs::*; + use void_fe::void_app::{self, VirtualDom}; + + static POEM_DATABASE: OnceCell = OnceCell::new(); + + async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs { + let user_theme = match cookies.get("theme") { + Some(c) => match c.value() { + "auto" => ThemePref::Auto, + "light" => ThemePref::Light, + "dark" => ThemePref::Dark, + _ => { + cookies.remove(Cookie::named("theme")); + cookies.add(Cookie::new("theme", "auto")); + ThemePref::Auto + } + }, + None => { + cookies.add(Cookie::new("theme", "auto")); + ThemePref::Auto + } + }; + let user_font = match cookies.get("font") { + Some(c) => match c.value() { + "nerd" => FontPref::NerdFont, + "open" => FontPref::OpenDyslexic, + _ => { + cookies.remove(Cookie::named("font")); + cookies.add(Cookie::new("font", "open")); + FontPref::OpenDyslexic + } + }, + None => { + cookies.add(Cookie::new("font", "open")); + FontPref::OpenDyslexic + } + }; + UserPrefs::new(user_theme, user_font) + } + + async fn set_user_theme(cookies: &CookieJar<'_>, theme: &str) { + if theme == "light" || theme == "dark" || theme == "auto" { + cookies.remove(Cookie::named("theme")); + cookies.add(Cookie::new("theme", format!("{theme}"))); + } else { + return; + } + } + + async fn set_user_font(cookies: &CookieJar<'_>, font: &str) { + if font == "nerd" || font == "open" { + cookies.remove(Cookie::named("font")); + cookies.add(Cookie::new("font", format!("{font}"))); + } else { + return; + } + } + + #[get("/")] + async fn index(cookies: &CookieJar<'_>) -> Template { + let user_prefs = get_user_prefs(cookies).await; + let void_props = VoidProps { + slug: None, + poem_database: POEM_DATABASE + .get() + .expect("Poem database is not initialized") + .clone(), + user_prefs: user_prefs, + }; + let mut vdom = VirtualDom::new_with_props(void_app::HomePage, void_props); + let _ = vdom.rebuild(); + let output = dioxus_ssr::render(&vdom); + Template::render( + "index", + context! { + app_title: "A Letter to the Void", + style_include: "", + test: &output, + dark_mode: "", + }, + ) + } + + #[get("/", rank = 3)] + async fn settings(cookies: &CookieJar<'_>) -> Template { + let user_prefs = get_user_prefs(cookies).await; + let mut vdom = VirtualDom::new_with_props(void_app::SettingsPage, user_prefs); + let _ = vdom.rebuild(); + let output = dioxus_ssr::render(&vdom); + Template::render( + "index", + context! { + app_title: "Settings", + style_include: "", + test: &output, + dark_mode: "" + }, + ) + } + + #[get("/?", rank = 2)] + async fn theme(cookies: &CookieJar<'_>, theme: &str) -> Redirect { + set_user_theme(cookies, theme).await; + Redirect::to("/settings") + } + + #[get("/?")] + async fn font(cookies: &CookieJar<'_>, font: &str) -> Redirect { + set_user_font(cookies, font).await; + Redirect::to("/settings") + } + + #[get("/")] + async fn poem_list(cookies: &CookieJar<'_>) -> Template { + let user_prefs = get_user_prefs(cookies).await; + let void_props = VoidProps { + slug: None, + poem_database: POEM_DATABASE + .get() + .expect("Poem database is not initialized") + .clone(), + user_prefs: user_prefs, + }; + let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, void_props); + let _ = vdom.rebuild(); + let output = dioxus_ssr::render(&vdom); + Template::render( + "index", + context! { + app_title: "A Letter to the Void", + style_include: "", + test: &output, + dark_mode: "", + }, + ) + } + + #[get("/")] + async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template { + let user_prefs = get_user_prefs(cookies).await; + let void_props = VoidProps { + slug: Some(entry.to_string()), + poem_database: POEM_DATABASE + .get() + .expect("Poem database is not initialized") + .clone(), + user_prefs: user_prefs, + }; + let mut vdom = VirtualDom::new_with_props(void_app::PoemPage, void_props); + let _ = vdom.rebuild(); + let output = dioxus_ssr::render(&vdom); + Template::render( + "index", + context! { + app_title: "A Letter to the Void", + style_include: "", + test: &output, + dark_mode: "", + }, + ) + } + + /// This runs `rocket::build()` with the needed mounts and routes. + pub async fn build_rocket() -> Rocket { + let mut poem_database = PoemDatabase::new(); + poem_database.build_poem_database().await; + POEM_DATABASE.set(poem_database).expect("Could not initialize poem database."); + rocket::build() + .mount("/images", FileServer::from("public/images")) + .mount("/styles", FileServer::from("public/styles")) + .mount("/fonts", FileServer::from("public/fonts")) + .mount("/poems", routes![poem_list, poem]) + .mount("/settings", routes![settings, theme, font]) + .mount("/", routes![index]) + .attach(Template::fairing()) + } +} diff --git a/void-fe/.vscode/settings.json b/void-fe/.vscode/settings.json new file mode 100644 index 0000000..b9d9ce2 --- /dev/null +++ b/void-fe/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "rust-analyzer.cargo.extraArgs": ["--profile", "rust-analyzer"], + // "rust-analyzer.cargo.buildScripts.invocationLocation": "root", + "rust-analyzer.cargo.target": "wasm32-unknown-unknown", + // "rust-analyzer.cargo.buildScripts.overrideCommand": ["dioxus", "build"], + "rust-analyzer.check.overrideCommand": ["cargo", "check", "--quiet", "--message-format=json"], + "rust-analyzer.check.invocationLocation": "root", + "rust-analyzer.check.targets": ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"], + // "rust-analyzer.runnables.command": "dioxus serve", + "rust-analyzer.cargo.buildScripts.enable": false, + "rust-analyzer.linkedProjects": [ + "./Cargo.toml" + ], + "rust-analyzer.showUnlinkedFileNotification": false, + "rust-analyzer.hover.actions.run.enable": true, + "rust-analyzer.hover.actions.debug.enable": true, + "rust-analyzer.hover.documentation.enable": true, + "rust-analyzer.hover.actions.enable": true +} diff --git a/void-fe/Cargo.toml b/void-fe/Cargo.toml new file mode 100644 index 0000000..3942d91 --- /dev/null +++ b/void-fe/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "void-fe" +version = "0.1.0" +authors = ["Ada Werefox "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { workspace = true } +markdown = { workspace = true } +dioxus-web = "0.3.1" +dioxus-autofmt = "0.3.0" +# WebAssembly Debug +wasm-logger = "0.2.0" +console_error_panic_hook = "0.1.7" +log = "0.4.17" +dioxus-helmet = "0.2.4" +dioxus-use-storage = "0.3.0" +rand = "0.8.5" + +[dependencies.getrandom] +version = "0.2.9" +features = ["js"] + +[dependencies.serde] +version = "1.0.160" +features = ["derive"] + +[dependencies.dioxus-router] +version = "0.3.0" +features = ["query", "web"] + +[dependencies.rust-embed] +version = "6.6.1" +features = ["debug-embed"] diff --git a/void-fe/Dioxus.toml b/void-fe/Dioxus.toml new file mode 100644 index 0000000..ad3765e --- /dev/null +++ b/void-fe/Dioxus.toml @@ -0,0 +1,48 @@ +[application] + +# App (Project) Name +name = "void-werefox-cafe" + +# Dioxus App Default Platform +# desktop, web, mobile, ssr +default_platform = "web" + +# `build` & `serve` dist path +out_dir = "dist" + +# resource (public) file folder +asset_dir = "../public" + +[web.app] + +# HTML title tag content +title = "A Letter to the Void" + +[web.watcher] + +# when watcher triggers, regenerate the `index.html` +reload_html = true + +# which files or dirs will be watcher monitoring +watch_path = ["src", "data", "../public", "tailwind.config.js", "Dioxus.toml", "Cargo.toml", "build.rs"] + +# implement redirect on 404 +index_on_404 = true + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = ["/styles/tailwind.min.css"] + +# Javascript code file +script = [] + +[web.resource.dev] + +# CSS style file +style = ["/styles/tailwind.min.css"] + +# Javascript code file +# serve: [dev-server] only +script = [] diff --git a/void-fe/build.rs b/void-fe/build.rs new file mode 100644 index 0000000..80daf7a --- /dev/null +++ b/void-fe/build.rs @@ -0,0 +1,20 @@ +fn main() { + let mut tailwind = std::process::Command::new("npx"); + tailwind.args( + "tailwindcss -i src/index.css -c tailwind.config.js -o ../public/styles/tailwind.min.css --minify" + .split(" "), + ); + tailwind.env("NODE_ENV", "production"); + match tailwind.spawn() { + Ok(_) => (), + Err(_) => { + print!("Didn't find npx in the path, can't compile CSS. Is Node installed?"); + () + } + } +} +// let mut content = Vec::new(); +// for f in std::fs::read_dir("../data/poems").unwrap() { +// content.push(std::fs::read_to_string(f.unwrap().path()).unwrap()); +// } +// } diff --git a/void-fe/data/other/homepage.md b/void-fe/data/other/homepage.md new file mode 100644 index 0000000..c10f2ae --- /dev/null +++ b/void-fe/data/other/homepage.md @@ -0,0 +1,4 @@ + *"A pop punk dragon on the Internet"* \ +Feel free to click/tap any of the buttons above this to learn more about my different aspects of personality. \ +Down below, I've got some more neat little pages and useful info you can look at. \ +Please do look around and enjoy your stay!~ \ No newline at end of file diff --git a/void-fe/data/poems/2021-02-27_audio-reading.md b/void-fe/data/poems/2021-02-27_audio-reading.md new file mode 100644 index 0000000..8503ba5 --- /dev/null +++ b/void-fe/data/poems/2021-02-27_audio-reading.md @@ -0,0 +1,44 @@ +# im on repeat +*Author's note: Unfortunately, I've lost the audio reading for this.* + +Death is like a memory. Ceaseless, and comforting\ +Knowing things will end has always helped me feel like I'm free\ +I can do what I want, I can say what I feel\ +In the end, I know, I know the end is coming, what's the deal? + +I'm looping,\ +I'm stagnant,\ +Feel like I'm on repeat\ +My heart has got a leak + +I'm writing\ +These lines\ +About my broken dreams\ +About my fucking sheets + +I'm hating\ +my thoughts\ +About my bad streaks\ +About my endless sleep + +break free\ +break free\ +break free\ +break free + +And when the thoughts and my memories come flowing through an endless string\ +I can't stop typing because they never stop they never cease\ +I'm just a stream of consciousness, typing on a digital sheet\ +Some lines they'll never read, a face they'll never see\ +And if this is the end of me then please try to remember me\ +I'm breaking down, I'm broken, but I'm still here and you're seeing me\ +Why can't I stop these bad feelings? I know everyone cares for me + +but all I see\ +when I look at the broken screen\ +are the fears and insecurities + +I'm nothing\ +I'm hopeless\ +I'm looping\ +I'm on repeat \ No newline at end of file diff --git a/void-fe/data/poems/2021-02-28_iced-coffee.md b/void-fe/data/poems/2021-02-28_iced-coffee.md new file mode 100644 index 0000000..4856c84 --- /dev/null +++ b/void-fe/data/poems/2021-02-28_iced-coffee.md @@ -0,0 +1,32 @@ +# Iced Coffee +Listen to the song on Soundcloud + +*Iced coffee on a cold Winter's day* \ +*Iced coffee bittersweet at the taste* \ +*Do you see me? I probably fade* \ +*Fade into darkness and I'll go away* + +Hmm.... + +Why can't you see me this mirror is broken \ +Why can't you see me I can't be this broken \ +Every line keeping me from satisfaction \ +I'm wondering why you can keep me in traction \ +I'm falling I'm sinking this love is a sinkhole \ +I don't understand why you keep me, this freakshow \ +I see you and there's so much better contestants \ +Competing and winning and gaining attention \ +And I'm consolation, the prize for obsession \ +Don't know why you'd even give me just a second + +*Iced coffee on a cold Winter's day*\ +*Iced coffee bittersweet at the taste*\ +*Do you see me? I probably fade*\ +*Fade into darkness and I'll go away* + +*Hmmmm....*\ +*Hmmmm....*\ +*Hmmmm....* **(it's like... I don't really even know why I bother)**\ +*Hmmmm....* **(am I even worth paying attention to in the first place?)**\ +*Hmmmm....*\ +*Hmmmm....* \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-01_sweetheart-sweet-tea-6ck4.md b/void-fe/data/poems/2021-03-01_sweetheart-sweet-tea-6ck4.md new file mode 100644 index 0000000..6292ecd --- /dev/null +++ b/void-fe/data/poems/2021-03-01_sweetheart-sweet-tea-6ck4.md @@ -0,0 +1,44 @@ +# Sweetheart, Sweet Tea +Do you remember? \ +The first time that we had met \ +Oh, I'm sure I don't regret that memory \ +Do you remember? \ +It's a story I'll forget \ +But the resolution finds itself yet + +You said you'd never leave me, hun \ +Oh, please just don't deceive me, hun \ +My honeysuckle, lemon sweetener \ +She won't leave me if I keep her \ +Close and in my comfort space \ +I know my heart I can't replace \ +But if you find the heart to keep me \ +I know that you'll never leave me + +Do you remember? \ +It's getting harder to forget \ +Every memory we make along the way \ +Do you remember? \ +The first time I called you "friend"\ +Oh, the resolution finds itself yet + +You said you'd never leave me, hun \ +Oh, please just don't deceive me, hun \ +My honeysuckle, lemon sweetener \ +She won't leave me if I keep her \ +Close and in my comfort space \ +I know my heart I can't replace \ +But if you find the heart to keep me \ +I know that you'll never leave me + +Honeysuckle, lemon sweetener \ +She won't leave me if I keep her \ +But if you find the heart to keep me \ +I know that you'll never lead me on + +Do you remember? \ +Every day I don't regret \ +Oh, I'm sure I won't forget your simple smile \ +Do you remember? \ +Hopefully you're satisfied \ +Cus the resolution lets me stay a while \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-02_writing-myself-into-my-own-grave-ill-never-be-happy.md b/void-fe/data/poems/2021-03-02_writing-myself-into-my-own-grave-ill-never-be-happy.md new file mode 100644 index 0000000..fa4d6de --- /dev/null +++ b/void-fe/data/poems/2021-03-02_writing-myself-into-my-own-grave-ill-never-be-happy.md @@ -0,0 +1,49 @@ +# Writing Myself Into My Own Grave (“I’ll never be happy”) +*You should keep your distance*\ +*You should never stay*\ +*You should learn your lesson*\ +*I’m never okay*\ +*I’ll always be wanting*\ +*More than I can say*\ +*Use your fucking head now*\ +*And please stay away*\ +*“I’ll never be happy”*\ +*That’s the simple phrase*\ +*Always pushing boundaries*\ +*Always such a pain*\ +*Writing lines is hopeless*\ +*Just pills to help delay*\ +*You should learn your lesson*\ +*I’m never okay* + +Mhm mhm.\ +**(It’s time for a break)** + +*I’m never satisfied, don’t you think that you’d agree?*\ +*Just a sad, pathetic, hopeless mess with endless strife and grief*\ +*You can say that I’m perfection, you can tell me that you care*\ +*You can say I deserve better, now just let me go from there*\ +*I’m nobody’s posession, no one’s aiming for my pride*\ +*And deserving better never helped me, I think that’s a lie*\ +*Now it’s not about attention, and it’s not about my worth*\ +*It’s not about a partnership I’ll never find on Earth*\ +*It’s the simple fact I’m broken and I’m tearing at the seams*\ +*Try to keep myself together helping other people, see?* + +*I worry about people*\ +*I worry how I’m seen*\ +*I worry what they think of me when I’m not on their screen*\ +*I worry if they think of me at all, just the same*\ +*I wonder if they worry ‘bout me too, when they’re in-game*\ +*I always seem to focus on if everyone’s alright*\ +*I always seem to go to bed and wonder through the night* + +*“Are they okay?”*\ +*“Did they see me?”*\ +*“Am I helping?”*\ +*I’m repeating* + +*I go to bed*\ +*I close my eyes*\ +*Another day*\ +*Another night* \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-03_introductions.md b/void-fe/data/poems/2021-03-03_introductions.md new file mode 100644 index 0000000..88ce2be --- /dev/null +++ b/void-fe/data/poems/2021-03-03_introductions.md @@ -0,0 +1,25 @@ +# Introductions +Hi! I'm Alice, and um... Uh.\ +I have something I wanna say, I guess... + +*Fuck yeah, I'm a trans girl*\ +*A "fuck the thoughts you had" girl*\ +*Yeah, I'm a bad bitch and I won't clean up my act, girl* + +Hah + +*I'm a poet and a hot mess*\ +*Don't wear a fucking suit and tie, I wanna wear cute dress*\ +**(moan)** *"Yes, ma'am," damn, I bet you wanna date this*\ +*Well, get in line, sweetie, I'm in high demand, wait list* + +Yeah + +*And I'm impatient*\ +*Only 3 months, downed the pills, and it leaves me fuckin restless*\ +*Your heart is on my wish list*\ +*Got pussy on my mind and not just 'cus I wanna lick clits* + +Damn \ +Better calm down a bit here \ +**(Is it hot in here? Or is that just me?)** \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-07_molded-hearts-and-melted-love.md b/void-fe/data/poems/2021-03-07_molded-hearts-and-melted-love.md new file mode 100644 index 0000000..d02bcec --- /dev/null +++ b/void-fe/data/poems/2021-03-07_molded-hearts-and-melted-love.md @@ -0,0 +1,40 @@ +# Molded Hearts and Melted Love +*Author’s Note: This song/poem has heavy overtones of relationship abuse. Please be aware of that before you read.* + +I’ve never been the one to think I’m waiting on their time\ +But days go by I’m wondering if they’re really satisfied\ +They tell me that that love me, and they’re happy to oblige\ +But when I ask for more forgiveness, it’s too much, I can’t deny + +I let myself believe that I’m the one who’s done wrong\ +And I can fix it baby, please, just let me write this little song\ +All the problems, all the issues, I can change myself you’ll see\ +I can mold myself so maybe you’ll stop yelling at me, please + +They’re wonderful, they’re pleasant, and I tell them every day\ +They message me on weekdays, other friends must stay away\ +When we’re calling every night I hear their voice just start to fade\ +They’re telling me it’s fine, and yet I know it’s not okay + +I let myself believe that I’m the one who’s done wrong\ +And I can fix it baby, please, just let me write this little song\ +All the problems, all the issues, I can change myself you’ll see\ +I can mold myself so maybe you’ll stop yelling at me, please + +I want them to be happy, I want them to be pleased\ +Why can’t I just be perfect? I’ll be anything they need\ +Since when did love become a game of trying to succeed\ +I hate this, every day I cry, I need to be set free + +(And yet)\ +I let myself believe that I’m the one who’s done wrong\ +And I can fix it baby, please, just let me write this little song\ +All the problems, all the issues, I can change myself you’ll see\ +I can mold myself so maybe you’ll stop yelling at me, please + +All the problems, all the issues, I can change myself you’ll see\ +I can mold myself so maybe you’ll stop yelling at me, please + +[Epilogue] + +(I love you, I just want you to love me... No, please, please say something... No don’t leave please just- I’m sorry. I’m sorry, I shouldn’t have said anything, you’re right.... I’ll stop talking to them... I’m sorry, please... Okay. Yes... Alright... I love you.... Are you okay?... I love you... I’m sorry... I’ll change, please just don’t leave me...) \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-07_poetry-to-the-void.md b/void-fe/data/poems/2021-03-07_poetry-to-the-void.md new file mode 100644 index 0000000..59349e3 --- /dev/null +++ b/void-fe/data/poems/2021-03-07_poetry-to-the-void.md @@ -0,0 +1,18 @@ +# Poetry to the Void +*Author's note: here's a bit of freeform poetry I wrote a while back that I thought I'd share. I know it doesn't flow super well, but I'm proud of it, and I think it's good sometimes to write stuff that's a bit off beat when it's meaningful to do so* + +Empty hearts and empty sheets \ +I'm sleeping in my dreams \ +And I wish I could say they were the same feel that I get when I see your name on my screen \ +Wish you were in my dreams when I'm fast asleep and I can't control the pace or the scene \ +But when I wake up it's still a fantasy \ +I'm alone and unseen \ +Empty hearts and black dreams \ +I'm sleeping in my sheets \ +And I wish that I could say you were here with me when I wake up and hear your name in my mind \ +Wish you were by my side and held tight and I can't convey how good it feels every time \ +But when I wake up it's still a fantasy \ +I'm alone and unseen \ +Tell me the difference between day dreaming and the way you pass right through my hands when I try to hold you \ +I'm missing someone I've never felt in the presence of my room or my heart before and I can't explain it, can't convey it \ +Still just writing lines to a void that comforts me as much as the paper I'd recycle when I'm done bleeding ink on the page \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-08_a-moments-rest-at-a-peaceful-shore.md b/void-fe/data/poems/2021-03-08_a-moments-rest-at-a-peaceful-shore.md new file mode 100644 index 0000000..bda0322 --- /dev/null +++ b/void-fe/data/poems/2021-03-08_a-moments-rest-at-a-peaceful-shore.md @@ -0,0 +1,14 @@ +# A Moment's Rest at a Peaceful Shore +The wind calms, the storm in my mind settles\ +The static pervading off the edges of my mind's perspective finally begins to focus itself into a clearer darkness + +My thoughts wedge themselves into place\ +For a brief moment, I am collected, as the fears and insecurities of my life slowly inch themselves further away + +The tide is low, I am standing at the shore\ +A breeze gently brushes past my skin as I ponder when the wind will pick up again and leave me to brave its harsh gusts + +Evidently, the storm will return\ +The static will regain its strength, and my thoughts will cloud themselves once more as I attempt to continue forward + +For now, in this moment, I am at peace \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-13_black-rose-gray-skies.md b/void-fe/data/poems/2021-03-13_black-rose-gray-skies.md new file mode 100644 index 0000000..6965b34 --- /dev/null +++ b/void-fe/data/poems/2021-03-13_black-rose-gray-skies.md @@ -0,0 +1,59 @@ +# Black Rose, Gray Skies +**[Intro]**\ +Black rose, thorns sharp and trapped inside a clear vessel\ +Petals falling, won't you please come and save this wilting weed\ +Slower still, it's a tragic, but slow death inside the glass cage\ +Seasons change, nights fade and dissipate into similar shades of gray + +**[Chorus]**\ +*On the windowsill, perched and perfectly still*\ +*I can see the brightest stars in the sky*\ +*Yes, the wind is still, make a wish, if you will*\ +*And I will too in hopes that time goes by* + +**[Verse 1]**\ +*This is*\ +*Not a cry for help, I don't need my princess Belle*\ +*I just want to truly be set free*\ +*I am*\ +*Trapped in this case, though it's safe, I'm afraid*\ +*Will I be the rose I see inside?*\ +*You can*\ +*Find me up here, perched and perfectly still*\ +*Kicked my feet and staring up so high*\ +*Black rose*\ +*Prick me again, make me bleed, little friend*\ +*Oh, if only I weren't in my mind* + +**[Chorus]**\ +*On the windowsill, perched and perfectly still*\ +*I can see the brightest stars in the sky*\ +*Yes, the wind is still, make a wish, if you will*\ +*And I will too in hopes that time goes by* + +**[Verse 2]**\ +*I don't*\ +*Want to be afraid, there's much progress I have made*\ +*And I'm only getting further, still*\ +*I am*\ +*Trapped inside my cage, don't see a way I can escape*\ +*A cognitive prison, against my will*\ +*Looking down*\ +*Will never help, I see my death, my biggest doubts*\ +*A fall that's deep enough that it would kill*\ +*So I*\ +*Keep my head held high, looking up into the sky*\ +*As the petals wilt onto the 'sill* + +**[Chorus]**\ +*On the windowsill, perched and perfectly still*\ +*I can see the brightest stars in the sky*\ +*Yes, the wind is still, make a wish, if you will*\ +*And I will too in hopes that time goes by* + +**[Epilogue]**\ +I look down at the black rose, the vessel is as glossy and beautiful as the treasure it contains\ +The stars in the sky look down at me and smile, and I can feel their warm glow from here\ +If I could be that rose, take it outside its cell and transfuse its radiant beauty\ +I am a dreamer in the hopes that one day the vessel shatters and I too will be set free\ +A rose like no other, with thorns trimmed, and petals full as it blooms in the new morning Sun \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-17_bittersweet-cheers.md b/void-fe/data/poems/2021-03-17_bittersweet-cheers.md new file mode 100644 index 0000000..fb96bf7 --- /dev/null +++ b/void-fe/data/poems/2021-03-17_bittersweet-cheers.md @@ -0,0 +1,61 @@ +# Bittersweet, Cheers +**[Intro]**\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*things are gonna change, yeah*\ +*things are gonna change* + +**[Verse 1]**\ +*I try to tell myself I'm happier in place*\ +*but that's a lie, dear*\ +*we all know my fears*\ +*I'm just worried what you think and what you'll say*\ +*am I talented yet?*\ +*questions in my own head* + +**[Pre-Chorus]**\ +*and if my friends and followers know me*\ +*then they'll know this song before I show them it* + +**[Chorus]**\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*another year gone, am I stuck in place?*\ +*but when I look back I don't recognize my own face*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*even for better, for worse, I'm here*\ +*and my words are echoing clear, my dear* + +**[Verse 2]**\ +*feels like I can't write a happy poem*\ +*but what's there to say?*\ +*not happy everyday*\ +*and I don't need you to feel sorry for me*\ +*this one's for my peers*\ +*bittersweet thoughts, cheers* + +**[Pre-Chorus]**\ +*and if my friends and followers know me*\ +*then they'll know this song before I show them it* + +**[Chorus]**\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*another year gone, am I stuck in place?*\ +*but when I look back I don't recognize my own face*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*things are gonna change, yeah*\ +*things are gonna change*\ +*even for better, for worse, I'm here*\ +*and my words are echoing clear, my dear* + +*another year gone, am I stuck in place?*\ +*but I don't look back, I just keep my pace* \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-18_notification-high.md b/void-fe/data/poems/2021-03-18_notification-high.md new file mode 100644 index 0000000..bf558fc --- /dev/null +++ b/void-fe/data/poems/2021-03-18_notification-high.md @@ -0,0 +1,30 @@ +# Notification High +**[Chorus]**\ +*I'm hot, I'm cool, I'm the best you've ever seen*\ +*not my ego, not a brag, just the facts up on the screen*\ +*I take selfies cus I'm worth it and you all just need to see*\ +*click, snap, upload, tap, here come the notifs loud and clear* + +**[Verse 1]**\ +*I can't help it if you're falling over me (click, snap, upload, tap)*\ +*though it sure is fun to see your little squeaks (click, snap, upload, tap)*\ +*judge me perfect, I'm a quirky little freak (click, snap, upload, tap)*\ +*boost my pictures, tell me sweet words, pray to God that I will see (click, snap upload, tap)* + +**[Chorus]**\ +*I'm hot, I'm cool, I'm the best you've ever seen*\ +*not my ego, not a brag, just the facts up on the screen*\ +*I take selfies cus I'm worth it and you all just need to see*\ +*click, snap, upload, tap, here come the notifs loud and clear* + +**[Bridge]**\ +*click, snap, upload, tap, click, snap, upload, tap* (I sometimes think that I'm too much, it's true)\ +*click, snap, upload, tap, click, snap, upload, tap* (I sometimes act like I don't have a clue)\ +*click, snap, upload, tap, click, snap, upload, tap* (I sometimes worry if it is the truth)\ +*click, snap, upload, tap, click, snap, upload, tap* (All this attention, this attention, this attention, this attention) + +**[Chorus]**\ +*I'm hot, I'm cool, I'm the best you've ever seen*\ +*not my ego, not a brag, just the facts up on the screen*\ +*I take selfies cus I'm worth it and you all just need to see*\ +*click, snap, upload, tap, here come the notifs loud and clear* \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-28_echoes.md b/void-fe/data/poems/2021-03-28_echoes.md new file mode 100644 index 0000000..4a3159c --- /dev/null +++ b/void-fe/data/poems/2021-03-28_echoes.md @@ -0,0 +1,71 @@ +# Echoes +**[Verse 1]** + +*Echoes*\ +*Of someone I used to be*\ +*Though I think I left myself quite far behind*\ +*Troubles*\ +*Of my life, they fade away*\ +*Getting distant as I keep myself on time* + +**[Pre-Chorus]** + +*You can't see me, you can't see me*\ +*But I'm growing*\ +*Just believe me, just believe me*\ +*I can show it*\ +*I thought I was done with proving*\ +*Myself worthy* + +*No, I'm not*\ +*The show goes on, I'm sorry* + +**[Chorus]** + +*Echoes, echoes, echoes*\ +*Remind me of a time, my dear*\ +*When I was once alone beside myself*\ +*Echoes, echoes, echoes*\ +*Used to read between the lines to clear*\ +*Me up on blurry lenses in my mind* + +*Now the echoes fade away*\ +*And I'm not who I used to be, but that's okay, it fades away some day* + +**[Verse 2]** + +*Pictures*\ +*Of a thing I used to see*\ +*Yet I keep it out of focus in the end*\ +*Memories*\ +*The scenes of yesterday*\ +*I'm so happy that I'm not who I was then* + +**[Pre-Chorus]** + +*You can't see me, you can't see me*\ +*But I'm growing*\ +*Just believe me, just believe me*\ +*I can show it*\ +*I thought I was done with proving*\ +*Myself worthy* + +*No, I'm not*\ +*The show goes on, I'm sorry* + +**[Chorus]** + +*Echoes, echoes, echoes*\ +*Remind me of a time, my dear*\ +*When I was once alone beside myself*\ +*Echoes, echoes, echoes*\ +*Used to read between the lines to clear*\ +*Me up on blurry lenses in my mind* + +*Now the echoes fade away*\ +*And I'm not who I used to be, but that's okay, it fades away some day* + +*Echoes, echoes, echoes* + +*Now the echoes fade away*\ +*And I'm not who I used to be, but that's okay, it fades away some day* \ No newline at end of file diff --git a/void-fe/data/poems/2021-03-29_youll-grow-out-of-this.md b/void-fe/data/poems/2021-03-29_youll-grow-out-of-this.md new file mode 100644 index 0000000..2ae3fb1 --- /dev/null +++ b/void-fe/data/poems/2021-03-29_youll-grow-out-of-this.md @@ -0,0 +1,34 @@ +# "You'll Grow Out Of This" +**[Verse 1]** + +*I write songs I'll never sing*\ +*Like I write lines you'll never read*\ +*And I can't help but be afraid*\ +*That I can't finish anything* + +**[Verse 2]** + +*My emotions not in check*\ +*Sorry, did I just say that?*\ +*I don't know why I am so sad*\ +*Now I'll cry and say my bad* + +**[Chorus]** + +*This is where I'd make a break, a part of this song to repeat*\ +*But I don't care what it should say, 'cus I'm already bored, okay?*\ +*This is where I'd write some lines to keep myself from going on*\ +*And if I don't then you'll move on because this song is way too long* + +**[Verse 3]** + +*ADHD isn't grand*\ +*It's more than just attention span*\ +*I just hope you'll understand*\ +*That I cannot control my hands* + +**[Verse 4]** + +*I could write more songs I guess*\ +*Instead of doing all the rest*\ +*Depends on if I finish this* \ No newline at end of file diff --git a/void-fe/data/poems/2021-04-04_foxes-are-predators.md b/void-fe/data/poems/2021-04-04_foxes-are-predators.md new file mode 100644 index 0000000..36811be --- /dev/null +++ b/void-fe/data/poems/2021-04-04_foxes-are-predators.md @@ -0,0 +1,43 @@ +# Foxes Are Predators +*I used to think about the monsters underneath my bed*\ +*Hiding in the darkness, now they're stuck inside my head*\ +*Why does everything I write feel like a call for help?*\ +*Reaching out and seeing that no one knows how to tell* + +*I've become the predator*\ +*The arrow on your hearts*\ +*Flailing wildly, spewing toxins*\ +*That's the hardest part*\ +*I'm no hunter, I don't bite, I think you might agree*\ +*Lately I've been seeing there's a deeper side of me* + +*Used to think about the many friendships I had held*\ +*Keeping people close, wondering if they kept me as well*\ +*Why does my destructive cycle keep on catching me?*\ +*Pushing them away and watching how they distance me* + +*I've become the predator*\ +*The arrow on your hearts*\ +*Flailing wildly, spewing toxins*\ +*That's the hardest part*\ +*I'm no hunter, I don't bite, I think you might agree*\ +*Lately I've been seeing there's a deeper side of me* + +*Lately I've been seeing there's a deeper side of me*\ +*Come on, see me closer, and I think you might agree*\ +*Look into my spiraling and thinking well of me*\ +*Promise that I'll hurt you, but don't misunderstand me* + +*I don't want to be villainous or toxic at my core*\ +*I really wish that I could just stop hurting anymore*\ +*I don't know how to fix this, but I'm trying all my tricks*\ +*I cannot keep on hurting people, 'cus it makes me sick* + +*I need you to believe me because sometimes I can't see it*\ +*So please look a little closer and I promise I will be a bit*\ +*More kind and empathetic and the person that you wanna be*\ +*Friends with, and maybe partners, maybe that's a little private see*\ +*I can't tell if I'm spiraling right now my thoughts keep flowing*\ +*And I don't know if you ever will quite know just what I'm knowing*\ +*Yeah, so let me finish writing and I'll get back to conspiring*\ +*How I'll be a better predator for you* \ No newline at end of file diff --git a/void-fe/data/poems/2021-04-27_missing-the-mark.md b/void-fe/data/poems/2021-04-27_missing-the-mark.md new file mode 100644 index 0000000..a24faaa --- /dev/null +++ b/void-fe/data/poems/2021-04-27_missing-the-mark.md @@ -0,0 +1,24 @@ +# Missing The Mark +*Lately I've been thinking 'bout how miserable I've been*\ +*Sadness never comforts me, but it's been my best friend*\ +*And I could write more lines 'bout how I wish I could see*\ +*All the love and friendship all my peers tell me they see* + +*Oh God, I wish*\ +*I could be happy for myself*\ +*Oh God, I wish*\ +*I could be happy for myself* + +*Keeping myself busy so the bad thoughts stay away*\ +*Telling myself good things so emotions won't go stray*\ +*Battles, always battles, fight the bad side of my brain*\ +*No, I'm not alone, but still it sometimes feels that way* + +*Oh God, I wish*\ +*I could be happy for myself*\ +*Oh God, I wish*\ +*I could be happy for myself*\ +*Oh God, I wish*\ +*I could be happy for myself* + +**It always seems it should be easier than this** \ No newline at end of file diff --git a/void-fe/data/poems/2021-05-19_support-class.md b/void-fe/data/poems/2021-05-19_support-class.md new file mode 100644 index 0000000..c331761 --- /dev/null +++ b/void-fe/data/poems/2021-05-19_support-class.md @@ -0,0 +1,21 @@ +# Support Class +*Words like knives carving thoughts into the pages of my life*\ +*Like scattered scraps of paper torn and fluttering in the wind*\ +*So too am I temporary and fleeting* + +*Like fingers pulling back and tearing at a lockbox of treasures*\ +*The tendrils scratching and aggressively tugging at my heart*\ +*It makes me feel wanted* + +*The thoughts and feelings and memories and doting and loving phrases echo in my mind ceaselessly to remind me that I am better and more whole than I was before*\ +*And when I look up into the stars and see them shining back at me it is a reminder that I am a small and insignificant being, but that I am wanted and loved and cared for all the same*\ +*And maybe when it's thoughts like this I don't feel so alone and afraid*\ +*And maybe I can learn for myself to love who I have become again* + +*We fall into these traps like moths and flies sinking deeply*\ +*Desperately clawing and bemoaning our woes and fears*\ +*But it's not too late* + +*Fight, bite, bark, and resist the plagues in your own self conscious*\ +*I am the protagonist of my own hopes, dreams, and desires*\ +*And you all are my support* \ No newline at end of file diff --git a/void-fe/data/poems/2021-05-27_i-wish-i-wore-my-garters.md b/void-fe/data/poems/2021-05-27_i-wish-i-wore-my-garters.md new file mode 100644 index 0000000..93a48c7 --- /dev/null +++ b/void-fe/data/poems/2021-05-27_i-wish-i-wore-my-garters.md @@ -0,0 +1,38 @@ +# I Wish I Wore My Garters +*I hate my bedroom door*\ +*I have to try a couple times to push it open*\ +*I hate to feel like I'm confined*\ +*I have to pee, and now I wanna go outside*\ +*But I'm still trapped inside my mind* + +*I hate this wooden floor* \ +*The second floor was just a little too intrusive* \ +*And every time I have to climb* \ +*A flight of stairs to get to where I feel I'm fine* \ +*But I'm still trapped inside my mind* + +*This feels good, yeah, this feels real*\ +*This feels healthy, so it seems*\ +*A shot of dopamine has got me wondering if this keeps*\ +*Circling, winding, aching headaches*\ +*Swirling thoughts and catching feelings, too* \ +*I'll see you soon* + +*I hate my ceiling fan* \ +*I have to keep it on because if not it's too hot* \ +*But I don't mean that I look nice*\ +*I have to keep the room from heating up this time*\ +*But I'm still trapped inside my mind* + +*I hate my bedroom door* \ +*I have to try a couple times to push it open* \ +*I hate to feel like I'm confined* \ +*So many walls and I'm not fine* \ +*I want to get outside my mind* \ +*I can't stop thinking every time* \ +*I don't want thoughts to make me cry*\ +*I just want to feel satisfied* \ +*There's just so many times I've tried*\ +*I hope my partner helps me smile* \ +*I bet my friends will stay a while*\ +*But I'm still trapped inside my mind* \ No newline at end of file diff --git a/void-fe/data/poems/2021-07-21_since-when-did-winter-end.md b/void-fe/data/poems/2021-07-21_since-when-did-winter-end.md new file mode 100644 index 0000000..84f92f5 --- /dev/null +++ b/void-fe/data/poems/2021-07-21_since-when-did-winter-end.md @@ -0,0 +1,53 @@ +# Since When Did Winter End +*I’m a mess*\ +*A disaster, but I see it in a better light now than I did before*\ +*I’m a mess*\ +*But I manage every moment, and I get along well when it’s not as warm* + +*Seasons change, people change*\ +*I’m not a perfect model*\ +*I can tell you how to improve*\ +*While I lament all my struggles*\ +*Then you’ll see* + +*When Winter ends I think I get*\ +*A little less upsetting*\ +*So it seems* + +*Here’s the thing*\ +*I know it’s not quite summer, but I’ll make believe it’s just as bright outside*\ +*Here’s the thing*\ +*You would think it would be better, but predictions haven’t ever been my pride* + +*Seasons change, people change*\ +*It’s not always the weather*\ +*I look around at all the leaves*\ +*And see that change is better*\ +*It’s insane* + +*When Winter ends I think I get*\ +*A little less upsetting*\ +*So it seems* + +*It’s surreal*\ +*Can’t believe so much has happened, I reminisce and then I wonder if it’s real*\ +*It’s surreal*\ +*I know Winter’s fast approaching, I’m prepared and I’m excited now, I feel* + +*Seasons change, people change*\ +*I can’t believe I’m here now*\ +*The time goes by and I still*\ +*Think that yesterday was 1 month*\ +*I’m impressed* + +*When Winter ends I think I get*\ +*A little less upsetting*\ +*So it seems* + +*When Winter ends I think I get*\ +*A little less upsetting*\ +*A little less depressing*\ +*A little less regretting*\ +*A little less repressing*\ +*A little less regressing*\ +*So it seems* \ No newline at end of file diff --git a/void-fe/data/poems/2021-07-25_shes-not-who-she-used-to-be.md b/void-fe/data/poems/2021-07-25_shes-not-who-she-used-to-be.md new file mode 100644 index 0000000..23630f2 --- /dev/null +++ b/void-fe/data/poems/2021-07-25_shes-not-who-she-used-to-be.md @@ -0,0 +1,36 @@ +# She's Not Who She Used To Be +*She looks in the mirror and likes what she sees*\ +*It's obvious she's not who she used to be*\ +*Thought she had her life found out by 14*\ +*But isn't it easy to think that, it seems*\ +*Thinking it's over just ain't quite her style*\ +*"Running, I'm running" she said for a while*\ +*Run from her problems, run from mistakes*\ +*Run because she doesn't understand things* + +*She's not a model, she's not a queen*\ +*Stressed and depressed, she would look up and scream*\ +*Running in circles, she said she was fine*\ +*"It'll always be this way" she said with a sigh*\ +*That's just who she is, and it won't ever change*\ +*She felt like she'd always be looked at as strange*\ +*Hiding her gender, hiding her heart*\ +*Keeping it secret's the easiest part* + +*"I'm fed up, I'm stuck, and I've had enough"*\ +*She wanted a change, she knew it'd be tough*\ +*She took a deep breath and decided to try*\ +*She quit her job, outed herself, and then cried*\ +*There's no point in trying to live a big lie*\ +*There's no point in not even trying to try*\ +*She talked to some friends and she knew what to do*\ +*"I'll fight for myself, cus it's long overdue"* + +*She looks in the mirror and likes what she sees*\ +*It's obvious she's not who she used to be*\ +*The sad, lonely teenager just wanting friends*\ +*The stressed, upset college kid hiding her dread*\ +*"I know I'm a girl, and I see it right now"*\ +*Things line up neatly, and clearer, somehow*\ +*That's my big story, that's who you see* \ +*I'm glad that I'm not who I used to be* \ No newline at end of file diff --git a/void-fe/data/poems/2021-11-21_probably-bad-for-you.md b/void-fe/data/poems/2021-11-21_probably-bad-for-you.md new file mode 100644 index 0000000..b630800 --- /dev/null +++ b/void-fe/data/poems/2021-11-21_probably-bad-for-you.md @@ -0,0 +1,45 @@ +# Probably Bad For You +*When did all the lights begin to fade away?*\ +*I see them now, I see them now*\ +*When did you decide to leave me hurt this way?*\ +*I'm healing now, won't bleed it out* + +*All the little silly things you said to put me down*\ +*And all the guilt trips sink into a funnel in the ground and now *\ +*It's clear I'm not gonna be by your side next year* + +*And now I'm probably bad for you*\ +*I know I'm kind of a sin to you*\ +*And maybe I'm still in love with you*\ +*But I am probably bad for you* + +*So when did you decide what's right from what's wrong?*\ +*Well, I'll sort it out, I'll sort it out*\ +*When did you decide I'm not the shining star you sought?*\ +*I'm shining now, bright through the clouds* + +*All the little silly things you said all those thoughts drown*\ +*And all the nights I stayed up hoping you would call me out and now*\ +*It's clear I'm not gonna be by your side next year* + +*And now I'm probably bad for you*\ +*I know I'm kind of a sin to you*\ +*And maybe I'm still in love with you*\ +*But I am probably bad for you* + +*Keep me close, keep me near*\ +*Tell me things I wanna hear*\ +*Let me know I'm not too far from home*\ +*Satisfy me just once more*\ +*Send excuses to my door*\ +*And don't forget to post it all, my dear*\ +*It's clear I'm not gonna be by your side next year* + +*I know I'm probably bad for you*\ +*I know I'm kind of a sin to you*\ +*And I don't think I'm in love with you*\ +*'Cus now I'm definitely bad for you* + +*All the little silly things I did to keep me in your mind*\ +*And all the times I sat alone at home and wondered why and now*\ +*It's clear I don't wanna be by your side next year* \ No newline at end of file diff --git a/void-fe/data/poems/2022-01-20_filtered-thoughts.md b/void-fe/data/poems/2022-01-20_filtered-thoughts.md new file mode 100644 index 0000000..1658bc3 --- /dev/null +++ b/void-fe/data/poems/2022-01-20_filtered-thoughts.md @@ -0,0 +1,20 @@ +# Filtered Thoughts +*Sometimes I wonder if I could write to save my life*\ +*Sometimes I wonder if all the effort's worth the strife*\ +*I've been down this road before and now the twists are turns are pleasant*\ +*Don't get too comfy, though, because I'm throwing another curveball at you* + +*All the rhythms and the sounds and the echoes leave me restless*\ +*I've been thinking, I've been thinking, I've been thinking of the present*\ +*Turning circles in my head and now I'm spiraling down under but*\ +*Don't take me there because Australia's just too many timezones apart* + +*Fuck you, I don't need this judgemental mindless headspace*\ +*I've been trying to keep up with all the thoughts and it's got me displaced*\ +*I can feel like I'm alone, but like I'm here, and now it doesn't make sense*\ +*I wish you could see beyond these filtered thoughts, I'm crying when I'm silent* + +*It might feel like I'm just rambling in the distance*\ +*It might feel like there's no pattern here and it's all senseless*\ +*The waves of my mind keep my time and now I'm pondering still*\ +*Sometimes I wonder if I'm loved for my posts or my personality* \ No newline at end of file diff --git a/void-fe/data/poems/2022-05-22_i-can-never-see-past-next-week.md b/void-fe/data/poems/2022-05-22_i-can-never-see-past-next-week.md new file mode 100644 index 0000000..bc87752 --- /dev/null +++ b/void-fe/data/poems/2022-05-22_i-can-never-see-past-next-week.md @@ -0,0 +1,18 @@ +# I can never see past next week +*A moment of peace in a busy world of busy people*\ +*Staring out the window, the view of the balcony just blissfully capturing what my heart feels*\ +*Though the loving embrace of the morning sun shines on me again, I can't help but let those thoughts intrude*\ +*Still fearing the storm*\ +*Still waiting for it to show* + +*A path I know I am to travel again and travel fully*\ +*There is time again until I must stand up and walk this path with ceaseless confidence*\ +*Whether or not I am a changed woman, the journey continues ever onward toward the horizon*\ +*Never ending past the hills*\ +*Never did I quite sit still* + +__Silence__\ +__Stillness__\ +__Serenity__ + +*Someday, I will make my break upon that path again* \ No newline at end of file diff --git a/void-fe/data/poems/2022-09-06_27.md b/void-fe/data/poems/2022-09-06_27.md new file mode 100644 index 0000000..b9cafc4 --- /dev/null +++ b/void-fe/data/poems/2022-09-06_27.md @@ -0,0 +1,44 @@ +# 27 +**27**\ +*I used to think that day was just a far off dream for me*\ +*Dreading when I wake because I can't see past next week*\ +*"What's the point of living if I'm just living a lie?"*\ +*Those echoes in my memory are far away tonight* + +**27**\ +*I used to think that I was all alone feeling this pain*\ +*Using words and writing poems to keep up the pace*\ +*Whisper reassurances to myself to feel safe*\ +*Hugging pillows tightly as I'm drifting in this space* + +**27**\ +*Now the railing that I'm safely behind keeps me sane*\ +*I'm not quite the black rose that I pricked, but just the same*\ +*I still can't see past next week, but maybe that's okay*\ +*Maybe in this case my age was not an early grave* + +**27**\ +*Now I use a new name and I wear a different face*\ +*But I'm still the same girl even if I'm less afraid*\ +*Back then I sat on sidelines to watch everyone else live*\ +*And now, for once, it's my turn, I've got something new to give* + +**27**\ +*I don't need to tell myself that I'm not worth living*\ +*I don't need to hold onto my reassurances*\ +*I don't need to feel like if I left no one would care*\ +*I've made it this far and now I'm letting myself live* + +**27**\ +*I'm doing my best and I know that's all I can do* \ +*I know it's enough and I know you will see it, too*\ +*This life is so precious and that's why, now, I can say* \ +*I'm glad that I know that I'll be turning 28* + +*There's no big ending, no big rhyme to close off this chapter* \ +*I'm not ending anything with a bang or a whimper* \ +*Just acknowledging what I've now firmly put behind me* + +This is how it ends \ +This is how it starts \ +I deserve it. \ No newline at end of file diff --git a/void-fe/data/poems/2023-01-31_they-said-i-could-be-anything-when-i-grew-up-but-i-was-already-a-girl-im.md b/void-fe/data/poems/2023-01-31_they-said-i-could-be-anything-when-i-grew-up-but-i-was-already-a-girl-im.md new file mode 100644 index 0000000..13649cd --- /dev/null +++ b/void-fe/data/poems/2023-01-31_they-said-i-could-be-anything-when-i-grew-up-but-i-was-already-a-girl-im.md @@ -0,0 +1,58 @@ +# They Said I Could Be Anything When I Grew Up, But I Was Already A Girl (I'm Living Proof) +*I still can't see past next week\ +It feels like an eternity and I\ +Can't keep waiting up\ +Life's for living 'til we're dead\ +But I'm not finished writing yet and I\ +Hope you're keeping up\ +I can't keep saying "it'll be next year"* + +(I wanna be "me" today)\ +*Fuck your opinion - I'm not listening\ +Cause I won't let those words take hold of me\ +I'm not afraid to be me (fuck, if I'm not a girl, then what gives you the right to tell me)\ +Fuck your opinion - I'm not listening\ +Cause I'm done being afraid to reach my peak\ +I'm not afraid to be me\ +I'm not afraid to be me* + +*I still can't see past next week\ +I'd even fear it in my sleep and I\ +Can't keep waking up\ +Dreams are meant to be lived out\ +No, I won't let you shape my doubts and I\ +Won't stop looking up\ +I can't keep saying "it'll be next year"* + +(I wanna be "me" today)\ +*Fuck your opinion - I'm not listening\ +Cause I won't let those words take hold of me\ +I'm not afraid to be me (fuck, if I'm not a girl, then what gives you the right to tell me)\ +Fuck your opinion - I'm not listening\ +Cause I'm done being afraid to reach my peak\ +I'm not afraid to be me\ +I'm not afraid to be me* + +*There's always so damn much to fear\ +There's always something creeping near\ +And I can't wait inside my room forever clutching my own sides* + +*There's always someone making fun\ +There's always some fuck with a gun\ +But I can't let that stop me living for the first time in my life* + +(I wanna be "me" today)\ +*Fuck your opinion - I'm not listening\ +Cause I won't let those words take hold of me\ +I'm not afraid to be me (fuck, if I'm not a girl, then what gives you the right to tell me)\ +Fuck your opinion - I'm not listening\ +Cause I'm done being afraid to reach my peak\ +I'm not afraid to be me\ +I'm not afraid to be me* + +(I'm not afraid to be me) *Fuck your gender roles, fuck biology*\ +(I'm not afraid to be me) *I know that I'm a girl, don't need to "wait and see"*\ +(I'm not afraid to be me) *'Cause I'm not done yet, I'm just at the start*\ +(I'm not afraid to be me) *I'll keep on writing 'til I empty out my heart* + +[**Yeah, in case you hadn't noticed, I'm a fucking girl - deal with it.**] \ No newline at end of file diff --git a/void-fe/data/poems/2023-02-15_drop-kicked-from-senselessness.md b/void-fe/data/poems/2023-02-15_drop-kicked-from-senselessness.md new file mode 100644 index 0000000..5f9e12a --- /dev/null +++ b/void-fe/data/poems/2023-02-15_drop-kicked-from-senselessness.md @@ -0,0 +1,14 @@ +# Drop Kicked From Senselessness +*Soft, muttered frequencies on the periphery of my subconscious*\ +*A tune I used to hear that flickers its presence*\ +*Giving me leverage of which to confine myself within the most secluded of spaces*\ +*That distant melody echoing against the walls of my mind*\ +*Silent, familiar wavelengths of nothingness that protrude*\ +*The flooding sensations of lights fluttering among darkness*\ +**Stop. Stop this.** + +*As the static fades out from its crescendo I am thrust outside those walls again*\ +*Glimmering bleak reality returning its vibrancy to mock my estate*\ +*The tempo and pacing and rhythm of the natural beats consume the timeline of my vision*\ +*Balancing myself and weighing my feet as though I've dropped from a short ledge*\ +*And that tune that was once so prominent is back in its chambers* \ No newline at end of file diff --git a/void-fe/data/poems/2023-02-28_what-do-you-mean-youre-not-gay-you-fucking-dated-me.md b/void-fe/data/poems/2023-02-28_what-do-you-mean-youre-not-gay-you-fucking-dated-me.md new file mode 100644 index 0000000..fabce54 --- /dev/null +++ b/void-fe/data/poems/2023-02-28_what-do-you-mean-youre-not-gay-you-fucking-dated-me.md @@ -0,0 +1,53 @@ +# What do you mean you're not gay, you fucking dated me +*Waiting on you to blink me to life*\ +*She said I'm her backup [gal] in the end*\ +*I've never been one to pull away*\ +*Say what you like, babe, love drunk in my bed*\ +*It never seemed like I was worth all the fuss*\ +*But if you made up your mind, then who could I trust?* + +*I'm wasting my years on you, babe*\ +*So you can call me your [girl]friend, or friend, anyway*\ +*It was never like you to change*\ +*The way that you view my life*\ +*So fuck off, screw you, I'm fine* + +*I'm just a mess who can't see my fate*\ +*Tell me again how to better serve you*\ +*Writing a post to get out my thoughts*\ +*I'd just be worse off, you told me the truth*\ +*"I just don't see you as a girl," she would try*\ +*And now you won't hear me say "this is my damn life"* + +*I'm wasting my years on you, babe*\ +*So you can call me your [girl]friend, or friend, anyway*\ +*It was never like you to change*\ +*The way that you view my life*\ +*So fuck off, screw you, I'm fine* + +*Tell me I'm not so useful anymore*\ +*You're moving on, and I'm just a bore*\ +*Say it to my face with this faded haze* + +**(spoken, ranting, raw)**\ +Cus let's face it, you wouldn't have the guts to say it sober\ +I'm worth so much more than you ever made me feel like\ +And the thought of you ending it on the note of how bad you feel just makes me angrier\ +It's like you literally never considered my feelings in your own selfish decisions\ +And then you have the fucking nerve to come to me\ +Saying shit like "I feel bad that things ended this way"\ +All while fucking deadnaming me in the process\ +I'm glad that you gave up on me, because I should have done it sooner\ +Oh, and that surgery you told me not to pursue because it would make you sad?\ +Fuck you. I'm getting it. I've needed it. Just leave me the fuck alone\ +Go back to your sad life with your miserable "career" and choke on it\ +You couldn't even make enough change to give yourself happiness\ +Why would I expect you to do so for me? + +*I'm wasting my years on you, babe*\ +*So you can call me your [girl]friend, or friend, anyway*\ +*It was never like you to change*\ +*The way that you view my life*\ +*So fuck off, screw you, I'm fine*\ +Fuck off, screw you, I'm fine. + diff --git a/void-fe/data/poems/2023-03-03_senseless-murmurs-of-the-estranged-the-last-night.md b/void-fe/data/poems/2023-03-03_senseless-murmurs-of-the-estranged-the-last-night.md new file mode 100644 index 0000000..9366aaa --- /dev/null +++ b/void-fe/data/poems/2023-03-03_senseless-murmurs-of-the-estranged-the-last-night.md @@ -0,0 +1,51 @@ +# Senseless Murmurs of the Estranged (~~The~~ Last Night) +*Slithering fangs and pointy tails*\ +*Tell me if I'm not feeling well*\ +*My mindscape's hazard lights sing symphonies that plead me not to crash*\ +*Maybe that last line's just a touch-*\ +*I'm feeling obsessed with feeling up*\ +*But the rhythm of our continued stumbling keeps me anchored on the act* + +*Maybe I'm not making sense*\ +*Break it down a little first* + +*Singing out my heartstrings like they never gave a pause*\ +*I'm writing another washed out drawn out rant recalling how we stalled*\ +*And you were always the one I asked for in my nighttime bender gleam*\ +*Separate the colors, strip my words, and paint the walls with apathy* + +*Cold night summer sunsets bail*\ +*Another take out date night last meal*\ +*Surrender my senses call my cell and keep my phrases right on track*\ +*The writing is on the wall tonight*\ +*Blinding reflections kill my sight*\ +*A murderous moment of dismemberment from feelings that you lack* + +*Maybe I'm not making sense*\ +*Break it down a little first* + +*Singing out my heartstrings like they never gave a pause*\ +*I'm writing another washed out drawn out rant recalling how we stalled*\ +*And you were always the one I asked for in my nighttime bender gleam*\ +*Separate the colors, strip my words, and paint the walls with apathy* + +*Call me out on conflict resolution from temptation of my thoughts*\ +*Shatter the glass and flip the script of all the preface that you wrought*\ +*I'm not seeing light;*\ +*this blurry image right;*\ +*choke my eyes, drain my voice;*\ +*break my ego, mayday;*\ +*I'll take solace knowing this will be the last night of this play*\ +*Where I'm the actor, you're the audience and I'm the one who pays* + +*Maybe I'm not making sense*\ +*Break it down a little first* + +*Singing out my heartstrings like they never gave a pause*\ +*I'm writing another washed out drawn out rant recalling how we stalled*\ +*And I can't stab myself in places that I know I shouldn't keep-*\ +*Me- I mean you, and this is true, I'm waking from this heavy sleep*\ +*I'll write my will, I've had my doubts, I'm singing songs, I'm bleeding out*\ +*Waterfalls perched on the windows of my dreary excess pout*\ +*And you were always the one I asked for in my nighttime bender gleam*\ +*Separate the colors, strip my words, and paint the walls with apathy* \ No newline at end of file diff --git a/void-fe/data/poems/2023-04-10_iced-coffe-part-2.md b/void-fe/data/poems/2023-04-10_iced-coffe-part-2.md new file mode 100644 index 0000000..66010a4 --- /dev/null +++ b/void-fe/data/poems/2023-04-10_iced-coffe-part-2.md @@ -0,0 +1,75 @@ +# Iced Coffee - Part 2 +*(Author's note: The first part of this is exactly the same as my original poem, "Iced Coffee". I included it both as a way to directly show my own growth in the poem and for convenience.)* + +*Iced coffee, on a cold Winter's day* \ +*Iced coffee, bittersweet at the taste* \ +*Do you see me? I probably fade* \ +*Fade into darkness, and I'll go away* + +Hmm.... + +*Why can't you see me? This mirror is broken* \ +*Why can't you see me? I can't be this broken* \ +*Every line keeping me from satisfaction* \ +*I'm wondering why you can keep me in traction* \ +*I'm falling, I'm sinking, this love is a sinkhole* \ +*I don't understand why you keep me, this freakshow* \ +*I see you and there's so much better contestants* \ +*Competing and winning and gaining attention* \ +*And I'm consolation, the prize for obsession* \ +*Don't know why you'd even give me just a second* + +*Iced coffee, on a cold Winter's day* \ +*Iced coffee, bittersweet at the taste* \ +*Do you see me? I probably fade* \ +*Fade into darkness and I'll go away* + +*Hmmmm....* \ +*Hmmmm....* \ +*Hmmmm....* **(it's like... I don't really even know why I bother)** \ +*Hmmmm....* **(am I even worth paying attention to in the first place?)** \ +*Hmmmm....* \ +*Hmmmm....* + +*Iced coffee, on a cold Winter's day* \ +*Iced coffee, bittersweet at the taste* \ +*Now you see me, and I'll be okay* \ +*I have my darkness so far tucked away* + +(chuckle) + +*I never thought I would tell you I've accepted* \ +*That I've resolved all of my feelings of shame* \ +*I've moved on and found others who keep me present* \ +*Remind me that being alone is okay* \ +*I look back and think about that pain you caused me* \ +*And realize I should have voiced my refrain* \ +*You never owed me all your time and attention* \ +*You never owed me anything, just the same* + +*We both agree there are much bigger aggressions* \ +*Than anger from feeling abandoned or strayed* \ +*I'm happy to find some common resolution* \ +*I'm happy we don't talk and I'm not afraid* \ +*I feel so much better about my own presence* \ +*I feel so much better and now I can say* \ +*That drinking iced coffee no longer reminds me* \ +*Of feeling isolated from your embrace* \ +*So I wrote more verses to speak of acceptance* \ +*I'm closing the book on that unhappy moment* + +*Iced coffee, on a cold Winter's day* \ +*Iced coffee, bittersweet at the taste* \ +*Now you see me, and I'll be okay* \ +*I have my darkness so far tucked away* + +*Hmmmm....* \ +*Hmmmm....* \ +*Hmmmm....* **(I wrote "Iced Coffee" to express some feelings I had at the time)**\ +*Hmmmm....* **(and while those feelings were valid. I realize now)**\ +*Hmmmm....* **(that the insecurity I felt had more to do with my self-worth)**\ +*Hmmmm....* **(and my reliance on needing someone to hold onto)**\ +*Hmmmm....* **(in order to keep myself feeling happy and safe)**\ +*Hmmmm....* **(I just wanted to express that I've grown since then)**\ +*Hmmmm....* \ +*Hmmmm....* \ No newline at end of file diff --git a/void-fe/data/poems/2023-05-16_what-should-you-say.md b/void-fe/data/poems/2023-05-16_what-should-you-say.md new file mode 100644 index 0000000..45d3d78 --- /dev/null +++ b/void-fe/data/poems/2023-05-16_what-should-you-say.md @@ -0,0 +1,73 @@ +# Gender Isn't Something You Can Make Someone Be (What Should You Say?) + +What should you say? \ +What should you do? \ +When there are so many people out there \ +Looking up at you \ +\ +I can't stop being so impressive \ +I can't stop being so obscene \ +Showing myself to the whole damn world \ +Making everyone say "that's who I wanna be" \ +\ +It's true that it's scary being "normal" \ +It's true that the journey's quite a drag \ +Queen in the making, I'm celebrating \ +Can't shoot me down in this middle act \ +\ +What should you say? \ +What should you do? \ +When there are so many people out there \ +Looking up at you, I'd say \ +\ +Fuck it, this life is right for me \ +Fuck it, laws can't keep me from being me \ +You wanna get me hiding under my bed \ +Parading colors like it was the national flag \ +\ +It's too hard to be cisgender \ +It's too hard to be unseen \ +I can't hide who I am and that's just \ +What they don't wanna see from me \ +\ +What should you say? \ +What should you do? \ +When there are so many people out there \ +Looking up at you \ +\ +I'm a monster, I'm a scene \ +Cut throat killers, living dreams \ +I'm the topic of the week, committing phrases on the screen \ +\ +No way back to home right now \ +There's nothing safe about the South \ +I'm no predator, but my pen writes bullets shooting from my snout \ +\ +Radical conservatives \ +Can kiss my ass and choke on it \ +Yeah, I'm not normal, but maybe normal's not a word that should persist \ +\ +I'm happy, I'm laughing, I'm living my life \ +You can't stop me when you put me in your sights \ +I'll wave my flag proudly and give you a punch \ +Can not see you liking that treatment too much \ +\ +What should you say? \ +What should you do? \ +When there are so many people out there \ +Looking up at you \ +\ +This is where I'd end the story \ +Somewhere happy and complete \ +But we're just getting started here \ +Don't keep running from your dreams \ +\ +It may seem hopeless to hold on \ +But we're all stronger and they'll see \ +The only things killing trans teens \ +Are bigots yelling in the streets \ +\ +So what should you say? \ +What should you do? \ +When there are so many people out there \ +Looking up at you diff --git a/void-fe/data/poems/2023-05-23_what-kind-of-dragon-has-acrophobia.md b/void-fe/data/poems/2023-05-23_what-kind-of-dragon-has-acrophobia.md new file mode 100644 index 0000000..876c2a9 --- /dev/null +++ b/void-fe/data/poems/2023-05-23_what-kind-of-dragon-has-acrophobia.md @@ -0,0 +1,35 @@ +# What Kind Of Dragon Has Acrophobia +_I may be a dragon, but I don't breathe fire for the thrill_ \ +_I may be a killer, but I killed my sinning shrill_ \ +_Voice in my head telling me to fight my fears_ \ +_Scales, claws gone scraping at my heart_ \ +_I'll never die, I'll never fall as long as my wings_ \ +_Can save me from my own self-doubt_ \ +\ +_The gnawing fangs of my own perpetual arrogance_ \ +_Blowing smoke like vapor waves flowing in a dance_ \ +_To invoke my surreptitious slithering tongue_ \ +_Making marks at poignant chapters_ \ +_The footnotes of my autobiography made live_ \ +_Seeking through the lines on the hunt_ \ +\ +_Tear my own holes in the plot_ \ +_Rip apart pages from the script_ \ +_Why am I always afraid to fall_ \ +_Why do I miss being human_ \ +_In a world where I'm anything_ \ +_But the same chained avian_ \ +_Singing songs to myself_ \ +_Writing words I'll burn up_ \ +\ +_The silence of the past leaves echoes in my soul_ \ +_And even though the play continues onward still_ \ +_I can't stop asking myself who I am in the end_ \ +_Questioning myself and defying my insecurity_ \ +\ +_I am a dragon at heart_ \ +_and when I soar I'll ignite_ \ +_the spirits of my greatest endeavors_ \ +_brought to life not by my own accord,_ \ +_but with the assistance of those who tend_ \ +_to the ashes I create around me_ \ No newline at end of file diff --git a/void-fe/data/poems/2023-06-14_hope-you-think-about-me.md b/void-fe/data/poems/2023-06-14_hope-you-think-about-me.md new file mode 100644 index 0000000..936d868 --- /dev/null +++ b/void-fe/data/poems/2023-06-14_hope-you-think-about-me.md @@ -0,0 +1,52 @@ +# hope you think about me + +_When I think about you_ \ +_When I think about me_ \ +_I think about every little problem that I wish I couldn't see_ \ +_When I'm lying awake_ \ +_When I'm trying to sleep_ \ +_I wanna just make the most of all my little dreams and memories_ \ +_Hope you think about me_ + +_Yeah, I'm kind of a freak_ \ +_A mess of scales and sharp teeth_ \ +_But I make myself out to be the softest of the dragons on your screen_ \ +_I'm a little bit hurt_ \ +_Just a little obscene_ \ +_Tie myself a new tourniquet to heal the places that I still might bleed_ + +_Yeah, I'm not perfect_ \ +_Yeah, I'm still not "me"_ \ +_But it's still worth it_ \ +_To walk down this street_ \ +_Hope you think about me_ \ +_Hope you think about me_  + +_She's a little uncouth_ \ +_She's a bit of a geek_ \ +_Don't you think it's just terribly attractive how she mumbles in her sleep_ \ +_Stumbling over her words_ \ +_Still, she's smiling at me_ \ +_Can't she just take the words out of your mouth and write them down effortlessly_ + +_I'm still improving_ \ +_I'm still not done_ \ +_Glad that I'm not_ \ +_The only one_ \ +_Hope you think about me_ \ +_Hope you think about me_ + +_I'm marching toward this new horizon_ \ +_With my hopes and dreams intact_ \ +_There's still so much I've yet to live for_ \ +_The past is left behind my back_ \ +_I'm still figuring this out, one step, one breath, one at a time_ \ +_I wanna learn how I can fly to let my wings lift me up high_ \ +_I'm so scared to take my jump now, this is it, no turning back_ \ +_I feel the tailwind brush against me, but I'm still not ready yet_ + +_Hope you think about me_ \ +_Hope you think about me_ **(Another night goes by, one breath at a time)** \ +_Hope you think about me_ **(I'm still not ready, but at least you know I'm trying)** \ +_Hope you think about me_ **(I do my best, and all the rest that I can say is...)** \ +_Hope you think about me_ \ No newline at end of file diff --git a/void-fe/data/poems/2023-08-29_another-day.md b/void-fe/data/poems/2023-08-29_another-day.md new file mode 100644 index 0000000..cb2a900 --- /dev/null +++ b/void-fe/data/poems/2023-08-29_another-day.md @@ -0,0 +1,52 @@ +# Another day + +*It's been a while now, huh?* \ +*I haven't wanted to write anything since then* \ +*It's quite a ride, though, huh?* \ +*Twisted turns in my head make me want to stop* + +*The days are moving on so slow* \ +*Time was never on my side much, though* \ +*And I could write another thousand words today* \ +*But there's not much you don't already know* + +*Can't think of one more line* \ +*I put the pen to the paper, but there it ends* \ +*Gotta write one more rhyme* \ +*Make the words come out more, effortlessly* + +*The days are moving on so slow* \ +*Time was never on my side much, though* \ +*And I could write another thousand words today* \ +*But there's not much you don't already know* + +*I tried to write my life out* \ +*I tried to do my best* \ +*I made my own decisions* \ +*Foolish, I confess* \ +*I live the consequences* \ +*I keep on moving forward* + +*My head keeps on spinning* \ +*I'm always repeating* \ +*These words are all searing* \ +*Are you all done hearing?* + +*The days are moving on so slow* \ +*Time was never on my side much, though* \ +*And I could write another thousand words today* \ +*But there's not much you don't already know* + +**They call it writer's block, but I don't feel like anyone's blocking me** \ +**I'm my own locked safe, and I've gone and lost the key** \ +**Trying my best, a dragon's fire is strong in the end** \ +**Eventually, the lock breaks, and I build a new safe again** \ +**It's a cycle that I struggle to comprehend and to stop** \ +**But the ends justify the means, I'll take one for the team** \ +**The next one's easier, each time one more drops** \ +**And I learn a little more about me** + +*The days are moving on so slow* \ +*Time was never on my side much, though* \ +*And I could write another thousand words today* \ +*But there's not much you don't already know* \ No newline at end of file diff --git a/void-fe/src/components.rs b/void-fe/src/components.rs new file mode 100644 index 0000000..ae03ce6 --- /dev/null +++ b/void-fe/src/components.rs @@ -0,0 +1,6 @@ +pub mod void_buttons; +pub mod void_footer; +pub mod void_page; +pub mod void_poem; +pub mod void_title; +pub mod void_content; \ No newline at end of file diff --git a/void-fe/src/components/void_buttons.rs b/void-fe/src/components/void_buttons.rs new file mode 100644 index 0000000..06a7406 --- /dev/null +++ b/void-fe/src/components/void_buttons.rs @@ -0,0 +1,72 @@ +use super::super::utils::{ + prop_structs::{ButtonProps, ContentChildren}, + user_prefs::{ThemedComponent, UserPrefs}, +}; +use dioxus::prelude::*; + +#[cfg(target_family = "wasm")] +use dioxus_router::Link; + +pub fn BackToHomePage(cx: Scope) -> Element { + let (user_theme, user_font) = cx.props.clone().get_pref_classes(ThemedComponent::Button); + #[cfg(any(target_family = "windows", target_family = "unix"))] + return cx.render(rsx!{ + a { class: "flex justify-center p-4 text-xl text-center ring-2 hover:animate-yip transition {user_theme} {user_font}", + href: "/", + p { + "Back to the homepage" + } + } + }); + #[cfg(target_family = "wasm")] + return cx.render(rsx!{ + Link { class: "flex justify-center p-4 text-xl text-center ring-2 hover:animate-yip transition {user_theme} {user_font}", + to: "/", + p { + "Back to the homepage" + } + } + }); +} + +pub fn NavigationButton(cx: Scope) -> Element { + let (user_theme, mut user_font) = cx + .props + .user_prefs + .clone() + .get_pref_classes(ThemedComponent::Button); + let title = cx.props.title.clone(); + let title_ref = title.as_str(); + let slug = cx.props.slug.clone(); + let slug_ref = slug.as_str(); + + match &cx.props.override_font { + Some(font) => user_font = font.clone(), + None => (), + } + + #[cfg(any(target_family = "windows", target_family = "unix"))] + return cx.render(rsx!{ + a { class: "flex basis-full justify-center p-4 ml-2 mr-2 text-xl text-center ring-2 hover:animate-yip transition {user_theme} {user_font}", + href: "{slug_ref}", + "{title_ref}" + } + }); + #[cfg(target_family = "wasm")] + return cx.render(rsx!{ + Link { class: "flex basis-full justify-center p-4 ml-2 mr-2 text-xl text-center ring-2 hover:animate-yip transition {user_theme} {user_font}", + to: "{slug_ref}", + div { + dangerous_inner_html: "{title_ref}", + } + } + }); +} + +pub fn ButtonGroup<'a>(cx: Scope<'a, ContentChildren<'a>>) -> Element { + cx.render(rsx! { + div { class: "flex md:flex-row md:space-y-0 flex-col space-y-4", + &cx.props.children + } + }) +} diff --git a/void-fe/src/components/void_content.rs b/void-fe/src/components/void_content.rs new file mode 100644 index 0000000..7159592 --- /dev/null +++ b/void-fe/src/components/void_content.rs @@ -0,0 +1,21 @@ +// Might wanna move stuff form `void_poem.rs` into here... +use crate::utils::prop_structs::{ContentProps}; +use super::super::utils::user_prefs::ThemedComponent; +use dioxus::prelude::*; + +pub fn RenderContent(cx: Scope) -> Element { + let (user_theme, user_font) = cx.props.user_prefs.get_pref_classes(ThemedComponent::Card); + let content = &cx.props.content; + #[cfg(any(target_family = "windows", target_family = "unix"))] + return cx.render(rsx!{ + div { class: "flex p-4 md:pl-8 md:pr-8 ml-4 mr-4 text-md text-center ring-4 {user_theme} {user_font}", + "{content}", + } + }); + #[cfg(target_family = "wasm")] + return cx.render(rsx!{ + div { class: "flex p-4 md:pl-8 md:pr-8 ml-4 mr-4 text-md text-center ring-4 {user_theme} {user_font}", + dangerous_inner_html: "{content}", + } + }); +} diff --git a/void-fe/src/components/void_footer.rs b/void-fe/src/components/void_footer.rs new file mode 100644 index 0000000..977865e --- /dev/null +++ b/void-fe/src/components/void_footer.rs @@ -0,0 +1,28 @@ +use crate::{ + components::void_buttons::{ButtonGroup, NavigationButton}, + utils::user_prefs::{ThemedComponent, UserPrefs}, +}; +use dioxus::prelude::*; + +pub fn Footer(cx: Scope) -> Element { + cx.render(rsx! { + MutantStandardFooter { theme: cx.props.clone().get_theme(), font: cx.props.clone().get_font() } + }) +} + +fn MutantStandardFooter(cx: Scope) -> Element { + let user_prefs = UserPrefs::new(cx.props.clone().get_theme(), cx.props.clone().get_font()); + let user_theme = cx.props.get_theme_classes(ThemedComponent::Card); + let user_font = cx.props.get_font_class(); + cx.render(rsx!{ + div { class: "p-4 flex flex-col space-y-4 mx-auto max-w-full justify-center ring-4 {user_theme} {user_font}", + ButtonGroup{ + NavigationButton { title: "⚙️ Settings".to_string(), slug: "/settings".to_string(), user_prefs: user_prefs.clone() } + NavigationButton { title: " /src".to_string(), slug: "https://gitea.werefox.cafe/ada/void-werefox-cafe".to_string(), user_prefs: user_prefs, override_font: "font-nerd".to_string() } + } + div { class: "flex mx-auto max-w-full justify-center text-md text-center", + "This site uses Mutant Standard emoji, which are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License" + } + } + }) +} diff --git a/void-fe/src/components/void_page.rs b/void-fe/src/components/void_page.rs new file mode 100644 index 0000000..e2ba025 --- /dev/null +++ b/void-fe/src/components/void_page.rs @@ -0,0 +1,13 @@ +use crate::utils::prop_structs::PageChildren; +use dioxus::prelude::*; + +pub fn PageBase<'a>(cx: Scope<'a, PageChildren<'a>>) -> Element { + cx.render(rsx! { + span { hidden: true, + a { rel: "me", href: "https://yiff.life/@werefox", "Mastodon" } + } + div { class: "min-h-screen", + div { class: "container space-y-4 pt-4 pb-4 max-w-3xl", &cx.props.children } + } + }) +} diff --git a/void-fe/src/components/void_poem.rs b/void-fe/src/components/void_poem.rs new file mode 100644 index 0000000..db9504a --- /dev/null +++ b/void-fe/src/components/void_poem.rs @@ -0,0 +1,88 @@ +use crate::components::void_buttons::*; +use crate::components::void_title::*; +use crate::utils::prop_structs::VoidProps; +use crate::utils::{prop_structs::PoemChildren, user_prefs::ThemedComponent}; +use dioxus::prelude::*; + +pub fn PoemList(cx: Scope) -> Element { + let poem_list = cx.props.poem_database.get_poem_list(); + cx.render(rsx! { + ul { class: "flex flex-col space-y-4", + poem_list.into_iter().map(|p| { + let slug = format!("/poems/{}", p.0); + rsx!{ + NavigationButton { title: p.1, slug: slug, user_prefs: cx.props.user_prefs.clone() } + } + }) + } + }) +} + +pub fn MakePoem<'a>(cx: Scope<'a, PoemChildren<'a>>) -> Element { + cx.render(rsx! { + div { class: "flex-col space-y-4", + &cx.props.children + } + }) +} + +pub fn GetPoem(cx: Scope) -> Element { + let poem_database = &cx.props.poem_database; + let slug = String::from(&cx.props.slug.clone().expect("No slug specified.")); + let poem_struct = poem_database.get_poem(slug.clone()); + cx.render(rsx! { + Title { title: poem_struct.title.clone(), is_html: true, user_prefs: cx.props.user_prefs.clone() } + MakePoem{ + PoemContent { slug: slug, poem_database: poem_database.clone(), user_prefs: cx.props.user_prefs.clone() } + } + }) +} + +pub fn PoemContent(cx: Scope) -> Element { + let (user_theme, user_font) = cx.props.user_prefs.get_pref_classes(ThemedComponent::Card); + let slug = cx + .props + .slug + .as_ref() + .expect("Received slug for poem selection."); + let content = &cx + .props + .poem_database + .poem_hashmap + .get(slug) + .expect("Grabbed poem stuct from databse.") + .content + .clone(); + let creation_date = &cx + .props + .poem_database + .poem_hashmap + .get(slug) + .expect("Grabbed poem struct from database.") + .creation_date + .clone(); + let publish_string = "\u{003C}br\u{003E}\u{003C}br\u{003E}\u{003C}br\u{003E}Published: "; + #[cfg(any(target_family = "unix", target_family = "windows"))] + return cx.render(rsx! { + div { class: "flex p-2 mx-auto max-w-full justify-center", + details { class: "group p-4 max-w-fit space-y-4 ring-4 {user_theme} {user_font}", + summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 hover:animate-yip transition ring-2 {user_theme} {user_font}", + } + div { class: "flex flex-col space-y-4 py-4 ml-4 mr-4", "{content}{publish_string}{creation_date}" + } + } + } + }); + #[cfg(target_family = "wasm")] + return cx.render(rsx! { + div { class: "flex p-2 mx-auto max-w-full justify-center", + details { class: "group p-4 max-w-fit space-y-4 ring-4 {user_theme} {user_font}", + summary { class: "group-open:before:content-['Close'] before:content-['Open'] flex justify-center p-2 hover:animate-yip transition ring-2 {user_theme} {user_font}", + } + div { class: "flex flex-col space-y-4 py-4 ml-4 mr-4", + dangerous_inner_html: "{content}{publish_string}{creation_date}", + } + } + } + }); +} diff --git a/void-fe/src/components/void_title.rs b/void-fe/src/components/void_title.rs new file mode 100644 index 0000000..773e685 --- /dev/null +++ b/void-fe/src/components/void_title.rs @@ -0,0 +1,41 @@ +use crate::utils::prop_structs::TitleProps; +use super::super::utils::user_prefs::ThemedComponent; +use dioxus::prelude::*; + +pub fn Title(cx: Scope) -> Element { + let user_prefs = cx.props.user_prefs.clone(); + let title_classes = user_prefs.get_theme_classes(ThemedComponent::Card); + let title = cx.props.title.clone(); + let is_html = cx.props.is_html; + cx.render(rsx!{ + div { class: "p-4 ring-4 {title_classes}", + span { class: "flex flex-row mx-auto max-w-full justify-center text-xl text-center", + TitleHtml { title: title, is_html: is_html, user_prefs: user_prefs } + } + } + }) +} + +fn TitleHtml(cx: Scope) -> Element { + let title = cx.props.title.clone(); + if cx.props.is_html { + #[cfg(any(target_family = "unix", target_family = "windows"))] + return cx.render(rsx! { + span { class: "flex flex-row align-middle mx-auto max-w-full justify-center", + "{title} " + } + }); + #[cfg(target_family = "wasm")] + return cx.render(rsx! { + span { class: "flex flex-row align-middle mx-auto max-w-full justify-center", + div { dangerous_inner_html: "{title}", } + } + }); + } else { + return cx.render(rsx! { + span { + "{title}" + } + }); + } +} diff --git a/void-fe/src/index.css b/void-fe/src/index.css new file mode 100644 index 0000000..75e5bdc --- /dev/null +++ b/void-fe/src/index.css @@ -0,0 +1,13 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@font-face { + font-family: "OpenDyslexic"; + src: url("/fonts/OpenDyslexic-Regular.otf"); +} + +@font-face { + font-family: "DejaVuSansMono"; + src: url("/fonts/DejaVuSansMono.ttf"); +} diff --git a/void-fe/src/lib.rs b/void-fe/src/lib.rs new file mode 100644 index 0000000..95e79f1 --- /dev/null +++ b/void-fe/src/lib.rs @@ -0,0 +1,175 @@ +//! # Rust Letter Frontend +//! +//! Rendering functions for the site using [Dioxus](https://dioxuslabs.com/). + +#![allow(non_snake_case)] + +mod components; +pub mod utils; + +/// A module that handles the functions needed +/// to render the site. +pub mod void_app { + + // import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types + pub use dioxus::prelude::*; + + use crate::components::void_buttons::*; + use crate::components::void_content::*; + use crate::components::void_footer::*; + use crate::components::void_page::PageBase; + use crate::components::void_poem::*; + use crate::components::void_title::*; + use crate::utils::helpers; + use crate::utils::prop_structs::*; + use crate::utils::user_prefs::*; + + #[cfg(any(target_family = "wasm"))] + use dioxus_helmet::Helmet; + #[cfg(any(target_family = "wasm"))] + use dioxus_router::{Link, Redirect, Route, Router}; + #[cfg(any(target_family = "wasm"))] + use dioxus_use_storage::use_local_storage; + + #[cfg(target_family = "wasm")] + pub fn DioxusApp(cx: Scope) -> Element { + let mut poem_database = PoemDatabase::new(); + poem_database.build_poem_database(); + + let user_prefs = UserPrefs::new(ThemePref::Auto, FontPref::OpenDyslexic); + + cx.render(rsx! { + Router { + Route { to: "/", HomePage { slug: "/".to_string(), poem_database: poem_database.clone(), user_prefs: user_prefs.clone(), } } + Route { to: "/poems", PoemListPage { slug: "/poems".to_string(), poem_database: poem_database.clone(), user_prefs: user_prefs.clone(), } } + Route { to: "/poems/:slug", PoemPage { slug: "".to_string(), poem_database: poem_database.clone(), user_prefs: user_prefs.clone(), } } + Route { to: "/settings", SettingsPage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } } + Route { to: "/settings/dark", SettingsPage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } } + Route { to: "/settings/font", SettingsPage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } } + Route { to: "", PageNotFound {} } + } + }) + } + + #[cfg(target_family = "wasm")] + fn PageNotFound(cx: Scope) -> Element { + cx.render(rsx! { + p { "That page doesn't exist, sorry!" } + Redirect { to: "/" } + }) + } + + /// Renders the app and returns the rendered Element. + pub fn HomePage(cx: Scope) -> Element { + let poem_database = &cx.props.poem_database; + let user_prefs = cx.props.user_prefs.clone(); + let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); + let page_title = "A Letter to the Void".to_string(); + cx.render(rsx!{ + div { class: "{user_theme} {user_font}", + PageBase { + Title { title: page_title, is_html: false, user_prefs: user_prefs.clone() } + RenderContent { content: helpers::get_homepage_paragraph(), user_prefs: user_prefs.clone() } + ButtonGroup { + NavigationButton { title: "See Latest Entry".to_string(), slug: poem_database.get_latest_entry("".to_string()), user_prefs: user_prefs.clone() } + NavigationButton { title: "See Oldest Entry".to_string(), slug: poem_database.get_oldest_entry("".to_string()), user_prefs: user_prefs.clone() } + NavigationButton { title: "See A Random Entry".to_string(), slug: poem_database.get_random_entry(), user_prefs: user_prefs.clone() } + NavigationButton { title: "See All Entries".to_string(), slug: "/poems".to_string(), user_prefs: user_prefs.clone() } + } + Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } + } + } + }) + } + + /// Renders the app and returns the rendered Element. + pub fn PoemListPage(cx: Scope) -> Element { + let poem_database = &cx.props.poem_database; + let user_prefs = cx.props.user_prefs.clone(); + let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); + cx.render(rsx! { + div { class: "{user_theme} {user_font}", + PageBase { + Title { title: "A Letter to the Void".to_string(), is_html: false, user_prefs: user_prefs.clone() } + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } + PoemList { poem_database: poem_database.clone(), user_prefs: user_prefs.clone() } + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } + Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } + } + } + }) + } + + pub fn PoemPage(cx: Scope) -> Element { + let poem_database = &cx.props.poem_database; + let user_prefs = cx.props.user_prefs.clone(); + let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); + #[cfg(any(target_family = "unix", target_family = "windows"))] + let slug = &cx + .props + .slug + .as_ref() + .expect("A slug was given in the pops.") + .clone(); + #[cfg(target_family = "wasm")] + let slug = String::from( + dioxus_router::use_route(cx) + .segment("slug") + .expect("No slug specified."), + ); + cx.render(rsx!{ + div { class: "{user_theme} {user_font}", + PageBase { + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } + GetPoem { slug: slug.clone(), poem_database: poem_database.clone(), user_prefs: user_prefs.clone() } + ButtonGroup { + NavigationButton { title: "Oldest".to_string(), slug: poem_database.get_oldest_entry(slug.clone()), user_prefs: user_prefs.clone() } + NavigationButton { title: "Previous".to_string(), slug: poem_database.get_previous_entry(slug.clone()), user_prefs: user_prefs.clone() } + NavigationButton { title: "Random".to_string(), slug: poem_database.get_random_entry(), user_prefs: user_prefs.clone() } + NavigationButton { title: "Next".to_string(), slug: poem_database.get_next_entry(slug.clone()), user_prefs: user_prefs.clone() } + NavigationButton { title: "Latest".to_string(), slug: poem_database.get_latest_entry(slug.clone()), user_prefs: user_prefs.clone() } + } + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } + Footer { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } + } + } + }) + } + + pub fn SettingsPage(cx: Scope) -> Element { + let user_prefs = cx.props.clone(); + let (user_theme, user_font) = user_prefs.get_pref_classes(ThemedComponent::Page); + // Get rid of this and create a general card component with children. + let (user_theme_card, user_font_card) = user_prefs.get_pref_classes(ThemedComponent::Card); + cx.render(rsx! { + div { class: "{user_theme} {user_font}", + PageBase { + Title { title: "Settings".to_string(), is_html: false, user_prefs: user_prefs.clone() } + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.clone().get_font() } + div { class: "p-4 flex flex-col space-y-4 mx-auto max-w-full justify-center", + div { class: "p-4 flex flex-col space-y-4 text-xl text-center ring-4 {user_theme_card} {user_font_card}", + p { + "Theme" + } + ButtonGroup { + NavigationButton { title: "Light".to_string(), slug: "/settings/?theme=light".to_string(), user_prefs: user_prefs.clone() } + NavigationButton { title: "Dark".to_string(), slug: "/settings/?theme=dark".to_string(), user_prefs: user_prefs.clone() } + NavigationButton { title: "Auto".to_string(), slug: "/settings/?theme=auto".to_string(), user_prefs: user_prefs.clone() } + } + } + div { class: "p-4 flex flex-col space-y-4 text-xl text-center ring-4 {user_theme_card} {user_font_card}", + p { + "Font" + } + ButtonGroup { + NavigationButton { title: "Nerd Font".to_string(), slug: "/settings/?font=nerd".to_string(), user_prefs: user_prefs.clone() override_font: "font-nerd".to_string() } + NavigationButton { title: "Open Dyslexic".to_string(), slug: "/settings/?font=open".to_string(), user_prefs: user_prefs.clone() override_font: "font-open".to_string() } + } + } + } + BackToHomePage { theme: user_prefs.clone().get_theme(), font: user_prefs.get_font() } + } + } + }) + } +} diff --git a/void-fe/src/main.rs b/void-fe/src/main.rs new file mode 100644 index 0000000..67e5c0e --- /dev/null +++ b/void-fe/src/main.rs @@ -0,0 +1,22 @@ +#[cfg(target_family = "wasm")] +use console_error_panic_hook; + +#[cfg(target_family = "wasm")] +use void_fe::void_app; + +#[cfg(target_family = "wasm")] +use wasm_logger; + +#[cfg(any(target_family = "unix", target_family = "windows"))] +fn main() { + print!("You can't run this without targeting web assembly. Try running `dioxus serve`.") +} + +#[cfg(target_family = "wasm")] +fn main() { + // init debug tool for WebAssembly + wasm_logger::init(wasm_logger::Config::default()); + console_error_panic_hook::set_once(); + + dioxus_web::launch(void_app::DioxusApp); +} diff --git a/void-fe/src/utils.rs b/void-fe/src/utils.rs new file mode 100644 index 0000000..8b86361 --- /dev/null +++ b/void-fe/src/utils.rs @@ -0,0 +1,3 @@ +pub mod helpers; +pub mod prop_structs; +pub mod user_prefs; diff --git a/void-fe/src/utils/helpers.rs b/void-fe/src/utils/helpers.rs new file mode 100644 index 0000000..f852084 --- /dev/null +++ b/void-fe/src/utils/helpers.rs @@ -0,0 +1,190 @@ +use markdown::Options; +use rand::seq::SliceRandom; +use rust_embed::RustEmbed; +use std::collections::{HashMap, VecDeque}; + +use super::prop_structs::{PoemDatabase, PoemStruct}; +#[derive(RustEmbed)] +#[folder = "data/other"] +struct OtherData; + +#[derive(RustEmbed)] +#[folder = "data/poems"] +pub struct Poems; + +impl PoemDatabase { + pub fn new() -> PoemDatabase { + PoemDatabase { + poem_list: Vec::<(String, String)>::new(), + poem_hashmap: HashMap::::new(), + } + } + + // There's no need to actually make a database yet, but maybe in the future... + #[cfg(any(target_family = "unix", target_family = "windows"))] + pub async fn build_poem_database(&mut self) { + for p in Poems::iter() { + let filename = p.to_string(); + let poem_content = Poems::get(&filename).expect("Found poem {filename:?}"); + let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref()) + .expect("Poem is valid UT8.") + .lines(); + let poem_title = poem_to_str.next().expect("No title specified."); + let poem_content = poem_to_str.into_iter().collect::>().join("\n"); + let poem_title_to_html_string = + markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap(); + let poem_content_to_html_string = + markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap(); + let mut split_filename = filename.trim_end_matches(".md").split("_"); + let creation_date = split_filename.next().expect("Obtained creation date"); + let slug = split_filename.next().expect("Obtained slug"); + self.poem_list + .push((creation_date.to_string(), slug.to_string())); + let poem_struct = PoemStruct { + title: poem_title_to_html_string.to_string(), + content: poem_content_to_html_string, + creation_date: creation_date.to_string(), + }; + self.poem_hashmap.insert(slug.to_string(), poem_struct); + } + self.poem_list.sort_by_key(|k| k.0.clone()) + } + + #[cfg(any(target_family = "wasm"))] + pub fn build_poem_database(&mut self) { + for p in Poems::iter() { + let filename = p.to_string(); + let poem_content = Poems::get(&filename).expect("Found poem {filename:?}"); + let mut poem_to_str = std::str::from_utf8(poem_content.data.as_ref()) + .expect("Poem is valid UT8.") + .lines(); + let poem_title = poem_to_str.next().expect("No title specified."); + let poem_content = poem_to_str.into_iter().collect::>().join("\n"); + let poem_title_to_html_string = + markdown::to_html_with_options(poem_title, &Options::gfm()).unwrap(); + let poem_content_to_html_string = + markdown::to_html_with_options(poem_content.as_str(), &Options::gfm()).unwrap(); + let mut split_filename = filename.trim_end_matches(".md").split("_"); + let creation_date = split_filename.next().expect("Obtained creation date"); + let slug = split_filename.next().expect("Obtained slug"); + self.poem_list + .push((creation_date.to_string(), slug.to_string())); + let poem_struct = PoemStruct { + title: poem_title_to_html_string.to_string(), + content: poem_content_to_html_string, + creation_date: creation_date.to_string(), + }; + self.poem_hashmap.insert(slug.to_string(), poem_struct); + } + self.poem_list.sort_by_key(|k| k.0.clone()) + } + + pub fn get_poem(&self, slug: String) -> PoemStruct { + self.poem_hashmap + .get(slug.as_str()) + .expect("Grabbed poem from database") + .clone() + } + + pub fn get_poem_list(&self) -> Vec<(String, String)> { + self.poem_list + .iter() + .map(|s| { + ( + s.1.clone(), + self.poem_hashmap + .get(&s.1) + .expect("Got poemstruct from database") + .title + .clone(), + ) + }) + .collect::>() + .clone() + } + + pub fn get_oldest_entry(&self, current: String) -> String { + let mut poem_list = VecDeque::from_iter(self.poem_list.iter()); + let oldest = poem_list + .pop_front() + .expect("There is an entry in this list of poems.") + .1 + .clone(); + if current == oldest { + return format!("/poems/{current}#"); + } + format!("/poems/{oldest}") + } + + pub fn get_latest_entry(&self, current: String) -> String { + let mut poem_list = self.poem_list.clone(); + let latest = poem_list + .pop() + .expect("There is an entry in this list of poems.") + .1 + .clone(); + if current == latest { + return format!("/poems/{current}#"); + } + format!("/poems/{latest}") + } + + pub fn get_previous_entry(&self, current: String) -> String { + let poem_list = self.poem_list.clone(); + match poem_list.iter().enumerate().find_map(|(index, p)| { + if p.1 == current { + if index != 0 { + Some(poem_list[index - 1].1.clone()) + } else { + None + } + } else { + None + } + }) { + Some(entry) => format!("/poems/{entry}"), + None => format!("/poems/{current}"), + } + } + + pub fn get_next_entry(&self, current: String) -> String { + let poem_list = self.poem_list.clone(); + match poem_list.iter().enumerate().find_map(|(index, p)| { + if p.1 == current { + if index != poem_list.len() - 1 { + Some(poem_list[index + 1].1.clone()) + } else { + None + } + } else { + None + } + }) { + Some(entry) => format!("/poems/{entry}"), + None => format!("/poems/{current}"), + } + } + // #[cfg(not(target_family = "wasm"))] + pub fn get_random_entry(&self) -> String { + let poem_list = self.poem_list.clone(); + let mut rng = rand::thread_rng(); + let random_entry = poem_list + .choose(&mut rng) + .expect("Got a valid entry") + .1 + .clone(); + // let random_entry = "introductions"; + format!("/poems/{random_entry}") + } +} + +pub fn get_homepage_paragraph() -> String { + let homepage_paragraph_content = + OtherData::get("homepage.md").expect("Found homepage paragraph."); + let homepage_paragraph_to_string = + std::str::from_utf8(homepage_paragraph_content.data.as_ref()) + .expect("Homepage file is valid UTF-8"); + let test = + markdown::to_html_with_options(homepage_paragraph_to_string, &Options::gfm()).unwrap(); + test +} diff --git a/void-fe/src/utils/prop_structs.rs b/void-fe/src/utils/prop_structs.rs new file mode 100644 index 0000000..9a11566 --- /dev/null +++ b/void-fe/src/utils/prop_structs.rs @@ -0,0 +1,66 @@ +use std::collections::HashMap; +use crate::void_app::{Element, Props}; +use super::user_prefs::UserPrefs; + +#[derive(PartialEq, Props)] +pub struct PoemRequest { + pub slug: String, + pub user_prefs: UserPrefs, +} + +#[derive(PartialEq, Props)] +pub struct TitleProps { + pub title: String, + pub is_html: bool, + pub user_prefs: UserPrefs, +} + +#[derive(PartialEq, Props)] +pub struct ContentProps { + pub content: String, + pub user_prefs: UserPrefs, +} + +#[derive(PartialEq, Props)] +pub struct ButtonProps { + pub title: String, + pub slug: String, + pub user_prefs: UserPrefs, + pub override_font: Option, +} + +#[derive(PartialEq, Props)] +pub struct VoidProps { + pub slug: Option, + pub poem_database: PoemDatabase, + pub user_prefs: UserPrefs, +} + +#[derive(PartialEq, Props, Clone, Debug)] +pub struct PoemDatabase { + pub poem_list: Vec<(String, String)>, + pub poem_hashmap: HashMap, +} + +#[derive(PartialEq, Clone, Debug)] +pub struct PoemStruct { + pub title: String, + pub content: String, + pub creation_date: String, +} + +// These next three should all just be one prop. +#[derive(Props)] +pub struct PoemChildren<'a> { + pub children: Element<'a>, +} + +#[derive(Props)] +pub struct PageChildren<'a> { + pub children: Element<'a>, +} + +#[derive(Props)] +pub struct ContentChildren<'a> { + pub children: Element<'a>, +} diff --git a/void-fe/src/utils/user_prefs.rs b/void-fe/src/utils/user_prefs.rs new file mode 100644 index 0000000..c7730a0 --- /dev/null +++ b/void-fe/src/utils/user_prefs.rs @@ -0,0 +1,154 @@ +use dioxus::prelude::*; + +#[derive(PartialEq, Props, Clone)] +pub struct UserPrefs { + theme: ThemePref, + font: FontPref, +} + +#[derive(PartialEq, Clone)] +pub enum ThemePref { + Light, + Dark, + Auto, +} + +#[derive(PartialEq, Clone)] +pub enum FontPref { + NerdFont, + OpenDyslexic, +} + +pub enum ThemedComponent { + Page, + Card, + Button, +} + +impl UserPrefs { + // TailwindCSS has a difficult time determining which classes we'll need for our site, + // the easiest way to fix this is to simply list all of them our in commented out class + // attributes, so all of these we *will* use, and TailwindCSS will know to compile them. + // class: "bg-alice-werefox-grey-light dark:bg-alice-werefox-grey" + // class: "bg-alice-werefox-grey" + // class: "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark" + // class: "dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light" + // class: "bg-alice-werefox-grey-dark ring-alice-werefox-red text-alice-werefox-grey-light" + // class: "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark" + // class: "hover:text-alice-werefox-blue-dark" + // class: "hover:ring-alice-werefox-blue dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red" + // class: "bg-alice-werefox-grey-dark ring-alice-werefox-red" + // class: "dark:text-alice-werefox-grey-light dark:hover:text-alice-werefox-blue-light dark:hover:ring-alice-werefox-blue" + // class: "text-alice-werefox-grey-light hover:text-alice-werefox-blue-light hover:ring-alice-werefox-blue" + + const PAGE_CLASSES: &str = "bg-alice-werefox-grey-light dark:bg-alice-werefox-grey"; + const CARD_CLASSES: &str = "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light"; + const BUTTON_CLASSES: &str = "bg-alice-werefox-grey-lightest ring-alice-werefox-red-dark text-alice-werefox-grey-dark hover:text-alice-werefox-blue-dark hover:ring-alice-werefox-blue dark:bg-alice-werefox-grey-dark dark:ring-alice-werefox-red dark:text-alice-werefox-grey-light dark:hover:text-alice-werefox-blue-light dark:hover:ring-alice-werefox-blue"; + + pub fn new(theme: ThemePref, font: FontPref) -> UserPrefs { + UserPrefs { theme, font } + } + + // I'm really about to write a ceil() function because I refuse to force devs to use Nightly + fn ceil(n: usize) -> usize { + if n.rem_euclid(2) == 0 { + n / 2 + } else { + n - 1 / 2 + } + } + + pub fn get_pref_classes(&self, component: ThemedComponent) -> (String, String) { + let theme = self.get_theme_classes(component).clone(); + let font = self.get_font_class().clone(); + (theme, font) + } + + pub fn get_theme_classes(&self, component: ThemedComponent) -> String { + match &self.theme { + ThemePref::Light => match component { + ThemedComponent::Page => Self::PAGE_CLASSES + .split_at(Self::ceil(Self::PAGE_CLASSES.len() / 2)) + .0 + .to_string(), + ThemedComponent::Card => Self::CARD_CLASSES + .split_at(Self::ceil(Self::CARD_CLASSES.len() / 2)) + .0 + .to_string(), + ThemedComponent::Button => Self::BUTTON_CLASSES + .split_at(Self::ceil(Self::BUTTON_CLASSES.len() / 2)) + .0 + .to_string(), + }, + ThemePref::Dark => match component { + ThemedComponent::Page => { + let remove_dark_tags = Self::PAGE_CLASSES.split("dark:").collect::(); + let split_whitespace = remove_dark_tags.as_str().split(" "); + let split_whitespace_length = split_whitespace.clone().count(); + split_whitespace + .skip(Self::ceil(split_whitespace_length / 2)) + .map(|e| format!("{e} ")) + .collect::() + } + ThemedComponent::Card => { + let remove_dark_tags = Self::CARD_CLASSES.split("dark:").collect::(); + let split_whitespace = remove_dark_tags.as_str().split(" "); + let split_whitespace_length = split_whitespace.clone().count(); + split_whitespace + .skip(Self::ceil(split_whitespace_length / 2)) + .map(|e| format!("{e} ")) + .collect::() + } + ThemedComponent::Button => { + let remove_dark_tags = Self::BUTTON_CLASSES.split("dark:").collect::(); + let split_whitespace = remove_dark_tags.as_str().split(" "); + let split_whitespace_length = split_whitespace.clone().count(); + split_whitespace + .skip(Self::ceil(split_whitespace_length / 2)) + .map(|e| format!("{e} ")) + .collect::() + } + }, + ThemePref::Auto => match component { + ThemedComponent::Page => Self::PAGE_CLASSES.to_string(), + ThemedComponent::Card => Self::CARD_CLASSES.to_string(), + ThemedComponent::Button => Self::BUTTON_CLASSES.to_string(), + }, + } + } + + pub fn get_font_class(&self) -> String { + match &self.font { + FontPref::OpenDyslexic => "font-open".to_string(), + FontPref::NerdFont => "font-nerd".to_string(), + } + } + + pub fn set_prefs(mut self, prefs: UserPrefs) { + self.theme = prefs.theme; + self.font = prefs.font; + } + + pub fn set_theme(mut self, theme: ThemePref) { + self.theme = theme; + } + + pub fn set_font(mut self, font: FontPref) { + self.font = font; + } + + pub fn get_prefs(self) -> (ThemePref, FontPref) { + let prefs = self.clone(); + (prefs.theme, prefs.font) + } + + pub fn get_theme(self) -> ThemePref { + let prefs = self.clone(); + prefs.theme.clone() + } + + pub fn get_font(self) -> FontPref { + let prefs = self.clone(); + prefs.font.clone() + } +} diff --git a/void-fe/tailwind.config.js b/void-fe/tailwind.config.js new file mode 100644 index 0000000..3e2bfb8 --- /dev/null +++ b/void-fe/tailwind.config.js @@ -0,0 +1,117 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + // Or if using `src` directory: + "./src/**/*.{rs,html,js,ts,jsx,tsx,ttf}", + "./target/**/*.{rs,html,js,ts,jsx,tsx,ttf}", + ], + theme: { + container: { + center: true, + padding: { + DEFAULT: "1rem", + xl: "0rem", + } + }, + extend: { + fontFamily: { + nerd: ["DejaVuSansMono"], + open: ["OpenDyslexic"], + }, + colors: { + "ada-werefox-cyan": { + light: "#AAFFFF", + DEFAULT: "#50FFFF", + dark: "#008888", + }, + "ada-werefox-grey": { + lightest: "#EEE", + lighter: "#DBDBDB", + light: "#CCC", + DEFAULT: "#424242", + dark: "#242424", + darker: "#121212", + }, + "skye-werefox-blue": { + light: "#94C2FF", + DEFAULT: "#75B1FF", + dark: "#0052B8", + darker: "#00377A", + darkest: "#00326B", + }, + "skye-werefox-pink": { + DEFAULT: "#FF84CA", + dark: "#9E0054", + darker: "#8A0040", + darkest: "#75003F", + }, + "skye-werefox-grey": { + lightest: "#EEE", + lighter: "#DBDBDB", + light: "#CCC", + DEFAULT: "#424242", + dark: "#242424", + darker: "#121212", + }, + "alice-werefox-grey": { + lightest: "#EEE", + lighter: "#DBDBDB", + light: "#CCC", + DEFAULT: "#242424", + dark: "#121212", + darker: "#000", + }, + "alice-werefox-red": { + light: "#E08587", + DEFAULT: "#c93439", + dark: "#800008", + darker: "#550006", + darkest: "#7A0000", + }, + "alice-werefox-blue": { + light: "#9197F3", + DEFAULT: "#1b29e0", + dark: "#3300FF", + darker: "#2C00DB", + darkest: "#2700C2", + }, + }, + keyframes: { + growshrink: { + "0%": { + transform: "scale(0.5)", + }, + "40%": { + transform: "scale(1.2)", + }, + "60%": { + transform: "scale(1.2)", + }, + "100% ": { + transform: "scale(0.5)", + }, + }, + wiggle: { + "0%, 100%": { transform: "rotate(-1deg)" }, + "50%": { transform: "rotate(1deg)" }, + }, + jiggle: { + "0%, 100%": { transform: "rotate(0deg)" }, + "25%": { transform: "rotate(-10deg)" }, + "75%": { transform: "rotate(10deg)" }, + }, + yip: { + "0%, 100%": { transform: "scale(1, 1)" }, + "50%": { transform: "scale(1.01, 1.01)" }, + }, + }, + animation: { + wiggle: "wiggle 7s ease-in-out infinite", + jiggle: "jiggle 5s cubic-bezier(0.75,0.25,0.25,0.75) infinite", + yip: "yip 0.1s ease-in-out", + growshrink: "growshrink 2s cubic-bezier(1, 0, 0, 1) infinite", + }, + }, + }, + plugins: [], +};