diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8b88b46 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6b6b136 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..5c20283 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 621aeb9..bde5f32 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Or search for Cozy Nest in the extension tab # Contribution As you may have notice, most of the JS source here are minified. I'm using Vite to bundle the extension. -The source code is available [HERE](https://github.com/Nevysha/cozy-nest-client) +The source code is available in the cozy-nest-client folder. [README](https://github.com/Nevysha/Cozy-Nest/blob/main/cozy-nest-client/README.md). My roadmap is available here : [Notion Roadmap](https://exclusive-drink-8c5.notion.site/Nevysha-Cozy-Nest-f95f333908f0406f990ed603b424780c). Please note that this is the draft I use to keep track of suggestions, issue, or idea that I get. I'm not sure I'll implement everything. diff --git a/cozy-nest-client/.env b/cozy-nest-client/.env new file mode 100644 index 0000000..da1e49f --- /dev/null +++ b/cozy-nest-client/.env @@ -0,0 +1 @@ +VITE_CONTEXT=DEV \ No newline at end of file diff --git a/cozy-nest-client/.env.production b/cozy-nest-client/.env.production new file mode 100644 index 0000000..ec45102 --- /dev/null +++ b/cozy-nest-client/.env.production @@ -0,0 +1 @@ +VITE_CONTEXT=PROD \ No newline at end of file diff --git a/cozy-nest-client/.gitignore b/cozy-nest-client/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/cozy-nest-client/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/cozy-nest-client/LICENSE b/cozy-nest-client/LICENSE new file mode 100644 index 0000000..211d32e --- /dev/null +++ b/cozy-nest-client/LICENSE @@ -0,0 +1,663 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (c) 2023 AUTOMATIC1111 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/cozy-nest-client/README.md b/cozy-nest-client/README.md new file mode 100644 index 0000000..0346fba --- /dev/null +++ b/cozy-nest-client/README.md @@ -0,0 +1,34 @@ +# Cozy Nest Client + +**![#f03c15](https://placehold.co/15x15/f03c15/f03c15.png) If you are looking for the Automatic1111's webui extension, please look [HERE](https://github.com/Nevysha/Cozy-Nest). This repo host the source code of Cozy Nest client.** + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G2L55CD) + +![](https://nevysha.art/wp-content/uploads/2023/01/nevy-icon-1-256-round.png) + +## Installation + +```bash +git clone https://github.com/Nevysha/Cozy-Nest.git +cd Cozy-Nest/cozy-nest-client +npm install +``` + +## Usage + +You need to have Cozy-Nest extension installed on a1111, and a1111 running. + +```bash +# start a1111 webui server +cd Cozy-Nest/cozy-nest-client +npm run dev +# access client at http://localhost: +``` + +## Build + +```bash +cd Cozy-Nest/cozy-nest-client +# check output folder in vite.config.js. It is hard coded atm. +npm run build +``` \ No newline at end of file diff --git a/cozy-nest-client/counter.js b/cozy-nest-client/counter.js new file mode 100644 index 0000000..881e2d7 --- /dev/null +++ b/cozy-nest-client/counter.js @@ -0,0 +1,9 @@ +export function setupCounter(element) { + let counter = 0 + const setCounter = (count) => { + counter = count + element.innerHTML = `count is ${counter}` + } + element.addEventListener('click', () => setCounter(counter + 1)) + setCounter(0) +} diff --git a/cozy-nest-client/index.html b/cozy-nest-client/index.html new file mode 100644 index 0000000..f75ee97 --- /dev/null +++ b/cozy-nest-client/index.html @@ -0,0 +1,12 @@ + + + + + + Vite App + + +
+ + + diff --git a/cozy-nest-client/main.js b/cozy-nest-client/main.js new file mode 100644 index 0000000..5148489 --- /dev/null +++ b/cozy-nest-client/main.js @@ -0,0 +1,60 @@ +import 'animate.css'; +import '@fontsource-variable/caveat'; + +import sheet from './main/cozy-nest-style.css?inline' assert { type: 'css' }; +const styleSheet = new CSSStyleSheet(); +styleSheet.replaceSync(sheet); +document.adoptedStyleSheets = [styleSheet]; + +import { + dummyLoraCard, dummyControlNetBloc, dummySubdirs +} from './main/cozy-utils.js'; +window.CozyTools = { + dummyLoraCard, + dummyControlNetBloc, + dummySubdirs +} + +import cozyNestLoader from './main/nevysha-cozy-nest.js' +import SimpleTimer from "./main/SimpleTimer.js"; +import {COZY_NEST_GRADIO_LOAD_DURATION} from "./main/Constants.js"; +import {CozyLogger} from "./main/CozyLogger.js"; + +(async () => { + //check if the param CozyNest=No is present in the url + const urlParams = new URLSearchParams(window.location.search); + const cozyNestParam = urlParams.get('CozyNest'); + if (cozyNestParam === "No") { + CozyLogger.log("Cozy Nest disabled by url param") + //remove the css with Cozy-Nest in the url + document.querySelectorAll('link').forEach(link => { + if (link.href.includes("Cozy-Nest")) link.remove() + }) + return + } + + SimpleTimer.time(COZY_NEST_GRADIO_LOAD_DURATION); + + // Cozy-Nest-Image-Browser link + const cozyNestImageBrowserLink = document.createElement('link'); + cozyNestImageBrowserLink.rel = 'stylesheet'; + cozyNestImageBrowserLink.type = 'text/css'; + cozyNestImageBrowserLink.href = `file=extensions/Cozy-Nest/cozy-nest-image-browser/assets/index.css?t=${Date.now()}`; + + // Append the link element to the document head + document.head.appendChild(cozyNestImageBrowserLink); + + if (import.meta.env.VITE_CONTEXT === 'DEV') { + CozyLogger.log('CozyNest: DEV MODE'); + document.addEventListener("DOMContentLoaded", function() { + cozyNestLoader(); + }) + } + else { + CozyLogger.init(false); + } +})(); + + + + diff --git a/cozy-nest-client/main/Constants.js b/cozy-nest-client/main/Constants.js new file mode 100644 index 0000000..813430b --- /dev/null +++ b/cozy-nest-client/main/Constants.js @@ -0,0 +1,4 @@ +export const COZY_NEST_DOM_TWEAK_LOAD_DURATION = "CozyNest:tweakLoadDuration"; +export const COZY_NEST_GRADIO_LOAD_DURATION = "CozyNest:gradioLoadDuration"; +export const SETTINGS_MIN_WIDTH = 420; +export const RESULT_MIN_WIDTH = 320; \ No newline at end of file diff --git a/cozy-nest-client/main/CozyLogger.js b/cozy-nest-client/main/CozyLogger.js new file mode 100644 index 0000000..9628a63 --- /dev/null +++ b/cozy-nest-client/main/CozyLogger.js @@ -0,0 +1,39 @@ +import cozyNestLoader from "./nevysha-cozy-nest.js"; + +export class CozyLogger { + + static _instance = null; + + static init(enabled) { + if (!CozyLogger._instance) { + CozyLogger._instance = new CozyLogger(enabled); + } + return CozyLogger._instance; + } + + static enable() { + CozyLogger._instance.enabled = true; + } + static disable() { + CozyLogger._instance.enabled = false; + } + + static log(...args) { + if (CozyLogger._instance.enabled) { + console.log(...args); + } + } + + constructor(enabled) { + this.enabled = enabled; + } +} + +if (import.meta.env.VITE_CONTEXT === 'DEV') { + CozyLogger.init(true); +} +else { + CozyLogger.init(false); +} + +window.CozyLogger = CozyLogger; \ No newline at end of file diff --git a/cozy-nest-client/main/Loading.js b/cozy-nest-client/main/Loading.js new file mode 100644 index 0000000..97f9d9c --- /dev/null +++ b/cozy-nest-client/main/Loading.js @@ -0,0 +1,106 @@ +import {getTheme} from "./cozy-utils.js"; +import SimpleTimer from "./SimpleTimer.js"; +import {COZY_NEST_GRADIO_LOAD_DURATION} from "./Constants.js"; +import {waves, loading_roll} from "./svg.js"; +import {applyAccentColor, applyBgGradiantColor, applyWavesColor} from "./tweaks/various-tweaks.js"; + +export default class Loading { + + static _instance = null; + + static start() { + if (!Loading._instance) { + Loading._instance = new Loading(); + } + Loading._instance.pushLoading(); + Loading._instance.setupObserver(); + } + static stop() { + if (Loading._instance) { + Loading._instance.observer.disconnect(); + } + //wait for one second to let gradio finish request... + setTimeout(() => document.querySelector("#nevysha-loading-wrap").remove(), 2000); + } + + constructor() { + this.observer = null; + } + + setupObserver() { + // Create a new observer instance + let step = 0; + //get last loaded time. If null or zero, set it to 15000ms + //since last update, I have to click on extra network button to load the HTML. That's why I add 2000ms (: + //the clean way would be to set a small timeout before removing the mutation observer but, eh, I'm lazy atm + const lastLoadingTimeSaved = SimpleTimer.last(COZY_NEST_GRADIO_LOAD_DURATION) + 2000 + const lastLoadingTime = lastLoadingTimeSaved ? lastLoadingTimeSaved : 15000 + //observer to update loading percentage + this.observer = new MutationObserver((mutations) => { + if (mutations[0].target.id !== 'loading_step_estimator') { + + //current elapsed loading time + const currentLoadingTime = SimpleTimer.get(COZY_NEST_GRADIO_LOAD_DURATION) + + if (currentLoadingTime < lastLoadingTime + 1000) { + //estimate the percentage of loading. Never go above 99% + const percentage = Math.min(Math.round((currentLoadingTime / lastLoadingTime) * 100), 99) + + document.querySelector("#loading_step_estimator").innerText = `${percentage}%` + } + else { + document.querySelector("#loading_step_estimator").innerText = `Woops, it's taking longer than expected...` + } + + this.pushLoading(); + } + }); + + // Configure the observer to watch for changes to the body element and its descendants + const config = { attributes: true, childList: true, subtree: true }; + this.observer.observe(document.body, config); + } + + /** + * add a full screen div hiding while the app is loading + */ + pushLoading() { + if (document.querySelector('#nevysha-loading')) return + + const maybeLightThemeClass = getTheme() === "light" ? "nevysha-light" : "" + + const loading = + `
+
+
+
+ Cozy Nest +
+ ${loading_roll} +
+ 1 +
+
+ Loading The Magic +
+
+ (and gradio) +
+
+ ${waves} + +
+
` + document.querySelector('body').insertAdjacentHTML('beforeend', loading); + + //get config from local storage COZY_NEST_CONFIG + let config = JSON.parse(localStorage.getItem("COZY_NEST_CONFIG")) + //merge with dummy config to avoid warning + config = {...{waves_color: "#ffffff", bg_gradiant_color: "#ffffff", accent_color: "#ffffff"}, ...config} + + applyWavesColor(config.waves_color) + applyBgGradiantColor(config.bg_gradiant_color); + applyAccentColor(config.accent_color, config.accent_color); + } + +} \ No newline at end of file diff --git a/cozy-nest-client/main/SimpleTimer.js b/cozy-nest-client/main/SimpleTimer.js new file mode 100644 index 0000000..89f0368 --- /dev/null +++ b/cozy-nest-client/main/SimpleTimer.js @@ -0,0 +1,46 @@ +export default class SimpleTimer { + + static timers = {}; + + // static method to create a new instance of SimpleTimer + static time(timerName) { + SimpleTimer.timers[timerName] = new SimpleTimer(timerName) + return SimpleTimer.timers[timerName]; + } + + static end(timerName) { + return SimpleTimer.timers[timerName].end(); + } + + static last(timerName) { + return localStorage.getItem(timerName) && Number(localStorage.getItem(timerName)); + } + + static get(timerName) { + return SimpleTimer.timers[timerName].get(); + } + + // constructor + constructor(timerName) { + this.timerName = timerName; + this.startTime = new Date(); + } + + // method to get the elapsed time + get() { + const endTime = new Date(); + //in ms + return endTime - this.startTime; + } + + // method to end the timer + end() { + const endTime = new Date(); + const timeDiff = endTime - this.startTime; //in ms + + //save the time in the local storage + localStorage.setItem(this.timerName, `${timeDiff}`); + + return timeDiff; + } +} \ No newline at end of file diff --git a/cozy-nest-client/main/cozy-nest-style.css b/cozy-nest-client/main/cozy-nest-style.css new file mode 100644 index 0000000..6c63249 --- /dev/null +++ b/cozy-nest-client/main/cozy-nest-style.css @@ -0,0 +1,1749 @@ +:root { + /*override by code when applying settings*/ + --nevysha-margin-left: 175px; + --ae-primary-color: rgb(92, 175, 214); + --nevysha-gradiant-1: rgb(101,0,94); + --nevysha-text-md: 12px; + --nevysha-color-from-luminance: black; + --extra-network-card-width: 13em; + --extra-network-card-height: 8em; + + --menu-top-height: 1px; + --main-container-height: 1px; +} +:root, .dark { + /*--nevysha-gradiant-1: #8777a1;*/ + /*--nevysha-gradiant-2: #00adb5;*/ + /*--nevysha-gradiant-3: #f98f69;*/ + /*--nevysha-gradiant-4: #ea638c;*/ + --nevysha-gradiant-2: rgb(28 28 28); + + --body-background-fill: rgba(255, 255, 255, 0) !important; + + /*primary button (ie "Generate")*/ + --button-primary-background-fill: var(--primary-500); + /*--input-background-fill: #ffffffc4;*/ + /*--input-background-fill-focus: var(--secondary-500);*/ + /*--input-background-fill-hover: var(--input-background-fill);*/ + + /*--secondary-tabs-background-color: #ffffff75;*/ + --tab-nav-background-color: #262626ad; + --tab-nav-background-color-selected: var(--input-background-fill); + /*--footer-text-color: #262626;*/ + /*--btn-background-color: #549cdb;*/ + + /*--block-title-text-color: #0a0a0a;*/ + /*--neutral-800: #0a0a0a;*/ + /*--body-text-color: #0a0a0a;*/ + /*--border-color-primary: #5050505e;*/ + /*--panel-background-fill: #11182752;*/ + + /*--button-primary-border-color: var(--primary-500);*/ + /*--button-primary-text-color: white;*/ + /*--secondary-text-color: #2c2c2c;*/ + /*--input-border-color: #a1a1a1;*/ + + --vertical-line-bg-color: #ffffff59; + + --checkbox-background-color: var(--nevysha-dark); + + --button-border-width: 0px; + --tabmenu-button-color: #ffffff; + + --nevysha-dark: #1c1c1c; + --nevysha-light-dark: #292a2e; + --nevysha-white: #6b7280; + --nevysha-input-border-color: hsl(214deg 5% 30%); + + --nevysha-color2: #f0a6caff; + --nevysha-color3: #efc3e6ff; + --nevysha-color4: #f0e6efff; + + --main-tabs-background-color: #14141485; + --background-fill-primary: var(--nevysha-light-dark); + + --ae-slider-bg-overlay: repeating-linear-gradient( 90deg, transparent, transparent max(3px, calc(0.671141% - 2px)), var(--ae-input-border-color) max(3px, calc(0.671141% - 2px)), var(--ae-input-border-color) max(4px, calc(0.671141% + 0px)) ); + --ae-subgroup-input-bg-color: hsl(225deg 6% 13%); + + --ae-input-border-color: hsl(214deg 5% 30%); + --ae-panel-border-radius: 0px; + --ae-input-bg-color: hsl(225deg 6% 13%); + --ae-input-color: hsl(210deg 4% 80%); + + --primary-50: var(--nevysha-color4); + --primary-100: var(--nevysha-color4); + --primary-200: var(--nevysha-color3); + --primary-300: var(--nevysha-color3); + --primary-400: var(--nevysha-light-dark); + --primary-500: var(--nevysha-light-dark); + --primary-600: var(--nevysha-dark); + --primary-700: var(--nevysha-dark); + --primary-800: var(--nevysha-dark); + --primary-900: var(--nevysha-dark); + --primary-950: var(--nevysha-dark); + + --secondary-50: var(--nevysha-color4); + --secondary-100: var(--nevysha-color4); + --secondary-200: var(--nevysha-color3); + --secondary-300: var(--nevysha-color3); + --secondary-400: var(--nevysha-light-dark); + --secondary-500: var(--nevysha-light-dark); + --secondary-600: var(--nevysha-dark); + --secondary-700: var(--nevysha-dark); + --secondary-800: var(--nevysha-dark); + --secondary-900: var(--nevysha-dark); + --secondary-950: var(--nevysha-dark); + + --neutral-50: #f9fafb; + --neutral-100: #f3f4f6; + --neutral-200: #e5e7eb; + --neutral-300: #d1d5db; + --neutral-400: #9ca3af; + --neutral-500: #6b7280; + --neutral-600: var(--nevysha-light-dark); + --neutral-700: var(--nevysha-light-dark); + --neutral-800: var(--nevysha-light-dark); + --neutral-900: var(--nevysha-light-dark); + --neutral-950: var(--nevysha-light-dark); + + --slider-color: var(--nevysha-dark); + --button-secondary-background-fill: var(--nevysha-dark); + --button-secondary-background-fill-hover: var(--nevysha-dark); + --checkbox-border-color: var(--nevysha-white); + --checkbox-border-color-hover: var(--ae-primary-color); + --color-accent: var(--ae-primary-color); + --link-text-color: var(--nevysha-white); + + + /*default dark*/ + --body-text-color: var(--neutral-100); + --color-accent-soft: var(--neutral-700); + --background-fill-secondary: var(--neutral-900); + --border-color-accent: var(--neutral-600); + --border-color-primary: var(--neutral-700); + --link-text-color-active: var(--secondary-500); + --link-text-color-hover: var(--ae-primary-color); + --link-text-color-visited: var(--secondary-600); + --body-text-color-subdued: var(--neutral-400); + --shadow-drop: rgba(0,0,0,0.05) 0px 1px 2px 0px; + --shadow-drop-lg: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --shadow-inset: rgba(0,0,0,0.05) 0px 2px 4px 0px inset; + --block-background-fill: var(--neutral-800); + --block-label-border-color: var(--nevysha-input-border-color); + --block-label-text-color: var(--neutral-200); + --block-title-text-color: var(--neutral-200); + --checkbox-background-color-selected: var(--secondary-600); + --checkbox-border-color-focus: var(--secondary-500); + --checkbox-border-color-selected: var(--checkbox-border-color); + --checkbox-label-background-fill: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + --checkbox-label-background-fill-hover: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + --error-background-fill: var(--background-fill-primary); + --error-text-color: #ef4444; + --input-background-fill: var(--nevysha-dark); + --input-background-fill-focus: var(--secondary-600); + --input-background-fill-hover: var(--input-background-fill); + --input-border-color-focus: var(--neutral-700); + --input-placeholder-color: var(--neutral-500); + --input-shadow-focus: 0 0 0 var(--shadow-spread) var(--neutral-700), var(--shadow-inset); + --stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-600)); + --table-border-color: var(--neutral-700); + --table-even-background-fill: var(--neutral-950); + --table-odd-background-fill: var(--neutral-900); + --button-cancel-background-fill: linear-gradient(to bottom right, #dc2626, #b91c1c); + --button-cancel-background-fill-hover: linear-gradient(to bottom right, #dc2626, #dc2626); + --button-cancel-border-color: #dc2626; + --button-cancel-border-color-hover: var(--button-cancel-border-color); + --button-cancel-text-color: white; + --button-cancel-text-color-hover: var(--button-cancel-text-color); + --button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-500), var(--primary-500)); + --button-primary-border-color: var(--primary-500); + --button-primary-text-color: white; + --button-primary-text-color-hover: var(--button-primary-text-color); + --button-secondary-border-color: var(--neutral-600); + --button-secondary-text-color: white; + --button-secondary-text-color-hover: var(--button-secondary-text-color); + + + --shadow-spread: 1px; + --block-border-color: var(--border-color-primary); + --block_border_width: None; + --block-info-text-color: var(--body-text-color-subdued); + --block-label-background-fill: var(--background-fill-secondary); + + --block_label_border_width: None; + + --block_shadow: None; + --block_title_background_fill: None; + --block_title_border_color: None; + --block_title_border_width: None; + + --panel-background-fill: var(--background-fill-secondary); + --panel-border-color: var(--border-color-primary); + --panel_border_width: None; + --checkbox-background-color-focus: var(--checkbox-background-color); + --checkbox-background-color-hover: var(--checkbox-background-color); + + --checkbox-border-width: var(--input-border-width); + --checkbox-label-background-fill-selected: var(--checkbox-label-background-fill); + --checkbox-label-border-color: var(--border-color-primary); + --checkbox-label-border-color-hover: var(--checkbox-label-border-color); + --checkbox-label-border-width: var(--input-border-width); + --checkbox-label-text-color: var(--body-text-color); + --checkbox-label-text-color-selected: var(--checkbox-label-text-color); + + --error-border-color: var(--border-color-primary); + --error_border_width: None; + + --input-border-color: var(--border-color-primary); + --input-border-color-hover: var(--input-border-color); + --input_border_width: None; + --input_shadow: None; + --loader_color: None; + --slider_color: None; + --table-row-focus: var(--color-accent-soft); + --button-primary-border-color-hover: var(--button-primary-border-color); + --button-secondary-border-color-hover: var(--button-secondary-border-color); + --spacing-xxs: 1px; + --spacing-xs: 2px; + --spacing-sm: 3px; + --spacing-md: 6px; + --spacing-lg: 4px; + --spacing-xl: 10px; + --spacing-xxl: 16px; + --radius-xxs: 1px; + --radius-xs: 2px; + --radius-sm: 0; + --radius-md: 6px; + --radius-lg: 2px !important; + --radius-xl: 12px; + --radius-xxl: 22px; + --text-xxs: 9px; + --text-xs: 10px; + --text-sm: 12px; + --text-lg: 12px; + --text-xl: 22px; + --text-xxl: 26px; + --font: 'Source Sans Pro', 'ui-sans-serif', 'system-ui', sans-serif; + --font-mono: 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace; + --body-text-size: var(--nevysha-text-md); + --body-text-weight: 400; + --embed-radius: var(--radius-lg); + --block-border-width: 1px; + --block-info-text-size: var(--text-sm); + --block-info-text-weight: 400; + --block-label-border-width: 1px; + --block-label-margin: 0; + --block-label-padding: var(--spacing-sm) var(--spacing-lg); + --block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0; + --block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px); + --block-label-text-size: var(--text-sm); + --block-label-text-weight: 400; + --block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px); + --block-radius: var(--radius-lg); + --block-shadow: var(--shadow-drop); + --block-title-background-fill: none; + --block-title-border-color: none; + --block-title-border-width: 1px; + --block-title-padding: 0; + --block-title-radius: none; + --block-title-text-size: var(--nevysha-text-md); + --block-title-text-weight: 400; + --container-radius: var(--radius-lg); + --form-gap-width: 1px; + --layout-gap: var(--spacing-xxl); + --panel-border-width: 0; + --section-header-text-size: var(--nevysha-text-md); + --section-header-text-weight: 400; + --checkbox-border-radius: var(--radius-sm); + --checkbox-label-gap: var(--spacing-lg); + --checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md)); + --checkbox-label-shadow: var(--shadow-drop); + --checkbox-label-text-size: var(--nevysha-text-md); + --checkbox-label-text-weight: 400; + --checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + --radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + --checkbox-shadow: var(--input-shadow); + --error-border-width: 1px; + --input-border-width: 1px; + --input-padding: var(--spacing-xl); + --input-radius: var(--radius-lg); + --input-shadow: 0 0 0 var(--shadow-spread) transparent, var(--shadow-inset); + --input-text-size: var(--nevysha-text-md); + --input-text-weight: 400; + --loader-color: var(--color-accent); + --prose-text-size: var(--nevysha-text-md); + --prose-text-weight: 400; + --prose-header-text-weight: 600; + --table-radius: var(--radius-lg); + --button-large-padding: 2px; + --button-large-radius: var(--radius-lg); + --button-large-text-size: var(--nevysha-text-md); + --button-large-text-weight: 600; + --button-shadow: var(--shadow-drop); + --button-shadow-active: var(--shadow-inset); + --button-shadow-hover: var(--shadow-drop-lg); + --button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm)); + --button-small-radius: var(--radius-lg); + --button-small-text-size: var(--nevysha-text-md); + --button-small-text-weight: 400; + --button-transition: none; +} + +.nevysha-light { + --nevysha-gradiant-2: #fefefe; + + --nevysha-white: #000000; + --nevysha-dark: #fefefe; + --nevysha-light-dark: #efefef; + --neutral-50: var(--nevysha-white); + --neutral-100: var(--nevysha-white); + --neutral-200: var(--nevysha-white); + --neutral-400: var(--nevysha-white); + --neutral-600: var(--nevysha-light-dark); + --neutral-700: var(--nevysha-light-dark); + --neutral-800: var(--nevysha-light-dark); + --neutral-900: var(--nevysha-light-dark); + --neutral-950: var(--nevysha-light-dark); + + --link-text-color-hover: var(--ae-primary-color); + + --ae-slider-bg-overlay: repeating-linear-gradient( 90deg, transparent, transparent max(3px, calc(0.671141% - 2px)), var(--ae-input-border-color) max(3px, calc(0.671141% - 2px)), var(--ae-input-border-color) max(4px, calc(0.671141% + 0px)) ); + --ae-subgroup-input-bg-color: hsl(225deg 6% 13%); + --ae-input-border-color: hsl(0deg 0% 84.25%); + --ae-input-color: hsl(0, 0%, 0%); + --ae-input-bg-color: hsl(0, 0%, 100%); + --button-secondary-background-fill: var(--nevysha-dark); + --block-label-background-fill: var(--background-fill-secondary); + --checkbox-label-background-fill-hover: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + + --vertical-line-bg-color: #18181859; + --checkbox-background-color: var(--nevysha-dark); + --checkbox-background-color-focus: var(--checkbox-background-color); + --checkbox-label-background-fill: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + --checkbox-label-background-fill-selected: var(--checkbox-label-background-fill); + --checkbox-label-text-color: var(--body-text-color); + --checkbox-label-text-color-selected: var(--checkbox-label-text-color); + --background-fill-secondary: var(--neutral-900); + --panel-background-fill: var(--background-fill-secondary); + --body-text-color-subdued: var(--neutral-400); + --block-label-text-color: var(--neutral-200); + --button-secondary-text-color: var(--nevysha-white); + --button-secondary-text-color-hover: var(--button-secondary-text-color); + --checkbox-border-color-hover: var(--ae-primary-color); + --checkbox-background-color-hover: var(--nevysha-dark); + --button-secondary-background-fill-hover: var(--ae-primary-color); + + --body-background-fill: rgba(255, 255, 255, 0) !important; + --tab-nav-background-color: var(--nevysha-light-dark); + --tab-nav-background-color-selected: var(--nevysha-dark); + --border-color-primary: #7a7a7a; + --input-border-color: var(--border-color-primary); + --block-border-color: var(--border-color-primary); + --input-border-color-focus: var(--ae-primary-color); + + --ae-panel-border-radius: 0px; + --tabnav-button-color: var(--nevysha-white); + + --input-background-fill: var(--nevysha-dark); + --body-text-color: var(--neutral-100); + --tabmenu-button-color: var(--nevysha-white); + --background-fill-primary: var(--nevysha-light-dark); + /*--border-color-primary: var(--neutral-700);*/ + --block-background-fill: var(--neutral-800); + --secondary-text-color: var(--nevysha-white); + --block-title-text-color: var(--neutral-100); + --main-tabs-background-color: #e5e5e585; +} + +/*css trick for perf ?*/ +#kofi_nevysha_support { + transform: rotateZ(360deg); +} + +.gradio-button.secondary-down:hover { + background: var(--button-secondary-background-fill-hover); + color: var(--button-secondary-text-color-hover); +} +.gradio-dropdown ul.options li.item.selected { + background-color: var(--ae-primary-color) !important; +} +.gradio-dropdown ul.options li.item:hover { + background-color: var(--color-accent); +} +.progressDiv .progress{ + background: var(--ae-primary-color) !important;; +} +/* Show the up/down arrows of number inputs */ +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; + position: relative; +} + +/* Set up arrow */ +input[type="number"]::-webkit-inner-spin-button::before { + content: '\25b2'; + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 50%; + text-align: center; + color: red; + font-size: 10px; +} + +/* Set down arrow */ +input[type="number"]::-webkit-inner-spin-button::after { + content: '\25bc'; + display: block; + position: absolute; + top: 50%; + left: 0; + right: 0; + bottom: 0; + text-align: center; + color: red; + font-size: 10px; +} + +.gradio-accordion { + background-color: var(--nevysha-light-dark) !important; + border: none !important; + border-radius: 3px !important; + color: var(--secondary-text-color) !important; + margin: 4px 0 4px 0 !important; +} + +.gradio-slider input[type=range] { + align-self: flex-start; +} + +.gradio-container.app { + padding: 2px !important; + transform: rotateZ(360deg) +} + +input[type=range] { + overflow: hidden; + width: 100%; + -webkit-appearance: none; + background-color: var(--ae-input-bg-color); + border: 1px solid var(--ae-input-border-color); + position:relative; + accent-color: var(--ae-primary-color) !important; +} +input[type=range]::after { + content: ''; + position: absolute; + height: 13px; + background-image: var(--ae-slider-bg-overlay); + opacity: 0.15; + width: 100%; +} +input[type=range]::-webkit-slider-runnable-track { + height: 14px; + -webkit-appearance: none; + color: var(--ae-primary-color); + margin-top: -1px; +} +input[type=range]::-moz-range-thumb, +input[type=range]::-webkit-slider-thumb { + color: var(--ae-primary-color); + border-radius: 0; +} + + + + +.nevysha.nevysha-tabnav { + display: flex; + position: fixed; + z-index: 2; + flex-direction: column; + width: 175px; + background-color: var(--tab-nav-background-color); + border-bottom: none !important; +} +.nevysha.nevysha-tabnav.center-menu-items { + justify-content: center; +} +.nevysha.nevysha-tabnav > .selected { + background-color: var(--tab-nav-background-color-selected) !important; + border-top: 2px solid var(--ae-primary-color); + border-radius: 0; +} + +.nevysha.nevysha-tabnav > button { + color: var(--tabmenu-button-color); +} + +#quicksettings_gap { + display: none; +} +#quicksettings_gap.nevysha-quicksettings-gap { + display:block; + flex: 1; + max-width: none; +} + +#tabs > .nevysha.tabitem { + margin-left: calc(var(--nevysha-margin-left) + 10px); + background-color: var(--main-tabs-background-color); + border: none; + border-radius: 0; + overflow-y: auto; + height: var(--main-container-height); + padding: 0 10px; +} +#tabs > .nevysha.tabitem::-webkit-scrollbar { + width: 5px; +} +#tabs > .nevysha.tabitem::-webkit-scrollbar-track { + background-color: transparent; +} +#tabs > .nevysha.tabitem::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} + +.nevysha.btn { + display: inline-flex; + justify-content: center; + align-items: center; + transition: var(--button-transition); + padding: var(--size-0-5) var(--size-2); + text-align: center; + + border: var(--button-border-width) solid var(--button-primary-border-color); + background: var(--button-primary-background-fill); + color: var(--button-primary-text-color); + + border-radius: var(--button-large-radius); + padding: var(--button-large-padding); + font-weight: var(--button-large-text-weight); + font-size: var(--button-large-text-size); + + --checkbox-background-color: var(--neutral-800); +} + +.nevysha.btn.refresh { + width: 50px; + max-width: 50px; + text-align: center; + vertical-align: middle; + height: 50px; + background-color: var(--nevysha-dark); + display: none; +} + +.block.padded:not(.gradio-accordion) { + padding: 10px !important; +} +.block.padded:not(.gradio-accordion) { + padding: 10px !important; +} + +.nevysha.settings-child { + background-color: var(--nevysha-light-dark) !important; + /*padding: 10px !important;*/ +} + +.gradio-button.tool { + border-radius: 0 !important; + border: none !important; +} + +#quicksettings { + width: auto; + align-items: stretch; + gap: 20px; +} +#quicksettings > .block.gradio-slider { + display: flex; + flex-direction: row; + align-content: space-between; +} + +#quicksettings > div.block { + padding: 0 !important; + display: flex; + flex-direction: row; + align-content: space-between; +} + +#quicksettings > div.block > * { + width: 100%; +} +#quicksettings > div.block > input[type="range"] { + margin-bottom: 2px; +} + +#quicksettings > .gradio-button.tool { + height: 33px; + margin-left: -20px; +} +#quicksettings.centered-quicksettings { + justify-content: center !important; +} + +#footer { + text-align: center; + position: fixed; + bottom: 0; + left: 0; + display: flex; + justify-content: center; + width: 100%; +} + +#footer > div { + display: flex; + position: fixed; + left: 10px; + bottom: 2px; +} +#footer .versions { + font-size: 85% !important; + opacity: 0.85 !important; + /* margin-left: auto; */ + position: fixed !important; + right: 10px !important; + left: auto !important; + bottom: 2px; +} + +.nevysha.svg-icon { + height: 20px; + fill: var(--nevysha-white); + margin: 3px 0 3px 0; +} + +.nevysha.svg-icon.rotate { + transform: rotate(315deg); +} + +/*footer text*/ +/*#footer > div {*/ +/* color: var(--footer-text-color);*/ +/*}*/ +/*!*versions*!*/ +/*#footer > div.versions > span {*/ +/* color: var(--footer-text-color);*/ +/*}*/ + +.token-remove > svg { + width: 20px; + height: 20px; + fill: var(--neutral-50); +} + +/*hiding scrollbar*/ +html { + overflow-y: hidden; +} + +body, #nevysha-loading { + font-family: -apple-system, BlinkMacSystemFont, sans-serif; + overflow: auto; + background: linear-gradient(330deg, var(--nevysha-gradiant-1) 3%, var(--nevysha-gradiant-2) 38%); + animation: gradient 35s ease infinite; + background-size: 400% 400%; + background-attachment: fixed; + + display: flex; + height: 100vh; +} + +@keyframes gradient { + 0% { + background-position: 0% 0%; + } + 50% { + background-position: 75% 75%; + } + 100% { + background-position: 0% 0%; + } +} + +.wave { + background: rgb(94 26 145 / 16%); + border-radius: 1000% 1000% 0 0; + position: fixed; + width: 200%; + height: 3.5em; + animation: wave 10s -3s linear infinite; + transform: translate3d(0, 0, 0); + opacity: 0.8; + bottom: 0; + left: 0; + z-index: 0; +} + +.wave:nth-of-type(2) { + bottom: -1.25em; + animation: wave 18s linear reverse infinite; + opacity: 0.8; +} + +.wave:nth-of-type(3) { + bottom: -2.5em; + animation: wave 20s -1s reverse infinite; + opacity: 0.9; +} + +@keyframes wave { + 2% { + transform: translateX(1); + } + + 25% { + transform: translateX(-25%); + } + + 50% { + transform: translateX(-50%); + } + + 75% { + transform: translateX(-25%); + } + + 100% { + transform: translateX(1); + } +} + +.block { + padding: 10px !important; +} + +.block.padded:not(.gradio-accordion) { + padding: 0 !important; +} + +.block.token-counter span { + background: var(--nevysha-dark) !important; + box-shadow: none !important; + border: none !important; + border-radius: 0 !important; +} + +.gradio-group { + margin-top: 10px !important; +} + +button.secondary, button.primary { + border: 1px solid var(--ae-input-border-color) !important; + border-radius: var(--ae-panel-border-radius) !important; + background: var(--ae-input-bg-color) !important; + color: var(--ae-input-color) !important; +} + +/*txt2img tweaks*/ + +.nevysha.generate-button, .nevysha.skip-interrupt-wrapper { + /*margin: 0 0 10px 0;*/ +} + +.nevysha.skip-interrupt-wrapper { + display: flex !important; + flex-direction: row; +} +.nevysha.skip-interrupt-wrapper > button { + position: relative; +} + +.nevysha.settings-wrapper { + flex: 1; + margin-top: 15px; + overflow-y: scroll; + padding: 0 5px 15px 0; +} +.nevysha.settings-wrapper::-webkit-scrollbar { + width: 5px; +} + +.nevysha.settings-wrapper::-webkit-scrollbar-track { + background-color: transparent; +} + +.nevysha.settings-wrapper::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} + +.nevysha.txt2img_toprow-wrapper { + display: flex; + flex-direction: column; +} + +#txt2img_settings, #img2img_settings { + flex: 1; + height: 100%; + display: flex; + flex-direction: column; + flex-wrap: nowrap; +} +#txt2img_script_container, #img2img_script_container { + padding: 0 !important; +} +#txt2img_tools, #img2img_tools { + gap: 0; +} + +#txt2img_tools > .form, #img2img_tools > .form { + gap: 0; + justify-content: space-between; +} +#txt2img_toprow, #img2img_toprow { + background-color: var(--nevysha-light-dark) !important; + padding: 10px !important; + margin-bottom: 6px; + display: flex; + flex-direction: column; +} + +#txt2img_script_container, #img2img_script_container { + background-color: transparent !important; +} + +#tab_txt2img > div, +#tab_img2img > div, #tab_img2img > div > div { + height: 100%; +} +.settings-gradio-parent { + height: 100%; + padding: 10px 0 0 0; +} +#txt2img_results, #img2img_results { + height: 100%; +} +#txt2img_gallery_container, #img2img_gallery_container { + flex: 1; + max-height: 100%; + overflow-y: auto; +} +.nevysha.nevysha-scrollable::-webkit-scrollbar { + width: 5px; +} + +.nevysha.nevysha-scrollable::-webkit-scrollbar-track { + background-color: transparent; +} + +.nevysha.nevysha-scrollable::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} + +.nevysha.nevysha-scrollable > div > div:nth-child(2) { + overflow-y: visible; +} + +#txt2img_gallery, #img2img_gallery { + height: 100%; + display: flex; + flex-direction: column; +} +#txt2img_gallery > div:nth-child(2), #img2img_gallery > div:nth-child(2) { + flex: 1; + min-height: auto !important; + max-height: none !important; +} +#txt2img_settings, +#img2img_settings, +#txt2img_results, +#img2img_results{ + flex-grow: 1; + flex-shrink: 0; +} + +#txt2img_settings, #img2img_settings { + flex-basis: 50%; +} + +#txt2img_results, #img2img_results { + flex-basis: 50%; +} + +#txt2img_seed_row, #img2img_seed_row { + display: flex; + align-content: center; + align-items: center; +} +#txt2img_seed_row > button, #img2img_seed_row > button { + align-self: auto; +} + + +/*image browser*/ +#image_browser_tabs_container > :not(:nth-child(-n+2)) { + background-color: var(--nevysha-light-dark) !important; +} + +#tab_settings { + background-color: var(--nevysha-light-dark) !important; +} + + +/*img2im*/ +#img2img_settings .tabs > :not(:first-child) { + background-color: var(--nevysha-light-dark) !important; +} + + +/*draggable*/ +.nevysha.resizable-children-container { + flex-wrap: nowrap; + width: calc(100% - 33px) !important; + display: flex; + flex-direction: row; +} + +.vertical-line-wrapper { + width: 10px !important; + max-width: 10px !important; + min-width: 10px !important; + height: calc(100% - 30px); + cursor: ew-resize; + display: flex; + justify-content: center; + margin: 15px -10px 0 -10px; +} + +.slide-right-browser-panel > .vertical-line-wrapper { + position: absolute; +} + +.slide-right-browser-panel > .slide-right-browser-panel-container { + flex: 1; + padding: 10px; + margin-left: 15px; +} + +.vertical-line { + width: 2px !important; + max-width: 2px !important; + min-width: 2px !important; + height: 100%; + cursor: ew-resize; + background-image: linear-gradient(to bottom, var(--vertical-line-bg-color) 7px, transparent 0); + background-size: 100% 13px; +} + +.gradio-image { + padding: 0 !important; +} + +#img2maskimg { + +} +#expendBtn { + position: absolute; + bottom: 10px; + right: 35px; + z-index: 99999; +} + +#img2maskimg > div:nth-child(3) > div > div { + display: flex; + justify-content: center; +} + +canvas.nevysha { + inset: auto; +} + +.brush > input[type="range"] { + min-width: 200px; +} +.block.gradio-checkbox { + margin: 0 !important; +} + + +.nevysha-accent { + background-color: var(--ae-primary-color) !important; +} + +/*extra network*/ +#txt2img_extra_networks_parent, +#img2img_extra_networks_parent { + position: fixed; + z-index: 9999; + background-color: var(--block-background-fill) !important; + width: 75vw; + right: 0; + height: calc(100% - (100px + var(--menu-top-height))); + top: calc(75px + var(--menu-top-height)); + padding-right: 15px; +} +#txt2img_extra_networks_nevysha_wrapper, +#img2img_extra_networks_nevysha_wrapper { + display: flex; + flex-direction: row; + height: 100%; +} + +#txt2img_extra_networks_nevysha_wrapper > .vertical-line-wrapper, +#img2img_extra_networks_nevysha_wrapper > .vertical-line-wrapper, +.slide-right-browser-panel > .vertical-line-wrapper { + z-index: 9999; + margin: 15px 0 0 5px; +} +/*div[id$="_extra_tabs"] {*/ +/* flex: 1 !important;*/ +/* height: 100% !important;*/ +/* display: flex !important;*/ +/* flex-direction: column !important;*/ +/*}*/ + +.nevysha-right-button-wrapper { + position: fixed; + right: 0; + top: calc(75px + var(--menu-top-height)); + z-index: 999; + height: calc(100vh - (100px + var(--menu-top-height))); + width: 25px; + min-width: 25px !important; + display: flex; + flex-direction: column; +} +.nevysha-right-button-wrapper > button { + flex: 1; + min-height: auto !important; + max-height: none !important; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 0 !important; + margin: 0 !important; +} +.nevysha-right-button-wrapper > button > div, .nevysha-extra-network-floating-btn > div { + /*write the text vertically*/ + writing-mode: vertical-rl; + width: 25px; + min-width: 25px !important; +} + +.nevysha-extra-network-floating-btn { + height: 100px; + position: absolute; + top: calc(50% - 50px); +} +.extra-network-cards { + overflow-x: hidden; +} +.extra-network-cards > .card { + width: var(--extra-network-card-width); + height: var(--extra-network-card-height); +} +.extra-network-cards .card .actions .name { + font-size: var(--nevysha-text-md); + line-break: normal; + text-overflow: ellipsis; + width: 100%; + display: block; +} +.slide-right-browser-panel { + position: fixed; + z-index: 9999; + background-color: var(--block-background-fill) !important; + width: 75vw; + right: 0; + height: calc(100% - (100px + var(--menu-top-height))); + top: calc(75px + var(--menu-top-height)); + padding-right: 15px; + display: flex; + flex-direction: row; +} +.extra-network-subdirs { + overflow: scroll; +} + + +[id$="_subdirs"] { + padding: 0; + margin: 0; + overflow: visible; +} + +[id$="cards_html"] { + display: flex; + flex-direction: column; + width: 100%; + padding: 0; + margin: 0; + align-items: stretch; + overflow: auto; +} +[id$="cards_html"]::-webkit-scrollbar { + width: 5px; +} + +[id$="cards_html"]::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} +[id$="cards_html"]::-webkit-scrollbar-track { + background-color: transparent; +} +[id$="_cards"] { + height: auto; + overflow: visible; + position: relative; +} + + +input[type="number"] { + width: 100px; +} + +#settings_nevyui { + +} +#nevyui-ui-block > * { + +} +.nevysha.settings-nevyui-title { + position: absolute; + top: 0; + width: 100%; + text-align: center; +} +.nevysha.settings-nevyui-title > h2 { + font-size: 1.8em; + color: var(--ae-primary-color); + font-family: 'Caveat Variable', sans-serif; +} +.nevysha.settings-nevyui-title > .subtitle { + font-size: 10px; + font-style: italic; +} +.nevysha.settings-nevyui-top > .info { + color: var(--body-text-color); + margin-bottom: 5px; + font-style: italic; +} +.nevysha-reporting { + color: var(--body-text-color) !important; + margin: 15px 0 15px 0 !important; + border-left: 4px solid var(--ae-primary-color); + padding-left: 5px; + font-size: 1.2em; +} +.nevysha.settings-nevyui-top > .nevysha-reporting > a { + color: var(--ae-primary-color); + text-decoration: underline; +} +#cozy_nest_settings_tabs .block { + background-color: transparent; +} +.nevysha-emphasis { + font-size: 1.1em; + margin-top: 5px; + font-weight: bold; + background-color: var(--ae-primary-color); + color: var(--nevysha-color-from-luminance) !important; + padding: 8px; + border-radius: 2px; +} +.nevysha-tabnav.nevysha-tabnav-settings > h2{ + font-size: 1.6em; + margin-top: 20px; +} +#nevyui_update_info_panel > article { + border-left: 4px solid var(--ae-primary-color); + padding-left: 15px; + margin-left: 5px; +} +#nevysha-version-info { + display: flex; + justify-content: space-between; +} +.nevysha-version-info-text{ + flex: 1; + margin-left: 10px !important; +} +#nevysha-rename-important-msg { + background-color: #9b0505; + color: white; + padding: 5px; + border-radius: 2px; +} +#nevysha-rename-important-msg > a { + color: var(--ae-primary-color); + text-decoration: underline; +} +.nevysha.settings-nevyui-bottom { + position: absolute; + bottom: 0; +} +.nevysha.settings-nevyui-bottom > p { + font-size: 0.8em; + color: var(--body-text-color); +} +#cozy_nest_settings_tabs { + background-color: var(--tab-nav-background-color-selected); +} +#cozy_nest_settings_tabs > .tabitem { + overflow-y: auto; + height: 40vh; +} +#cozy_nest_settings_tabs > .tab-nav { + background-color: var(--tab-nav-background-color); +} +#cozy_nest_settings_tabs > .tab-nav > * { + border-radius: 0; +} +#cozy_nest_settings_tabs > .tab-nav > .selected { + background-color: var(--tab-nav-background-color-selected) !important; + border-top: 2px solid var(--ae-primary-color); +} + +.nevysha-draggable-anchor-icon { + cursor: pointer; + position: relative; + top: 2px; + left: 2px; + width: 60px; + height: 35px; + display: flex; + align-content: center; + justify-content: center; + flex-wrap: wrap; + background: var(--ae-input-bg-color); + border: 1px solid var(--ae-input-border-color); +} + +.nevysha-draggable-anchor-icon > svg { + height: 15px; + fill: var(--body-text-color); +} + +.nevysha-draggable-anchor { + position: absolute; + top: 0; + left: 0; + cursor: pointer; + z-index: 9999; + width: 60px; + height: 35px; +} + +#img_browser_main_block { + gap:0; +} +#img_browser_main_block .form { + align-items: center; +} +textarea.nevysha-image-browser-folder { + display: block; + position: relative; + outline: none!important; + box-shadow: var(--input-shadow); + border: var(--input-border-width) solid var(--input-border-color); + resize: none; +} +#cnib_output_folder > label > textarea { + display: none; +} +.nevysha-image-browser-folder-container { + display: flex; + flex-direction: row; +} +.nevysha-image-browser-folder-btn { + border: 1px solid var(--ae-input-border-color) !important; + border-radius: var(--ae-panel-border-radius) !important; + background: var(--ae-input-bg-color) !important; + color: var(--ae-input-color) !important; + padding: 0 10px !important; + min-width: 60px; +} + + + /*fix menu to top*/ +.nevysha.nevysha-tabnav.menu-fix-top{ + position: fixed; + flex-direction: row; + width: 100%; + top: 0; +} +.gradio-container.app { + z-index: 1; + height: 100vh !important; +} +.gradio-container.app.menu-fix-top { + padding-top: 0 !important; + padding-bottom: 20px !important; +} + +#tab_nevyui > div { + height: 100%; +} +#nevyui-ui-wrapper { + background-color: var(--block-background-fill); +} +.nevysha-tab-settings { + position: fixed; + right: 5px; + top: 30px; + height: fit-content; + width: max(800px, 50vw); + z-index: 9999; + background-color: var(--block-background-fill); + border: 1px solid var(--ae-input-border-color) +} +.nevysha-btn-menu-wrapper { + display: flex; + justify-content: center; + margin: 15px 0; +} +.nevysha-btn-menu-wrapper.menu-fix-top { + position: relative; + right: 20px; + margin: 0 0 0 auto; + display: flex; + gap: 10px; + justify-content: end; +} +.nevysha-btn-menu-wrapper > button > svg { + fill: var(--ae-primary-color); + width: 20px; +} +#nevysha-saved-feedback-wrapper { + height: 1px; +} +.nevysha-feedback { + margin: auto; + width: 100%; + text-align: center; + margin-top: -15px !important; + color: var(--ae-primary-color) !important; +} + +#nevyui_update_info_panel { + padding: 5px; +} +.markdown-body { + font-size: 1em; + color: var(--body-text-color); + line-height: 1.5; + font-weight: 400; + letter-spacing: 0.00938em; + word-wrap: break-word; + padding: 0 10px; + max-height: 400px; + overflow-y: auto; +} +.markdown-body code { + font-family: monospace; + font-size: 0.9em; + background-color: var(--ae-input-bg-color); + color: var(--body-text-color); + padding: 2px; + border-radius: 2px; +} +.markdown-body > h1 { + font-size: medium; + color: var(--body-text-color); + margin-top: 30px; +} +.markdown-body > h2 { + font-size: 1.4em; + color: var(--body-text-color); + margin-top: 30px; +} +.markdown-body > ul { + margin-left: 20px; +} +.markdown-body > ul > li > ul { + margin-left: 20px; +} +.markdown-body > ul > li { + margin-bottom: 10px; +} + + +/*Style to apply when #nevysha_other_tabs is empty*/ +#nevysha_other_tabs:empty { + height: 200px; + width: 200px; +} +#nevysha_other_tabs:empty::before { + content: "Drop tabs here to hide them"; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + color: var(--body-text-color); + font-size: 1.2em; + font-weight: 500; + text-align: center; +} + +#nevysha_other_tabs { + background-color: var(--block-background-fill); + position: absolute; + display: flex; + flex-direction: column; + border: 1px solid var(--ae-input-border-color); +} + +#nevysha_other_tabs > button { + text-align: left; +} +.nevysha-other-tab-text { + padding: 3px 10px; + text-align: left; +} +.remove-nevysha-other-tab { + padding-right: 4px; + padding-left: 4px; +} + +/*LOADING*/ +.nevysha-cozy-nest-app-name{ + font-size: 4em; + margin-bottom: 30%; + /*color: #e378b2;*/ + color: var(--ae-primary-color); + font-family: 'Caveat Variable', sans-serif; + text-transform: uppercase; +} +#nevysha-loading > div.nevysha-loading-progress > div.subtext1 { + font-size: 1em; + color: var(--body-text-color); + opacity: 1; + margin-top: 30%; +} +#nevysha-loading > div.nevysha-loading-progress > div.subtext2 { + font-size: 0.8em; + color: var(--body-text-color); + opacity: 0.2; +} +#nevysha-loading-wrap { + background-color: var(--nevysha-gradiant-2); + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 9000; +} + +#nevysha-loading-wrap > #nevysha-loading > .footer { + position: fixed; + bottom: calc(3.5em + 25px); + right: 25px; + color: var(--body-text-color); + font-size: 0.7em; + opacity: 0.3; +} + +#nevysha-loading { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + z-index: 9001; +} +#loading_step_estimator { + font-size: 0.8em; +} + +.nevysha-loading-progress { + margin: auto; + color: var(--ae-primary-color); + text-align: center; +} + +.lds-roller { + display: inline-block; + position: relative; + width: 80px; + height: 80px; +} +.lds-roller div { + animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; + transform-origin: 40px 40px; +} +.lds-roller div:after { + content: " "; + display: block; + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--ae-primary-color); + margin: -4px 0 0 -4px; +} +.lds-roller div:nth-child(1) { + animation-delay: -0.036s; +} +.lds-roller div:nth-child(1):after { + top: 63px; + left: 63px; +} +.lds-roller div:nth-child(2) { + animation-delay: -0.072s; +} +.lds-roller div:nth-child(2):after { + top: 68px; + left: 56px; +} +.lds-roller div:nth-child(3) { + animation-delay: -0.108s; +} +.lds-roller div:nth-child(3):after { + top: 71px; + left: 48px; +} +.lds-roller div:nth-child(4) { + animation-delay: -0.144s; +} +.lds-roller div:nth-child(4):after { + top: 72px; + left: 40px; +} +.lds-roller div:nth-child(5) { + animation-delay: -0.18s; +} +.lds-roller div:nth-child(5):after { + top: 71px; + left: 32px; +} +.lds-roller div:nth-child(6) { + animation-delay: -0.216s; +} +.lds-roller div:nth-child(6):after { + top: 68px; + left: 24px; +} +.lds-roller div:nth-child(7) { + animation-delay: -0.252s; +} +.lds-roller div:nth-child(7):after { + top: 63px; + left: 17px; +} +.lds-roller div:nth-child(8) { + animation-delay: -0.288s; +} +.lds-roller div:nth-child(8):after { + top: 56px; + left: 12px; +} +@keyframes lds-roller { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +#kofi_nevysha_support > img { + height: 15px !important; +} +.nevysha-kofi-tab { + width: auto; + height: auto; +} + +/*quickfix*/ +.livePreview { + background-color: var(--background-fill-primary) !important; +} + +:root { + --error-handler-white: #eeeeee; +} +#dialog-message-wrap { + font-size: 12px; + position: fixed; + z-index: 1000; + width: 100vw; + height: 100vh; + top: 0; + backdrop-filter: blur(10px); + display: flex; + /* align-content: stretch; */ + justify-content: center; +} +#dialog-message { + display: flex; + flex-direction: column; + padding: 10px; + margin: 50px; + background-color: var(--nevysha-gradiant-2); +} +#dialog-message > .header { + display: flex; + justify-content: space-between; +} +#dialog-message > .header > h1 { + font-size: 1.5em; +} +.ui-dialog-title { + color: var(--error-handler-white); +} +#cozy_nest_error_handling_display { + color: var(--error-handler-white); +} +#cozy_nest_error_handling_display_stack { + color: red; + font-weight: bold; + font-family: monospace; + white-space: pre-wrap; + background-color: #222222; + padding: 25px; + border-radius: 3px; + border-color: red; +} +#cozynest-error-extentions > table > tbody > tr > td > a { + color: var(--error-handler-white); + font-style: italic; +} +#dialog-message > fieldset { + color: var(--error-handler-white); + margin-bottom: 40px; +} +#cozynest-error-instance-info > a { + color: cyan !important; + text-decoration: underline; + font-weight: bold; +} +.cozynest-error-tips { + font-weight: bold; + color: var(--error-handler-white); + background-color: #d57411; + padding: 10px; + font-size: 15px; +} +.cozynest-error-tips > a { + color: cyan; + text-decoration: underline; + font-weight: bold; +} +.ui-dialog { + background-color: #101010; + border: none; +} +.ui-dialog-titlebar, .ui-dialog-buttonpane { + background-color: black; + border: none; + color: var(--error-handler-white); +} +.ui-button { + background-color: #222222; + border: none; + color: var(--error-handler-white); +} +.ui-button:hover, .ui-widget.ui-widget-content { + border: none; +} + +/*Image Browser*/ +.blocInfo, textarea { + display: block; + position: relative; + outline: none!important; + box-shadow: var(--input-shadow); + border: var(--input-border-width) solid var(--input-border-color); + border-color: var(--input-border-color)!important; + border-radius: var(--input-radius)!important; + background: var(--input-background-fill)!important; + background-color: var(--input-background-fill)!important; + width: 100%; + color: var(--body-text-color)!important; + font-weight: var(--input-text-weight)!important; + font-size: var(--input-text-size)!important; + line-height: var(--line-sm)!important; + font-family: monospace!important; +} + +/*Fix for generation info size*/ + +.infotext { + max-height: 200px; + overflow-y: auto; +} +.infotext::-webkit-scrollbar { + width: 5px; +} + +.infotext::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} +.infotext::-webkit-scrollbar-track { + background-color: transparent; +} + +ul.options { + overflow-y: auto; + z-index: 303; + border: 1px solid var(--ae-input-border-color); +} +ul.options::-webkit-scrollbar { + width: 5px; +} + +ul.options::-webkit-scrollbar-track { + background-color: transparent; +} + +ul.options::-webkit-scrollbar-thumb { + background-color: var(--ae-primary-color); + border-radius: 20px; +} + +button:hover { + filter: brightness(1.2) !important; +} +.nevysha-button:hover { + filter: brightness(1.2) !important; +} +body.nevysha-light button:hover { + filter: brightness(0.95) !important +} +body.nevysha-light .nevysha-button:hover { + filter: brightness(0.95) !important +} + +.nevysha-enhanced-prompt-field { + padding: 10px !important; +} +.nevysha-enhanced-prompt-field > .prompt { + height: 289px; + display: block; + position: relative; + outline: none!important; + box-shadow: var(--input-shadow); + border: var(--input-border-width) solid var(--input-border-color); + border-radius: var(--input-radius); + background: var(--input-background-fill); + width: 100%; + color: var(--body-text-color)!important; + font-weight: var(--input-text-weight)!important; + font-size: var(--input-text-size)!important; + line-height: var(--line-sm)!important; + font-family: monospace!important; + overflow: auto; + min-height: 45px; + padding: 10px; +} +.nevysha-enhanced-prompt-field-bracket { + font-weight:bold; + font-size: 1.2em; +} \ No newline at end of file diff --git a/cozy-nest-client/main/cozy-utils.js b/cozy-nest-client/main/cozy-utils.js new file mode 100644 index 0000000..29b51a7 --- /dev/null +++ b/cozy-nest-client/main/cozy-utils.js @@ -0,0 +1,79 @@ +export const getTheme = () => { + const gradioURL = window.location.href + if (!gradioURL.includes('?__theme=')) { + return 'dark' + } + return gradioURL.split('?__theme=')[1]; +} + +export const hexToRgb = (hex) => { + const bigint = parseInt(hex.replace('#', ''), 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + + return `${r} ${g} ${b}`; +} + +export const isUpToDate = (current, remote) => { + const v1 = current.split('.'); + const v2 = remote.split('.'); + + for (let i = 0; i < Math.max(v1.length, v2.length); i++) { + const num1 = parseInt(v1[i]) || 0; + const num2 = parseInt(v2[i]) || 0; + + if (num1 < num2) { + return false; + } else if (num1 > num2) { + return true; + } + } + + return true; // Both versions are equal +} + +export const getLuminance = (hexcolor) => { + // remove # character from hex color string + const hex = hexcolor.replace('#', ''); + + // convert hex color to RGB values + const r = parseInt(hex.substr(0,2),16); + const g = parseInt(hex.substr(2,2),16); + const b = parseInt(hex.substr(4,2),16); + + // calculate the relative luminance of the color + return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; +} + +//dummy method +export const dummyLoraCard = () => { + const container = document.querySelector("#txt2img_lora_cards"); + + // Get the first child element of the container + const firstChild = container.firstChild; + + // Duplicate the first child element 100 times and append them to the fragment + for (let i = 0; i < 100; i++) { + const clone = container.querySelector('.card').cloneNode(true); + container.insertBefore(clone, firstChild); + } +}; + +export const dummyControlNetBloc = () => { + const container = document.querySelector("#txt2img_controlnet"); + + // Get the parent element of the container + const parent = container.parentElement; + + // Duplicate the first child element 100 times and append them to the fragment + for (let i = 0; i < 100; i++) { + const clone = parent.cloneNode(true); + parent.parentElement.insertBefore(clone, parent); + } +} + +export const dummySubdirs = () => { + const $subdirs = $('#txt2img_lora_subdirs'); + $subdirs.append($subdirs.html()); +} diff --git a/cozy-nest-client/main/kofi-cup-border.png b/cozy-nest-client/main/kofi-cup-border.png new file mode 100644 index 0000000..0a12895 Binary files /dev/null and b/cozy-nest-client/main/kofi-cup-border.png differ diff --git a/cozy-nest-client/main/nevysha-cozy-nest.js b/cozy-nest-client/main/nevysha-cozy-nest.js new file mode 100644 index 0000000..d3c95c4 --- /dev/null +++ b/cozy-nest-client/main/nevysha-cozy-nest.js @@ -0,0 +1,1808 @@ +import showdown from 'showdown/dist/showdown.js'; +import $ from "jquery"; +window.$ = window.jQuery = $; + +import SimpleTimer from "./SimpleTimer.js"; +import {getTheme, isUpToDate, getLuminance} from './cozy-utils.js'; +import {COZY_NEST_DOM_TWEAK_LOAD_DURATION, COZY_NEST_GRADIO_LOAD_DURATION, SETTINGS_MIN_WIDTH, RESULT_MIN_WIDTH} from "./Constants.js"; +import Loading from "./Loading.js"; + +import {waves, svg_magic_wand, svg_update_info} from "./svg.js"; +import {applyAccentColor, applyBgGradiantColor, applyWavesColor + , wrapDataGenerationInfo, wrapSettings, createVerticalLineComp} from "./tweaks/various-tweaks.js"; +import kofiCup from './kofi-cup-border.png' +import { + setupPopupInstanceInfo, + populateInstanceInfoDialog, + showInstanceInfoDialog +} from "./tweaks/troubleshot-dialog.js"; +import {CozyLogger} from "./CozyLogger.js"; + + +const addDraggable = ({prefix}) => { + + const settings = document.getElementById(`${prefix}_settings`); + + //change min-width to min(420px, 100%) + settings.style.minWidth = `min(${SETTINGS_MIN_WIDTH}px, 100%)` + + // Create a new vertical line element + const lineWrapper = createVerticalLineComp(); + + // Insert the line element after the settings element + settings.insertAdjacentElement('afterend', lineWrapper); + + const container = settings.parentElement; + container.classList.add('nevysha', 'resizable-children-container'); + const results = document.getElementById(`${prefix}_results`); + + //change min-width to 320px + settings.style.minWidth = `min(${RESULT_MIN_WIDTH}px, 100%)`; + + //get linePosition from local storage + let linePosition = localStorage.getItem(`${prefix}_linePosition`); + if (!linePosition) { + linePosition = 50; + localStorage.setItem(`${prefix}_linePosition`, `${linePosition}`); + } + settings.style.flexBasis = `${linePosition}%`; + results.style.flexBasis = `${100 - linePosition}%`; + + let isDragging = false; + + lineWrapper.addEventListener('mousedown', (e) => { + isDragging = true; + e.preventDefault(); + }); + + document.addEventListener('mousemove', (event) => { + if (!isDragging) return; + + //calc the offset of the tab + const tab = document.querySelector(`#tab_${prefix}`); + let offsetX = tab.offsetLeft; + let parent = tab.offsetParent; + + while (parent) { + offsetX += parent.offsetLeft; + parent = parent.offsetParent; + } + + const containerWidth = container.offsetWidth; + const mouseX = event.clientX; + const linePosition = ((mouseX - offsetX) / containerWidth) * 100; + + //if settings width is min, return + if (linePosition <= SETTINGS_MIN_WIDTH / containerWidth * 100) { + return; + } + //if results width is min, return + if (linePosition >= (1 - RESULT_MIN_WIDTH / containerWidth) * 100) { + return; + } + + //save linePosition to local storage + localStorage.setItem(`${prefix}_linePosition`, `${linePosition}`); + + settings.style.flexBasis = `${linePosition}%`; + results.style.flexBasis = `${100 - linePosition}%`; + }); + + document.addEventListener('mouseup', () => { + isDragging = false; + }); +} + +const tweakButtonsIcons = () => { + document.querySelectorAll('button').forEach((button) => { + if (button.textContent.includes('📂')) { + // Add SVG element to the SVG container here + button.innerHTML = ''; + } + if (button.textContent.includes('🔄')) { + button.innerHTML = ''; + } + if (button.textContent.includes('↙️')) { + button.innerHTML = ''; + } + if (button.textContent.includes('🗑️')) { + button.innerHTML = ''; + } + if (button.textContent.includes('🎴')) { + button.innerHTML = ''; + } + if (button.textContent.includes('📋')) { + button.innerHTML = ''; + } + if (button.textContent.includes('💾')) { + button.innerHTML = ''; + } + if (button.textContent.includes('🎲️')) { + button.innerHTML = ''; + } + if (button.textContent.includes('♻️')) { + button.innerHTML = ''; + } + }); +} + +function tweakInpainting() { + + //expend button + const img2maskimg = document.getElementById("img2maskimg") + const expendBtn = document.createElement("button") + expendBtn.setAttribute("id", "expendBtn") + expendBtn.setAttribute("class", "nevysha lg primary gradio-button btn") + expendBtn.textContent = "Expand" + img2maskimg.insertAdjacentElement("beforeend", expendBtn) + + const inpaintTab = document.getElementById("img2maskimg"); + let defaultStyle = inpaintTab.getAttribute("style"); + let nodesCanvasData = [] + let expended = false; + expendBtn.addEventListener("click", () => { + + if (!document.querySelectorAll("canvas")) { + return; + } + + if (!expended) { + expendBtn.textContent = "Reduce" + expendBtn.style.position = "fixed"; + inpaintTab.style.position = "fixed"; + inpaintTab.style.zIndex = 999 + inpaintTab.style.top = "5px"; + inpaintTab.style.left = "5px"; + inpaintTab.style.width = "calc(100vw - 10px)"; + inpaintTab.style.height = "calc(100vh - 10px)"; + inpaintTab.style.overflow = ""; + + //hide button to delete image + //this button is inside #img2maskimg > .image-container + //it's the third button + document.querySelector('#img2maskimg > .image-container').querySelector("button:nth-child(3)").style.display = "none" + + //apply to canvas + const nodesCanvas = document.querySelectorAll("canvas") + nodesCanvasData = []; + nodesCanvas.forEach((canvas) => { + let canvasId = `nevysha-${canvas.getAttribute("key")}-canvas`; + canvas.setAttribute('id',canvasId) + canvas.classList.add("nevysha") + nodesCanvasData.push({ + id: canvasId, + defaultStyle: canvas.getAttribute("style"), + }) + + canvas.style.maxWidth = "calc(100vw - 20px)"; + canvas.style.width = ""; + canvas.style.maxHeight = "calc(100vh - 20px)"; + canvas.style.height = ""; + }) + + } else { + expendBtn.textContent = "Expand" + expendBtn.style.position = "absolute"; + inpaintTab.setAttribute("style", defaultStyle); + + document.querySelector('#img2maskimg > .image-container').querySelector("button:nth-child(3)").style.display = "block" + + //revert canvas + nodesCanvasData.forEach((canvasData) => { + const canvas = document.getElementById(canvasData.id) + canvas.setAttribute("style", canvasData.defaultStyle); + }) + } + expended = !expended; + + }) +} + +function addScrollable(bundle) { + document.getElementById(`${bundle.prefix}_gallery_container`).classList.add("nevysha","nevysha-scrollable") +} + +function getHexColorForAccent() { + return document.querySelector("#setting_nevyui_accentColor").querySelector("input").value; +} + + + +function applyCozyNestConfig() { + + //waves + const setWaveColor = () => { + const hexColor = document.querySelector("#setting_nevyui_waveColor").querySelector("input").value; + applyWavesColor(hexColor); + } + setWaveColor() + document.querySelector("#setting_nevyui_waveColor").querySelector("input").addEventListener("change", setWaveColor) + + //background gradient + const setGradientColor = () => { + const hexColor = document.querySelector("#setting_nevyui_bgGradiantColor").querySelector("input").value; + applyBgGradiantColor(hexColor); + } + setGradientColor() + document.querySelector("#setting_nevyui_bgGradiantColor").querySelector("input").addEventListener("change", setGradientColor) + + //disable waves and gradiant + const setDisabledWavesAndGradiant = () => { + const disableWavesAndGradiant = document.querySelector("#setting_nevyui_disableWavesAndGradiant").querySelector("input").checked; + const $waves = $('.wave'); + const $body = $('body'); + if (disableWavesAndGradiant) { + $waves.css('display', 'none'); + $waves.css('animation', 'none'); + $body.css('background', 'var(--nevysha-gradiant-2)'); + $body.css('animation', 'none'); + } + else { + $waves.css('display', ''); + $waves.css('animation', ''); + $body.css('background', ''); + $body.css('animation', ''); + } + + } + setDisabledWavesAndGradiant() + document.querySelector("#setting_nevyui_disableWavesAndGradiant").querySelector("input").addEventListener("change", setDisabledWavesAndGradiant) + + //background gradient + const setAccentColor = () => { + const hexColor = getHexColorForAccent(); + applyAccentColor(hexColor, getHexColorForAccent()); + } + //accent generate button + const setAccentForGenerate = () => { + const checked = document.querySelector("#setting_nevyui_accentGenerateButton").querySelector("input").checked; + document.querySelectorAll('button[id$="_generate"]').forEach((btn) => { + if (checked) { + let txtColorAppending = ""; + if (getLuminance(getHexColorForAccent()) > 0.5) { + txtColorAppending = "color: black !important"; + } + btn.setAttribute("style", `background: var(--ae-primary-color) !important; ${txtColorAppending}`); + } else { + btn.setAttribute("style", ''); + } + }) + } + + setAccentColor() + document.querySelector("#setting_nevyui_accentColor").querySelector("input").addEventListener("change", setAccentColor) + document.querySelector("#setting_nevyui_accentColor").querySelector("input").addEventListener("change", setAccentForGenerate) + + + setAccentForGenerate() + document.querySelector("#setting_nevyui_accentGenerateButton").querySelector("input").addEventListener("change", setAccentForGenerate); + + //font size + const setFontSize = () => { + const fontSize = document.querySelector("#setting_nevyui_fontSize").querySelector("input[type=number]").value; + document.querySelector(':root').style.setProperty('--nevysha-text-md', `${fontSize}px`); + recalcOffsetFromMenuHeight() + } + setFontSize() + document.querySelector("#setting_nevyui_fontSize").querySelector("input[type=number]").addEventListener("change", setFontSize) + document.querySelector("#setting_nevyui_fontSize").querySelector("input[type=range]").addEventListener("change", setFontSize) + + //card height + const setCardHeight = () => { + const cardHeight = document.querySelector("#setting_nevyui_cardHeight").querySelector("input[type=number]").value; + document.querySelector(':root').style.setProperty('--extra-network-card-height', `${cardHeight}em`); + } + setCardHeight() + document.querySelector("#setting_nevyui_cardHeight").querySelector("input[type=number]").addEventListener("change", setCardHeight) + document.querySelector("#setting_nevyui_cardHeight").querySelector("input[type=range]").addEventListener("change", setCardHeight) + + //card width + const setCardWidth = () => { + const cardWidth = document.querySelector("#setting_nevyui_cardWidth").querySelector("input[type=number]").value; + document.querySelector(':root').style.setProperty('--extra-network-card-width', `${cardWidth}em`); + } + setCardWidth() + document.querySelector("#setting_nevyui_cardWidth").querySelector("input[type=number]").addEventListener("change", setCardWidth) + document.querySelector("#setting_nevyui_cardWidth").querySelector("input[type=range]").addEventListener("change", setCardWidth) + + //check if menu is in left or top mode + const menuPosition = () => { + const isLeftChecked = document.querySelector("#setting_nevyui_menuPosition").querySelector("input[value=left]").checked; + + //top mode + if (!isLeftChecked) { + document.querySelector(".nevysha.nevysha-tabnav").classList.add("menu-fix-top") + document.querySelector(".gradio-container.app").classList.add("menu-fix-top") + document.querySelector("#nevysha-btn-menu-wrapper")?.classList.add("menu-fix-top") + document.querySelector(':root').style.setProperty('--nevysha-margin-left', `0`); + document.querySelector(':root').style.setProperty('--menu-top-height', `25px`); + + //centered or not + const isCenteredChecked = document.querySelector("#setting_nevyui_menuPosition").querySelector("input[value=top_centered]").checked; + if (isCenteredChecked) { + COZY_NEST_CONFIG.main_menu_position = "top_centered"; + document.querySelector(".nevysha.nevysha-tabnav").classList.add("center-menu-items") + } else { + COZY_NEST_CONFIG.main_menu_position = "top"; + document.querySelector(".nevysha.nevysha-tabnav").classList.remove("center-menu-items") + } + } + //left mode + else { + COZY_NEST_CONFIG.main_menu_position = "left"; + document.querySelector(".nevysha.nevysha-tabnav").classList.remove("menu-fix-top") + document.querySelector(".gradio-container.app").classList.remove("menu-fix-top") + document.querySelector("#nevysha-btn-menu-wrapper")?.classList.remove("menu-fix-top") + document.querySelector(':root').style.setProperty('--nevysha-margin-left', `175px`); + document.querySelector(':root').style.setProperty('--menu-top-height', `1px`); + } + recalcOffsetFromMenuHeight() + } + menuPosition() + document.querySelector("#setting_nevyui_menuPosition").querySelector("input[value=left]").addEventListener("change", menuPosition) + document.querySelector("#setting_nevyui_menuPosition").querySelector("input[value=top]").addEventListener("change", menuPosition) + document.querySelector("#setting_nevyui_menuPosition").querySelector("input[value=top_centered]").addEventListener("change", menuPosition) + + //quicksetting gap + const setQuicksettingPosition = () => { + const position = document.querySelector("#setting_nevyui_quicksettingsPosition") + .querySelector("input[type=radio]:checked").value; + if (position === 'split') { + document.querySelector("#quicksettings_gap").classList.add("nevysha-quicksettings-gap") + document.querySelector("#quicksettings").classList.remove("centered-quicksettings") + } + else if (position === 'centered') { + document.querySelector("#quicksettings_gap").classList.remove("nevysha-quicksettings-gap") + document.querySelector("#quicksettings").classList.add("centered-quicksettings") + } + else { + document.querySelector("#quicksettings_gap").classList.remove("nevysha-quicksettings-gap") + document.querySelector("#quicksettings").classList.remove("centered-quicksettings") + } + } + setQuicksettingPosition() + document.querySelector("#setting_nevyui_quicksettingsPosition") + .querySelectorAll("input[type=radio]").forEach((input) => input.addEventListener("change", setQuicksettingPosition)) + +} + +function tweakAWQ() { + + const observer = new MutationObserver((mutationsList, observer) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList') { + const addedNodes = Array.from(mutation.addedNodes); + const targetNode = addedNodes.find(node => node.id === 'AWQ-container'); + if (targetNode) { + observer.disconnect(); + closure(); + break; + } + } + } + }); + + const observerConfig = { + childList: true, + subtree: true + }; + + observer.observe(document.documentElement, observerConfig); + + const closure = () => { + const awqContainer = document.querySelector("#AWQ-container") + + //create a wrapper div + const awqWrapper = document.createElement("div") + awqWrapper.id = "nevysha_awq_wrapper" + awqWrapper.style.zIndex = "9999" + awqWrapper.style.display = "none" + awqWrapper.style.position = "fixed" + awqWrapper.style.bottom = "30px" + document.body.appendChild(awqWrapper) + + //bush awqContainer into wrapper + awqWrapper.appendChild(awqContainer) + + const btnAWQ = document.createElement("button") + btnAWQ.classList.add("nevysha-btn-menu", "nevysha-btn-menu-awq", "gradio-button", "primary", "nevysha") + btnAWQ.id = "nevyui_awq_btn" + btnAWQ.innerHTML = 'Show/Hide AWQ' + btnAWQ.title = "Show/Hide AWQ" + btnAWQ.setAttribute("style", "position: fixed; bottom: 0; left: calc(50% - 75px); width: 150px;") + + document.querySelector('div.app').insertAdjacentElement('beforeend', btnAWQ) + btnAWQ.addEventListener("click", () => { + if (awqWrapper.style.display === "none") { + awqWrapper.style.display = "block" + } else { + awqWrapper.style.display = "none" + } + }); + } + + +} + +const addCozyNestCustomBtn = () => { + //create a wrapper div + const nevySettingstabMenuWrapper = document.createElement("div"); + nevySettingstabMenuWrapper.classList.add("nevysha-btn-menu-wrapper"); + nevySettingstabMenuWrapper.id = "nevysha-btn-menu-wrapper"; + + //add a new button in the tabnav + const nevySettingstabMenu2 = ``; + nevySettingstabMenuWrapper.insertAdjacentHTML('beforeend', nevySettingstabMenu2); + //add a new button in the tabnav + const updateInfoBtn = ``; + nevySettingstabMenuWrapper.insertAdjacentHTML('beforeend', updateInfoBtn); + //add the wrapper div in the tabnav + document.querySelector("#tabs > div.tab-nav").insertAdjacentElement('beforeend', nevySettingstabMenuWrapper); + + //create a div that will contain a dialog + //create a wrapper div + const updateTab = document.createElement("div"); + updateTab.classList.add("nevysha-update-tab", "nevysha", "nevysha-tab", "nevysha-tab-settings"); + updateTab.id = "nevyui_update_info_panel"; + updateTab.style = "display: none;"; + document.querySelector("#tabs").insertAdjacentElement("beforeend", updateTab) + + //add kofi image :blush: + const kofiImg = document.createElement('button') + kofiImg.id = 'kofi_nevysha_support' + kofiImg.innerHTML = `Consider a donation on ko-fi! :3` + kofiImg.title = "Consider a donation on ko-fi! :3" + nevySettingstabMenuWrapper.insertAdjacentElement('beforeend', kofiImg); + + //create a div that will contain a dialog to display the iframe + const kofiTab = document.createElement("div"); + kofiTab.classList.add("nevysha-kofi-tab", "nevysha", "nevysha-tab", "nevysha-tab-settings"); + kofiTab.id = "nevyui_kofi_panel"; + kofiTab.style = "display: none;"; + // kofiTab.innerHTML = `` + document.querySelector("#tabs").insertAdjacentElement("beforeend", kofiTab) + + let kofiImgIsVisible = false + + function toggleKofiPanel() { + + window.open("https://ko-fi.com/nevysha", "_blank") + } + + //add event listener to the button + kofiImg.addEventListener("click", () => { + toggleKofiPanel(); + }); + //close the panel when clicking outside + document.addEventListener("click", (e) => { + if (kofiImgIsVisible && !e.target.closest("#kofi_nevysha_support")) { + toggleKofiPanel(); + } + }); + + //fetch version_data.json + loadVersionData().then(ignored => ignored) +} + +async function loadVersionData() { + + const current_version_data = await (await fetch(`file=extensions/Cozy-Nest/version_data.json?${new Date()}`)).json() + const remote_version_data = await (await fetch(`https://raw.githubusercontent.com/Nevysha/Cozy-Nest/main/version_data.json?${new Date()}`)).json() + + //in current_version_data.version and remote_version_data.version, replace string version to int + current_version_data.number = parseInt(current_version_data.version.replace(/\./g, '')) + remote_version_data.number = parseInt(remote_version_data.version.replace(/\./g, '')) + + let remote_patchnote = await (await fetch(`https://raw.githubusercontent.com/Nevysha/Cozy-Nest/main/PATCHNOTE.md?t=${new Date()}`)).text(); + //insert "Patchnote" title div + let patchnoteTitle = `

Patchnote [${remote_version_data.version}]

`; + //if local version si higher than remote version, fetch from local file (for dev purpose) + if (current_version_data.number > remote_version_data.number) { + remote_patchnote = await (await fetch(`file=extensions/Cozy-Nest/PATCHNOTE.md?t=${new Date()}`)).text(); + patchnoteTitle = `

Patchnote [${current_version_data.version}_DEV]

`; + } + + document.querySelector("#nevyui_update_info_panel").insertAdjacentHTML('beforeend', patchnoteTitle); + + //regex to replace [x] with a checkmark + const regex = /\[x\]/g; + remote_patchnote = remote_patchnote.replace(regex, ""); //TODO add icon ? + + //regex to replace [ ] with a cross + const regex2 = /\[ \]/g; + remote_patchnote = remote_patchnote.replace(regex2, ""); //TODO add icon ? + + + const converter = new showdown.Converter(); + + const article = `
${converter.makeHtml(remote_patchnote)}
` + document.querySelector('#nevyui_update_info_panel').insertAdjacentHTML('beforeend', article) + + //create a div that will contain info related to version compliance + const versionInfo = document.createElement("div"); + versionInfo.classList.add("nevysha-version-info", "nevysha-emphasis"); + versionInfo.id = "nevysha-version-info"; + //add div to the beginning of the updateTab + document.querySelector('#nevyui_update_info_panel').insertAdjacentElement('afterbegin', versionInfo) + + //add a button to update the extension + const updateBtn = + ``; + document.querySelector('#nevysha-version-info').insertAdjacentHTML('beforeend', updateBtn) + document.querySelector('#nevyui_update_btn').addEventListener('click', (e) => { + //prevent default behavior + e.preventDefault(); + e.stopPropagation(); + + //trigger click on nevyui_sh_options_update button + document.querySelector('#nevyui_sh_options_update').click() + //wait for 5s and trigger reloadUI by clicking settings_restart_gradio button + //change nevyui_update_btn to Update in progress + document.querySelector('#nevyui_update_btn').innerHTML = "Update in progress..." + setTimeout(() => { + document.querySelector('#settings_restart_gradio').click() + }, 5000); + }); + + //compare versions and display info + if (isUpToDate(current_version_data.version, remote_version_data.version)) { + //versions are the same + const p = `

You are up to date! (installed: v${current_version_data.version})

` + //add p to the beginning of nevysha-version-info + document.querySelector('#nevysha-version-info').insertAdjacentHTML('afterbegin', p) + //hide update button + document.querySelector('#nevyui_update_btn').style.display = "none"; + //add version info to the bottom-right corner (no update available) + document.getElementsByClassName("versions")[0].innerHTML += '⠀•⠀Cozy Nest: ⠀v' + current_version_data.version + ''; + } + else { + //local version is older than remote version + const p = `

An update is available! (installed: v${current_version_data.version}, new : v${remote_version_data.version})

` + //add p to the end of nevysha-version-info + document.querySelector('#nevysha-version-info').insertAdjacentHTML('afterbegin', p) + + //set fill color of .nevysha-btn-menu-wrapper > button > svg to red + document.querySelector('#nevyui_update_info > svg').style.fill = "red"; + + //add version info to the bottom-right corner with a notice about an update + document.getElementsByClassName("versions")[0].innerHTML += '⠀•⠀Cozy Nest:⠀v' + current_version_data.version + ''; + } + + //add close button + const closeBtn = ``; + document.querySelector('#nevysha-version-info').insertAdjacentHTML('afterbegin', closeBtn) + document.querySelector('#nevyui_update_info_close_btn').addEventListener('click', (e) => { + //prevent default behavior + e.preventDefault(); + e.stopPropagation(); + + document.querySelector('#nevyui_update_info').click(); + }); + +} + +function createFolderListComponent() { + // create component to add and remove folders to scrap for images browser + const componentContainer = document.querySelector('#cnib_output_folder').parentElement; + const textarea = document.querySelector('#cnib_output_folder textarea'); + componentContainer.classList.remove('hidden') + + function updateList(foldersList) { + document.querySelectorAll('.nevysha-image-browser-folder-container').forEach(el => el.remove()); + textarea.value = JSON.stringify(foldersList); + + //throw change event to update textarea + textarea.dispatchEvent(new Event('change')); + textarea.dispatchEvent(new Event('blur')); + + parseAndDisplayFolderSettings(); + } + + function parseAndDisplayFolderSettings() { + const forldersListJson = textarea.value; + const foldersList = JSON.parse(forldersListJson); + + for (const folderIndex in foldersList) { + const folder = foldersList[folderIndex]; + const imageBrowserFolderContainer = document.createElement('div'); + imageBrowserFolderContainer.classList.add('nevysha-image-browser-folder-container'); + componentContainer.appendChild(imageBrowserFolderContainer); + + //input for path + const imageBrowserFolder = document.createElement('textarea'); + imageBrowserFolder.classList.add('nevysha-image-browser-folder'); + imageBrowserFolder.value = folder; + imageBrowserFolder.setAttribute('enabled', 'false'); + imageBrowserFolderContainer.appendChild(imageBrowserFolder); + + //button to remove folder + const imageBrowserFolderRemoveBtn = document.createElement('button'); + imageBrowserFolderRemoveBtn.classList.add('nevysha-image-browser-folder-btn'); + imageBrowserFolderRemoveBtn.innerHTML = 'Remove'; + imageBrowserFolderRemoveBtn.addEventListener('click', (e) => { + //prevent default behavior + e.preventDefault(); + e.stopPropagation(); + + //remove from list using index + foldersList.splice(folderIndex, 1); + updateList(foldersList); + + }); + imageBrowserFolderContainer.appendChild(imageBrowserFolderRemoveBtn); + + } + + //add a last empty one to add a new folder + const imageBrowserFolderContainer = document.createElement('div'); + imageBrowserFolderContainer.classList.add('nevysha-image-browser-folder-container'); + componentContainer.appendChild(imageBrowserFolderContainer); + + //input for path + const imageBrowserFolder = document.createElement('textarea'); + imageBrowserFolder.classList.add('nevysha-image-browser-folder'); + imageBrowserFolder.setAttribute("placeholder", 'Paste a folder path here...'); + imageBrowserFolderContainer.appendChild(imageBrowserFolder); + + //button to remove folder + const imageBrowserFolderAddBtn = document.createElement('button'); + imageBrowserFolderAddBtn.classList.add('nevysha-image-browser-folder-btn'); + imageBrowserFolderAddBtn.innerHTML = 'Add'; + imageBrowserFolderAddBtn.addEventListener('click', (e) => { + //prevent default behavior + e.preventDefault(); + e.stopPropagation(); + + const folder = imageBrowserFolder.value; + if (folder.length <= 0) { + window.alert("Please enter a folder path to add."); + return; + } + + const foldersListJson = textarea.value; + const foldersList = JSON.parse(foldersListJson); + + //check if folder already exists + if (foldersList.includes(folder)) { + window.alert("This folder is already in the list."); + return; + } + + foldersList.push(folder); + + updateList(foldersList); + + }); + imageBrowserFolderContainer.appendChild(imageBrowserFolderAddBtn); + } + + parseAndDisplayFolderSettings(); +} + +const tweakNevyUiSettings = () => { + // select button element with "Nevysha Cozy Nest" as its content + const nevySettingstabMenu = $('#tabs > div > button:contains("Nevysha Cozy Nest")'); + // hide the button + nevySettingstabMenu.hide(); + + addCozyNestCustomBtn(); + + ///create an hideable right side panel + const nevySettingstab = `