diff --git a/api/README.md b/api/README.md index 34aaed0..fe5aef6 100644 --- a/api/README.md +++ b/api/README.md @@ -130,4 +130,14 @@ Gets the details for a single, specific intrinsic. The following data is returne } ] } -``` \ No newline at end of file +``` + +### `GET /version` +Gets version information for the data. The following data is returned: +```json +{ + "intelVersion": "M.m.p (Major.minor.patch version as reported by Intel)", + "intelUpdate": "yyyy-MM-dd (date of Intel's last update prior to scraping)", + "scrapeDate": "yyyy-MM-dd (date of last update)" +} +``` diff --git a/api/src/main/resources/logback.xml b/api/src/main/resources/logback.xml index 2e46a79..97606fb 100644 --- a/api/src/main/resources/logback.xml +++ b/api/src/main/resources/logback.xml @@ -8,7 +8,7 @@ - + - \ No newline at end of file + diff --git a/frontend/composeApp/build.gradle.kts b/frontend/composeApp/build.gradle.kts index e892cf8..33a3b0a 100644 --- a/frontend/composeApp/build.gradle.kts +++ b/frontend/composeApp/build.gradle.kts @@ -47,12 +47,14 @@ kotlin { implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.ktor.client.core) implementation(libs.ktor.client.logging) + implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.serialization.kotlinx.json) - implementation(libs.dotenv) implementation(libs.json) implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.json) implementation(libs.logback.classic) + implementation(libs.material3) + implementation(libs.lucide) } desktopMain.dependencies { implementation(compose.desktop.currentOs) @@ -65,7 +67,6 @@ kotlin { } } - compose.desktop { application { mainClass = "com.jaytux.simd.frontend.MainKt" @@ -77,3 +78,7 @@ compose.desktop { } } } + +compose.resources { + // +} \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-Italic-VariableFont_wght.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..6acf196 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-Italic-VariableFont_wght.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-VariableFont_wght.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-VariableFont_wght.ttf new file mode 100644 index 0000000..8c07df8 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/Alegreya-VariableFont_wght.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/OFL.txt b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/OFL.txt new file mode 100644 index 0000000..0042c66 --- /dev/null +++ b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Alegreya Project Authors (https://github.com/huertatipografica/Alegreya) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/README.txt b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/README.txt new file mode 100644 index 0000000..6c8e9b0 --- /dev/null +++ b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/README.txt @@ -0,0 +1,75 @@ +Alegreya Variable Font +====================== + +This download contains Alegreya as both variable fonts and static fonts. + +Alegreya is a variable font with this axis: + wght + +This means all the styles are contained in these files: + Alegreya/Alegreya-VariableFont_wght.ttf + Alegreya/Alegreya-Italic-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Alegreya: + Alegreya/static/Alegreya-Regular.ttf + Alegreya/static/Alegreya-Medium.ttf + Alegreya/static/Alegreya-SemiBold.ttf + Alegreya/static/Alegreya-Bold.ttf + Alegreya/static/Alegreya-ExtraBold.ttf + Alegreya/static/Alegreya-Black.ttf + Alegreya/static/Alegreya-Italic.ttf + Alegreya/static/Alegreya-MediumItalic.ttf + Alegreya/static/Alegreya-SemiBoldItalic.ttf + Alegreya/static/Alegreya-BoldItalic.ttf + Alegreya/static/Alegreya-ExtraBoldItalic.ttf + Alegreya/static/Alegreya-BlackItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Black.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Black.ttf new file mode 100644 index 0000000..846ec96 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Black.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BlackItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BlackItalic.ttf new file mode 100644 index 0000000..ea26069 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BlackItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Bold.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Bold.ttf new file mode 100644 index 0000000..fe6306a Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Bold.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BoldItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BoldItalic.ttf new file mode 100644 index 0000000..1876276 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-BoldItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBold.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBold.ttf new file mode 100644 index 0000000..8efdcd0 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBold.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBoldItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBoldItalic.ttf new file mode 100644 index 0000000..7c9d661 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-ExtraBoldItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Italic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Italic.ttf new file mode 100644 index 0000000..20ea1d7 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Italic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Medium.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Medium.ttf new file mode 100644 index 0000000..d04ac69 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Medium.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-MediumItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-MediumItalic.ttf new file mode 100644 index 0000000..1425d18 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-MediumItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Regular.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Regular.ttf new file mode 100644 index 0000000..3270a9f Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-Regular.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBold.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBold.ttf new file mode 100644 index 0000000..b941c35 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBold.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBoldItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBoldItalic.ttf new file mode 100644 index 0000000..cc93f0c Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Alegreya/static/Alegreya-SemiBoldItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/LICENSE.txt b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/LICENSE.txt new file mode 100644 index 0000000..75b5248 --- /dev/null +++ b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/README.txt b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/README.txt new file mode 100644 index 0000000..ebe9bf2 --- /dev/null +++ b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/README.txt @@ -0,0 +1,77 @@ +Roboto Mono Variable Font +========================= + +This download contains Roboto Mono as both variable fonts and static fonts. + +Roboto Mono is a variable font with this axis: + wght + +This means all the styles are contained in these files: + Roboto_Mono/RobotoMono-VariableFont_wght.ttf + Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Roboto Mono: + Roboto_Mono/static/RobotoMono-Thin.ttf + Roboto_Mono/static/RobotoMono-ExtraLight.ttf + Roboto_Mono/static/RobotoMono-Light.ttf + Roboto_Mono/static/RobotoMono-Regular.ttf + Roboto_Mono/static/RobotoMono-Medium.ttf + Roboto_Mono/static/RobotoMono-SemiBold.ttf + Roboto_Mono/static/RobotoMono-Bold.ttf + Roboto_Mono/static/RobotoMono-ThinItalic.ttf + Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf + Roboto_Mono/static/RobotoMono-LightItalic.ttf + Roboto_Mono/static/RobotoMono-Italic.ttf + Roboto_Mono/static/RobotoMono-MediumItalic.ttf + Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf + Roboto_Mono/static/RobotoMono-BoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (LICENSE.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..1a4d694 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-VariableFont_wght.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-VariableFont_wght.ttf new file mode 100644 index 0000000..fc02de4 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/RobotoMono-VariableFont_wght.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Bold.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Bold.ttf new file mode 100644 index 0000000..d884128 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Bold.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-BoldItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-BoldItalic.ttf new file mode 100644 index 0000000..e9c4802 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-BoldItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLight.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLight.ttf new file mode 100644 index 0000000..9ff7ac6 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLight.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..9e962d4 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Italic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Italic.ttf new file mode 100644 index 0000000..61e5303 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Italic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Light.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Light.ttf new file mode 100644 index 0000000..4893662 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Light.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-LightItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-LightItalic.ttf new file mode 100644 index 0000000..39b7250 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-LightItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Medium.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Medium.ttf new file mode 100644 index 0000000..f6c149a Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Medium.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-MediumItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-MediumItalic.ttf new file mode 100644 index 0000000..70a1a75 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-MediumItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Regular.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Regular.ttf new file mode 100644 index 0000000..6df2b25 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Regular.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBold.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBold.ttf new file mode 100644 index 0000000..82ddc82 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBold.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..15b0846 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Thin.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Thin.ttf new file mode 100644 index 0000000..aeb997b Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-Thin.ttf differ diff --git a/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ThinItalic.ttf b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ThinItalic.ttf new file mode 100644 index 0000000..ab99e08 Binary files /dev/null and b/frontend/composeApp/src/commonMain/composeResources/font/Roboto_Mono/static/RobotoMono-ThinItalic.ttf differ diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/App.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/App.kt index 3b2f0b1..3b49883 100644 --- a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/App.kt +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/App.kt @@ -1,36 +1,32 @@ package com.jaytux.simd.frontend -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.painterResource +import com.jaytux.simd.frontend.theme.SimdTheme +import com.jaytux.simd.frontend.ui.DataState +import com.jaytux.simd.frontend.ui.ErrorSnackBar +import com.jaytux.simd.frontend.ui.topBar import org.jetbrains.compose.ui.tooling.preview.Preview -import frontend.composeapp.generated.resources.Res -import frontend.composeapp.generated.resources.compose_multiplatform - @Composable @Preview fun App() { - MaterialTheme { - var showContent by remember { mutableStateOf(false) } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Button(onClick = { showContent = !showContent }) { - Text("Click me!") - } - AnimatedVisibility(showContent) { - val greeting = remember { Greeting().greet() } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Image(painterResource(Res.drawable.compose_multiplatform), null) - Text("Compose: $greeting") - } + SimdTheme { + val scope = rememberCoroutineScope() + val snackState = remember { SnackbarHostState() } + val data = DataState(scope, { + println(it) + snackState.showSnackbar(it, duration = SnackbarDuration.Short) + }) + + Scaffold( + topBar = { topBar(data) }, + snackbarHost = { SnackbarHost(snackState) { ErrorSnackBar(it) } } + ) { + Surface(Modifier.padding(top = it.calculateTopPadding())) { + mainView(data) } } } diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Greeting.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Greeting.kt deleted file mode 100644 index dc92ff9..0000000 --- a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Greeting.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.jaytux.simd.frontend - -class Greeting { - fun greet(): String { - return "Hello, X!" - } -} \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/OrError.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/OrError.kt new file mode 100644 index 0000000..160202b --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/OrError.kt @@ -0,0 +1,34 @@ +package com.jaytux.simd.frontend + +import androidx.compose.runtime.Composable + +sealed class Either { + class Left(val value: L) : Either() + class Right(val value: R) : Either() + + fun fold(onLeft: (L) -> T, onRight: (R) -> T): T = when(this) { + is Left -> onLeft(value) + is Right -> onRight(value) + } + + suspend fun foldSuspend(onLeft: suspend (L) -> T, onRight: suspend (R) -> T): T = when(this) { + is Left -> onLeft(value) + is Right -> onRight(value) + } + + @Composable + fun foldCompose(onLeft: @Composable (L) -> T, onRight: @Composable (R) -> T): T = when(this) { + is Left -> onLeft(value) + is Right -> onRight(value) + } +} + +fun T.left() = Either.Left(this) +fun T.right() = Either.Right(this) + +fun Either.map(f: (R) -> X): Either = when(this) { + is Either.Left -> this + is Either.Right -> Either.Right(f(value)) +} + +typealias OrError = Either \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Platform.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Platform.kt index fffb17b..06ed0dc 100644 --- a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Platform.kt +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Platform.kt @@ -1,5 +1,10 @@ package com.jaytux.simd.frontend +import androidx.compose.runtime.Composable +import com.jaytux.simd.frontend.ui.DataState import io.ktor.client.* -expect fun getKtorClient(): HttpClient \ No newline at end of file +expect fun getKtorClient(builder: HttpClientConfig<*>.() -> Unit): HttpClient + +@Composable +expect fun mainView(data: DataState): Unit \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Util.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Util.kt new file mode 100644 index 0000000..aef5697 --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/Util.kt @@ -0,0 +1,6 @@ +package com.jaytux.simd.frontend + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State + +fun MutableState.immutable(): State = this \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Client.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Client.kt index 5323e37..125d8f8 100644 --- a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Client.kt +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Client.kt @@ -1,7 +1,15 @@ package com.jaytux.simd.frontend.client -import com.jaytux.simd.frontend.getKtorClient +import com.jaytux.simd.frontend.* import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.coroutines.delay import kotlinx.datetime.LocalDate import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable @@ -10,12 +18,14 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid @OptIn(ExperimentalUuidApi::class) object Client { - val httpClient: HttpClient by lazy { getKtorClient() } + val httpClient: HttpClient by lazy { getKtorClient{ install(ContentNegotiation) { json() } } } + val baseUrl = "https://simd.jaytux.com/api" object UUIDSerializer : KSerializer { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING) @@ -65,12 +75,114 @@ object Client { @Serializable data class Paginated(val page: Long, val totalPages: Long, val items: List) interface PaginatedResponse { + fun currentPage(): Long + fun totalPages(): Long fun currentItems(): List fun hasNextPage(): Boolean - suspend fun loadNextPage() + suspend fun loadNextPage(): OrError } - suspend fun getAll(): PaginatedResponse { - // + private inline suspend fun throttle(millis: Long, crossinline block: suspend () -> T): T { + delay(millis) + return block() } + + private suspend inline fun makeBasicRequest(url: String, crossinline builder: URLBuilder.() -> Unit = {}): OrError = try { + val resp = httpClient.get(url) { + header("Accept", "application/json") + expectSuccess = true + url { builder() } + } + resp.body().right() + } catch (e: Exception) { + "Failed to load $url: ${e.message ?: "Unknown error"}".left() + } + + private suspend inline fun getPaginated(url: String): OrError> { + val loader: suspend (Long?) -> OrError> = { page: Long? -> + makeBasicRequest>(url + (if (page != null) "/$page" else "")) + } + + return loader(null).map { p0 -> + object : PaginatedResponse { + var page = p0.page + val total = p0.totalPages + var current = p0.items + + override fun currentItems(): List = current + override fun hasNextPage(): Boolean = page < total + override fun currentPage(): Long = page + override fun totalPages(): Long = total + + override suspend fun loadNextPage(): OrError { + if(hasNextPage()) { + return loader(page + 1).map { + page = it.page + current = it.items + } + } + else { + return "No more pages (for URL ${url})".left() + } + } + + } + } + } + + private suspend inline fun getPaginatedQuery(url: String, crossinline addParams: URLBuilder.() -> Unit = {}): OrError> { + val loader: suspend (Long?) -> OrError> = { page: Long? -> + makeBasicRequest>(url + (if (page != null) "/$page" else "")) { + addParams() + if(page != null) parameters.append("page", "$page") + } + } + + return loader(null).map { p0 -> + object : PaginatedResponse { + var page = p0.page + val total = p0.totalPages + var current = p0.items + + override fun currentItems(): List = current + override fun hasNextPage(): Boolean = page < total + override fun currentPage(): Long = page + override fun totalPages(): Long = total + + override suspend fun loadNextPage(): OrError { + if(hasNextPage()) { + return loader(page + 1).map { + page = it.page + current = it.items + } + } + else { + return "No more pages (for URL ${url})".left() + } + } + + } + } + } + + suspend fun getAll(): OrError> = getPaginated("$baseUrl/all") + suspend fun getCpuid(): OrError> = getPaginated("$baseUrl/cpuid") + suspend fun getTech(): OrError> = getPaginated("$baseUrl/tech") + suspend fun getCategory(): OrError> = getPaginated("$baseUrl/category") + suspend fun getTypes(): OrError> = getPaginated("$baseUrl/types") + + suspend fun getSearch( + name: String? = null, returnT: String? = null, cpuid: List = listOf(), + tech: List = listOf(), category: List = listOf(), desc: String? = null + ): OrError> = getPaginatedQuery("$baseUrl/search") { + if(name != null) parameters.append("name", name) + if(returnT != null) parameters.append("returnT", returnT) + if(cpuid.isNotEmpty()) parameters.append("cpuid", Json.encodeToString(cpuid)) + if(tech.isNotEmpty()) parameters.append("tech", Json.encodeToString(tech)) + if(category.isNotEmpty()) parameters.append("category", Json.encodeToString(category)) + if(desc != null) parameters.append("desc", desc) + } + + suspend fun getDetails(id: Uuid): OrError = makeBasicRequest("$baseUrl/details/$id") + suspend fun getVersion(): OrError = makeBasicRequest("$baseUrl/version") } \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Loader.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Loader.kt new file mode 100644 index 0000000..18dddad --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/client/Loader.kt @@ -0,0 +1,53 @@ +package com.jaytux.simd.frontend.client + +import androidx.compose.runtime.mutableStateOf +import com.jaytux.simd.frontend.OrError +import com.jaytux.simd.frontend.immutable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +object Loader { + val progressInit = "Initializing..." + val progressFailed = "Finished (failed)" + val progressFinished = "Finished" + + fun CoroutineScope.loadAll( + client: suspend () -> OrError>, + onError: suspend (String) -> Unit, + onFinishSuccess: suspend (List) -> Unit, + onStatusChange: suspend (String) -> Unit, + onProgress: suspend (List) -> Unit = {}, + throttleBefore: Long = 0, + ) = launch { + delay(throttleBefore) // in case of UI-driven loading + + onStatusChange(progressInit) + + client().foldSuspend({ + onStatusChange(progressFailed) + onError(it) + }) { pg -> + onStatusChange("Loading ${pg.currentPage() + 1}/${pg.totalPages()}") + val res = pg.currentItems().toMutableList() + var anyError = false + + while (pg.hasNextPage() && !anyError) { + pg.loadNextPage().foldSuspend({ + onStatusChange(progressFailed) + onError(it) + anyError = true + }) { + onStatusChange("Loading ${pg.currentPage() + 1}/${pg.totalPages()}") + res.addAll(pg.currentItems()) + onProgress(res) + } + } + + if (!anyError) { + onStatusChange(progressFinished) + onFinishSuccess(res) + } + } + } +} \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Color.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Color.kt new file mode 100644 index 0000000..eff9065 --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Color.kt @@ -0,0 +1,225 @@ +package com.jaytux.simd.frontend.theme +import androidx.compose.ui.graphics.Color + +val primaryLight = Color(0xFF005CB9) +val onPrimaryLight = Color(0xFFFFFFFF) +val primaryContainerLight = Color(0xFF5B9BFF) +val onPrimaryContainerLight = Color(0xFF00326A) +val secondaryLight = Color(0xFF176648) +val onSecondaryLight = Color(0xFFFFFFFF) +val secondaryContainerLight = Color(0xFF367F5F) +val onSecondaryContainerLight = Color(0xFFE3FFED) +val tertiaryLight = Color(0xFF8C3D9B) +val onTertiaryLight = Color(0xFFFFFFFF) +val tertiaryContainerLight = Color(0xFFD07BDE) +val onTertiaryContainerLight = Color(0xFF5A036C) +val errorLight = Color(0xFFBA1A1A) +val onErrorLight = Color(0xFFFFFFFF) +val errorContainerLight = Color(0xFFFFDAD6) +val onErrorContainerLight = Color(0xFF93000A) +val backgroundLight = Color(0xFFF9F9FF) +val onBackgroundLight = Color(0xFF191C22) +val surfaceLight = Color(0xFFF9F9FF) +val onSurfaceLight = Color(0xFF191C22) +val surfaceVariantLight = Color(0xFFDEE2F1) +val onSurfaceVariantLight = Color(0xFF424752) +val outlineLight = Color(0xFF727784) +val outlineVariantLight = Color(0xFFC2C6D4) +val scrimLight = Color(0xFF000000) +val inverseSurfaceLight = Color(0xFF2E3037) +val inverseOnSurfaceLight = Color(0xFFEFF0F9) +val inversePrimaryLight = Color(0xFFAAC7FF) +val surfaceDimLight = Color(0xFFD8D9E2) +val surfaceBrightLight = Color(0xFFF9F9FF) +val surfaceContainerLowestLight = Color(0xFFFFFFFF) +val surfaceContainerLowLight = Color(0xFFF2F3FC) +val surfaceContainerLight = Color(0xFFECEDF6) +val surfaceContainerHighLight = Color(0xFFE7E8F0) +val surfaceContainerHighestLight = Color(0xFFE1E2EB) + +val primaryLightMediumContrast = Color(0xFF00356F) +val onPrimaryLightMediumContrast = Color(0xFFFFFFFF) +val primaryContainerLightMediumContrast = Color(0xFF1D6BCC) +val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF) +val secondaryLightMediumContrast = Color(0xFF003F29) +val onSecondaryLightMediumContrast = Color(0xFFFFFFFF) +val secondaryContainerLightMediumContrast = Color(0xFF307A5A) +val onSecondaryContainerLightMediumContrast = Color(0xFFFFFFFF) +val tertiaryLightMediumContrast = Color(0xFF5D096F) +val onTertiaryLightMediumContrast = Color(0xFFFFFFFF) +val tertiaryContainerLightMediumContrast = Color(0xFF9C4CAC) +val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF) +val errorLightMediumContrast = Color(0xFF740006) +val onErrorLightMediumContrast = Color(0xFFFFFFFF) +val errorContainerLightMediumContrast = Color(0xFFCF2C27) +val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF) +val backgroundLightMediumContrast = Color(0xFFF9F9FF) +val onBackgroundLightMediumContrast = Color(0xFF191C22) +val surfaceLightMediumContrast = Color(0xFFF9F9FF) +val onSurfaceLightMediumContrast = Color(0xFF0E1117) +val surfaceVariantLightMediumContrast = Color(0xFFDEE2F1) +val onSurfaceVariantLightMediumContrast = Color(0xFF313641) +val outlineLightMediumContrast = Color(0xFF4D525E) +val outlineVariantLightMediumContrast = Color(0xFF686D7A) +val scrimLightMediumContrast = Color(0xFF000000) +val inverseSurfaceLightMediumContrast = Color(0xFF2E3037) +val inverseOnSurfaceLightMediumContrast = Color(0xFFEFF0F9) +val inversePrimaryLightMediumContrast = Color(0xFFAAC7FF) +val surfaceDimLightMediumContrast = Color(0xFFC5C6CE) +val surfaceBrightLightMediumContrast = Color(0xFFF9F9FF) +val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF) +val surfaceContainerLowLightMediumContrast = Color(0xFFF2F3FC) +val surfaceContainerLightMediumContrast = Color(0xFFE7E8F0) +val surfaceContainerHighLightMediumContrast = Color(0xFFDBDCE5) +val surfaceContainerHighestLightMediumContrast = Color(0xFFD0D1DA) + +val primaryLightHighContrast = Color(0xFF002B5D) +val onPrimaryLightHighContrast = Color(0xFFFFFFFF) +val primaryContainerLightHighContrast = Color(0xFF004892) +val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF) +val secondaryLightHighContrast = Color(0xFF003321) +val onSecondaryLightHighContrast = Color(0xFFFFFFFF) +val secondaryContainerLightHighContrast = Color(0xFF005439) +val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF) +val tertiaryLightHighContrast = Color(0xFF4F0060) +val onTertiaryLightHighContrast = Color(0xFFFFFFFF) +val tertiaryContainerLightHighContrast = Color(0xFF732584) +val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF) +val errorLightHighContrast = Color(0xFF600004) +val onErrorLightHighContrast = Color(0xFFFFFFFF) +val errorContainerLightHighContrast = Color(0xFF98000A) +val onErrorContainerLightHighContrast = Color(0xFFFFFFFF) +val backgroundLightHighContrast = Color(0xFFF9F9FF) +val onBackgroundLightHighContrast = Color(0xFF191C22) +val surfaceLightHighContrast = Color(0xFFF9F9FF) +val onSurfaceLightHighContrast = Color(0xFF000000) +val surfaceVariantLightHighContrast = Color(0xFFDEE2F1) +val onSurfaceVariantLightHighContrast = Color(0xFF000000) +val outlineLightHighContrast = Color(0xFF272C37) +val outlineVariantLightHighContrast = Color(0xFF444955) +val scrimLightHighContrast = Color(0xFF000000) +val inverseSurfaceLightHighContrast = Color(0xFF2E3037) +val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF) +val inversePrimaryLightHighContrast = Color(0xFFAAC7FF) +val surfaceDimLightHighContrast = Color(0xFFB7B8C1) +val surfaceBrightLightHighContrast = Color(0xFFF9F9FF) +val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF) +val surfaceContainerLowLightHighContrast = Color(0xFFEFF0F9) +val surfaceContainerLightHighContrast = Color(0xFFE1E2EB) +val surfaceContainerHighLightHighContrast = Color(0xFFD3D4DC) +val surfaceContainerHighestLightHighContrast = Color(0xFFC5C6CE) + +val primaryDark = Color(0xFFAAC7FF) +val onPrimaryDark = Color(0xFF002F65) +val primaryContainerDark = Color(0xFF5B9BFF) +val onPrimaryContainerDark = Color(0xFF00326A) +val secondaryDark = Color(0xFF8CD6B0) +val onSecondaryDark = Color(0xFF003825) +val secondaryContainerDark = Color(0xFF367F5F) +val onSecondaryContainerDark = Color(0xFFE3FFED) +val tertiaryDark = Color(0xFFF6ADFF) +val onTertiaryDark = Color(0xFF560068) +val tertiaryContainerDark = Color(0xFFD07BDE) +val onTertiaryContainerDark = Color(0xFF5A036C) +val errorDark = Color(0xFFFFB4AB) +val onErrorDark = Color(0xFF690005) +val errorContainerDark = Color(0xFF93000A) +val onErrorContainerDark = Color(0xFFFFDAD6) +val backgroundDark = Color(0xFF111319) +val onBackgroundDark = Color(0xFFE1E2EB) +val surfaceDark = Color(0xFF111319) +val onSurfaceDark = Color(0xFFE1E2EB) +val surfaceVariantDark = Color(0xFF424752) +val onSurfaceVariantDark = Color(0xFFC2C6D4) +val outlineDark = Color(0xFF8C919E) +val outlineVariantDark = Color(0xFF424752) +val scrimDark = Color(0xFF000000) +val inverseSurfaceDark = Color(0xFFE1E2EB) +val inverseOnSurfaceDark = Color(0xFF2E3037) +val inversePrimaryDark = Color(0xFF005CB9) +val surfaceDimDark = Color(0xFF111319) +val surfaceBrightDark = Color(0xFF363940) +val surfaceContainerLowestDark = Color(0xFF0B0E14) +val surfaceContainerLowDark = Color(0xFF191C22) +val surfaceContainerDark = Color(0xFF1D2026) +val surfaceContainerHighDark = Color(0xFF272A30) +val surfaceContainerHighestDark = Color(0xFF32353B) + +val primaryDarkMediumContrast = Color(0xFFCDDDFF) +val onPrimaryDarkMediumContrast = Color(0xFF002551) +val primaryContainerDarkMediumContrast = Color(0xFF5B9BFF) +val onPrimaryContainerDarkMediumContrast = Color(0xFF000C22) +val secondaryDarkMediumContrast = Color(0xFFA1ECC5) +val onSecondaryDarkMediumContrast = Color(0xFF002C1C) +val secondaryContainerDarkMediumContrast = Color(0xFF569F7C) +val onSecondaryContainerDarkMediumContrast = Color(0xFF000000) +val tertiaryDarkMediumContrast = Color(0xFFFDCDFF) +val onTertiaryDarkMediumContrast = Color(0xFF450054) +val tertiaryContainerDarkMediumContrast = Color(0xFFD07BDE) +val onTertiaryContainerDarkMediumContrast = Color(0xFF1C0023) +val errorDarkMediumContrast = Color(0xFFFFD2CC) +val onErrorDarkMediumContrast = Color(0xFF540003) +val errorContainerDarkMediumContrast = Color(0xFFFF5449) +val onErrorContainerDarkMediumContrast = Color(0xFF000000) +val backgroundDarkMediumContrast = Color(0xFF111319) +val onBackgroundDarkMediumContrast = Color(0xFFE1E2EB) +val surfaceDarkMediumContrast = Color(0xFF111319) +val onSurfaceDarkMediumContrast = Color(0xFFFFFFFF) +val surfaceVariantDarkMediumContrast = Color(0xFF424752) +val onSurfaceVariantDarkMediumContrast = Color(0xFFD8DCEB) +val outlineDarkMediumContrast = Color(0xFFADB2C0) +val outlineVariantDarkMediumContrast = Color(0xFF8B909D) +val scrimDarkMediumContrast = Color(0xFF000000) +val inverseSurfaceDarkMediumContrast = Color(0xFFE1E2EB) +val inverseOnSurfaceDarkMediumContrast = Color(0xFF272A30) +val inversePrimaryDarkMediumContrast = Color(0xFF004690) +val surfaceDimDarkMediumContrast = Color(0xFF111319) +val surfaceBrightDarkMediumContrast = Color(0xFF42444B) +val surfaceContainerLowestDarkMediumContrast = Color(0xFF05070D) +val surfaceContainerLowDarkMediumContrast = Color(0xFF1B1E24) +val surfaceContainerDarkMediumContrast = Color(0xFF25282E) +val surfaceContainerHighDarkMediumContrast = Color(0xFF303339) +val surfaceContainerHighestDarkMediumContrast = Color(0xFF3B3E44) + +val primaryDarkHighContrast = Color(0xFFEBF0FF) +val onPrimaryDarkHighContrast = Color(0xFF000000) +val primaryContainerDarkHighContrast = Color(0xFFA4C3FF) +val onPrimaryContainerDarkHighContrast = Color(0xFF000B20) +val secondaryDarkHighContrast = Color(0xFFBAFFDA) +val onSecondaryDarkHighContrast = Color(0xFF000000) +val secondaryContainerDarkHighContrast = Color(0xFF88D2AD) +val onSecondaryContainerDarkHighContrast = Color(0xFF000E07) +val tertiaryDarkHighContrast = Color(0xFFFFEAFC) +val onTertiaryDarkHighContrast = Color(0xFF000000) +val tertiaryContainerDarkHighContrast = Color(0xFFF5A7FF) +val onTertiaryContainerDarkHighContrast = Color(0xFF1A0022) +val errorDarkHighContrast = Color(0xFFFFECE9) +val onErrorDarkHighContrast = Color(0xFF000000) +val errorContainerDarkHighContrast = Color(0xFFFFAEA4) +val onErrorContainerDarkHighContrast = Color(0xFF220001) +val backgroundDarkHighContrast = Color(0xFF111319) +val onBackgroundDarkHighContrast = Color(0xFFE1E2EB) +val surfaceDarkHighContrast = Color(0xFF111319) +val onSurfaceDarkHighContrast = Color(0xFFFFFFFF) +val surfaceVariantDarkHighContrast = Color(0xFF424752) +val onSurfaceVariantDarkHighContrast = Color(0xFFFFFFFF) +val outlineDarkHighContrast = Color(0xFFEBF0FF) +val outlineVariantDarkHighContrast = Color(0xFFBEC2D1) +val scrimDarkHighContrast = Color(0xFF000000) +val inverseSurfaceDarkHighContrast = Color(0xFFE1E2EB) +val inverseOnSurfaceDarkHighContrast = Color(0xFF000000) +val inversePrimaryDarkHighContrast = Color(0xFF004690) +val surfaceDimDarkHighContrast = Color(0xFF111319) +val surfaceBrightDarkHighContrast = Color(0xFF4D5057) +val surfaceContainerLowestDarkHighContrast = Color(0xFF000000) +val surfaceContainerLowDarkHighContrast = Color(0xFF1D2026) +val surfaceContainerDarkHighContrast = Color(0xFF2E3037) +val surfaceContainerHighDarkHighContrast = Color(0xFF393B42) +val surfaceContainerHighestDarkHighContrast = Color(0xFF44474E) + + + + + + + diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Theme.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Theme.kt new file mode 100644 index 0000000..5e8f96c --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Theme.kt @@ -0,0 +1,259 @@ +package com.jaytux.simd.frontend.theme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color + +private val lightScheme = lightColorScheme( + primary = primaryLight, + onPrimary = onPrimaryLight, + primaryContainer = primaryContainerLight, + onPrimaryContainer = onPrimaryContainerLight, + secondary = secondaryLight, + onSecondary = onSecondaryLight, + secondaryContainer = secondaryContainerLight, + onSecondaryContainer = onSecondaryContainerLight, + tertiary = tertiaryLight, + onTertiary = onTertiaryLight, + tertiaryContainer = tertiaryContainerLight, + onTertiaryContainer = onTertiaryContainerLight, + error = errorLight, + onError = onErrorLight, + errorContainer = errorContainerLight, + onErrorContainer = onErrorContainerLight, + background = backgroundLight, + onBackground = onBackgroundLight, + surface = surfaceLight, + onSurface = onSurfaceLight, + surfaceVariant = surfaceVariantLight, + onSurfaceVariant = onSurfaceVariantLight, + outline = outlineLight, + outlineVariant = outlineVariantLight, + scrim = scrimLight, + inverseSurface = inverseSurfaceLight, + inverseOnSurface = inverseOnSurfaceLight, + inversePrimary = inversePrimaryLight, + surfaceDim = surfaceDimLight, + surfaceBright = surfaceBrightLight, + surfaceContainerLowest = surfaceContainerLowestLight, + surfaceContainerLow = surfaceContainerLowLight, + surfaceContainer = surfaceContainerLight, + surfaceContainerHigh = surfaceContainerHighLight, + surfaceContainerHighest = surfaceContainerHighestLight, +) + +private val darkScheme = darkColorScheme( + primary = primaryDark, + onPrimary = onPrimaryDark, + primaryContainer = primaryContainerDark, + onPrimaryContainer = onPrimaryContainerDark, + secondary = secondaryDark, + onSecondary = onSecondaryDark, + secondaryContainer = secondaryContainerDark, + onSecondaryContainer = onSecondaryContainerDark, + tertiary = tertiaryDark, + onTertiary = onTertiaryDark, + tertiaryContainer = tertiaryContainerDark, + onTertiaryContainer = onTertiaryContainerDark, + error = errorDark, + onError = onErrorDark, + errorContainer = errorContainerDark, + onErrorContainer = onErrorContainerDark, + background = backgroundDark, + onBackground = onBackgroundDark, + surface = surfaceDark, + onSurface = onSurfaceDark, + surfaceVariant = surfaceVariantDark, + onSurfaceVariant = onSurfaceVariantDark, + outline = outlineDark, + outlineVariant = outlineVariantDark, + scrim = scrimDark, + inverseSurface = inverseSurfaceDark, + inverseOnSurface = inverseOnSurfaceDark, + inversePrimary = inversePrimaryDark, + surfaceDim = surfaceDimDark, + surfaceBright = surfaceBrightDark, + surfaceContainerLowest = surfaceContainerLowestDark, + surfaceContainerLow = surfaceContainerLowDark, + surfaceContainer = surfaceContainerDark, + surfaceContainerHigh = surfaceContainerHighDark, + surfaceContainerHighest = surfaceContainerHighestDark, +) + +private val mediumContrastLightColorScheme = lightColorScheme( + primary = primaryLightMediumContrast, + onPrimary = onPrimaryLightMediumContrast, + primaryContainer = primaryContainerLightMediumContrast, + onPrimaryContainer = onPrimaryContainerLightMediumContrast, + secondary = secondaryLightMediumContrast, + onSecondary = onSecondaryLightMediumContrast, + secondaryContainer = secondaryContainerLightMediumContrast, + onSecondaryContainer = onSecondaryContainerLightMediumContrast, + tertiary = tertiaryLightMediumContrast, + onTertiary = onTertiaryLightMediumContrast, + tertiaryContainer = tertiaryContainerLightMediumContrast, + onTertiaryContainer = onTertiaryContainerLightMediumContrast, + error = errorLightMediumContrast, + onError = onErrorLightMediumContrast, + errorContainer = errorContainerLightMediumContrast, + onErrorContainer = onErrorContainerLightMediumContrast, + background = backgroundLightMediumContrast, + onBackground = onBackgroundLightMediumContrast, + surface = surfaceLightMediumContrast, + onSurface = onSurfaceLightMediumContrast, + surfaceVariant = surfaceVariantLightMediumContrast, + onSurfaceVariant = onSurfaceVariantLightMediumContrast, + outline = outlineLightMediumContrast, + outlineVariant = outlineVariantLightMediumContrast, + scrim = scrimLightMediumContrast, + inverseSurface = inverseSurfaceLightMediumContrast, + inverseOnSurface = inverseOnSurfaceLightMediumContrast, + inversePrimary = inversePrimaryLightMediumContrast, + surfaceDim = surfaceDimLightMediumContrast, + surfaceBright = surfaceBrightLightMediumContrast, + surfaceContainerLowest = surfaceContainerLowestLightMediumContrast, + surfaceContainerLow = surfaceContainerLowLightMediumContrast, + surfaceContainer = surfaceContainerLightMediumContrast, + surfaceContainerHigh = surfaceContainerHighLightMediumContrast, + surfaceContainerHighest = surfaceContainerHighestLightMediumContrast, +) + +private val highContrastLightColorScheme = lightColorScheme( + primary = primaryLightHighContrast, + onPrimary = onPrimaryLightHighContrast, + primaryContainer = primaryContainerLightHighContrast, + onPrimaryContainer = onPrimaryContainerLightHighContrast, + secondary = secondaryLightHighContrast, + onSecondary = onSecondaryLightHighContrast, + secondaryContainer = secondaryContainerLightHighContrast, + onSecondaryContainer = onSecondaryContainerLightHighContrast, + tertiary = tertiaryLightHighContrast, + onTertiary = onTertiaryLightHighContrast, + tertiaryContainer = tertiaryContainerLightHighContrast, + onTertiaryContainer = onTertiaryContainerLightHighContrast, + error = errorLightHighContrast, + onError = onErrorLightHighContrast, + errorContainer = errorContainerLightHighContrast, + onErrorContainer = onErrorContainerLightHighContrast, + background = backgroundLightHighContrast, + onBackground = onBackgroundLightHighContrast, + surface = surfaceLightHighContrast, + onSurface = onSurfaceLightHighContrast, + surfaceVariant = surfaceVariantLightHighContrast, + onSurfaceVariant = onSurfaceVariantLightHighContrast, + outline = outlineLightHighContrast, + outlineVariant = outlineVariantLightHighContrast, + scrim = scrimLightHighContrast, + inverseSurface = inverseSurfaceLightHighContrast, + inverseOnSurface = inverseOnSurfaceLightHighContrast, + inversePrimary = inversePrimaryLightHighContrast, + surfaceDim = surfaceDimLightHighContrast, + surfaceBright = surfaceBrightLightHighContrast, + surfaceContainerLowest = surfaceContainerLowestLightHighContrast, + surfaceContainerLow = surfaceContainerLowLightHighContrast, + surfaceContainer = surfaceContainerLightHighContrast, + surfaceContainerHigh = surfaceContainerHighLightHighContrast, + surfaceContainerHighest = surfaceContainerHighestLightHighContrast, +) + +private val mediumContrastDarkColorScheme = darkColorScheme( + primary = primaryDarkMediumContrast, + onPrimary = onPrimaryDarkMediumContrast, + primaryContainer = primaryContainerDarkMediumContrast, + onPrimaryContainer = onPrimaryContainerDarkMediumContrast, + secondary = secondaryDarkMediumContrast, + onSecondary = onSecondaryDarkMediumContrast, + secondaryContainer = secondaryContainerDarkMediumContrast, + onSecondaryContainer = onSecondaryContainerDarkMediumContrast, + tertiary = tertiaryDarkMediumContrast, + onTertiary = onTertiaryDarkMediumContrast, + tertiaryContainer = tertiaryContainerDarkMediumContrast, + onTertiaryContainer = onTertiaryContainerDarkMediumContrast, + error = errorDarkMediumContrast, + onError = onErrorDarkMediumContrast, + errorContainer = errorContainerDarkMediumContrast, + onErrorContainer = onErrorContainerDarkMediumContrast, + background = backgroundDarkMediumContrast, + onBackground = onBackgroundDarkMediumContrast, + surface = surfaceDarkMediumContrast, + onSurface = onSurfaceDarkMediumContrast, + surfaceVariant = surfaceVariantDarkMediumContrast, + onSurfaceVariant = onSurfaceVariantDarkMediumContrast, + outline = outlineDarkMediumContrast, + outlineVariant = outlineVariantDarkMediumContrast, + scrim = scrimDarkMediumContrast, + inverseSurface = inverseSurfaceDarkMediumContrast, + inverseOnSurface = inverseOnSurfaceDarkMediumContrast, + inversePrimary = inversePrimaryDarkMediumContrast, + surfaceDim = surfaceDimDarkMediumContrast, + surfaceBright = surfaceBrightDarkMediumContrast, + surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast, + surfaceContainerLow = surfaceContainerLowDarkMediumContrast, + surfaceContainer = surfaceContainerDarkMediumContrast, + surfaceContainerHigh = surfaceContainerHighDarkMediumContrast, + surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast, +) + +private val highContrastDarkColorScheme = darkColorScheme( + primary = primaryDarkHighContrast, + onPrimary = onPrimaryDarkHighContrast, + primaryContainer = primaryContainerDarkHighContrast, + onPrimaryContainer = onPrimaryContainerDarkHighContrast, + secondary = secondaryDarkHighContrast, + onSecondary = onSecondaryDarkHighContrast, + secondaryContainer = secondaryContainerDarkHighContrast, + onSecondaryContainer = onSecondaryContainerDarkHighContrast, + tertiary = tertiaryDarkHighContrast, + onTertiary = onTertiaryDarkHighContrast, + tertiaryContainer = tertiaryContainerDarkHighContrast, + onTertiaryContainer = onTertiaryContainerDarkHighContrast, + error = errorDarkHighContrast, + onError = onErrorDarkHighContrast, + errorContainer = errorContainerDarkHighContrast, + onErrorContainer = onErrorContainerDarkHighContrast, + background = backgroundDarkHighContrast, + onBackground = onBackgroundDarkHighContrast, + surface = surfaceDarkHighContrast, + onSurface = onSurfaceDarkHighContrast, + surfaceVariant = surfaceVariantDarkHighContrast, + onSurfaceVariant = onSurfaceVariantDarkHighContrast, + outline = outlineDarkHighContrast, + outlineVariant = outlineVariantDarkHighContrast, + scrim = scrimDarkHighContrast, + inverseSurface = inverseSurfaceDarkHighContrast, + inverseOnSurface = inverseOnSurfaceDarkHighContrast, + inversePrimary = inversePrimaryDarkHighContrast, + surfaceDim = surfaceDimDarkHighContrast, + surfaceBright = surfaceBrightDarkHighContrast, + surfaceContainerLowest = surfaceContainerLowestDarkHighContrast, + surfaceContainerLow = surfaceContainerLowDarkHighContrast, + surfaceContainer = surfaceContainerDarkHighContrast, + surfaceContainerHigh = surfaceContainerHighDarkHighContrast, + surfaceContainerHighest = surfaceContainerHighestDarkHighContrast, +) + +@Immutable +data class ColorFamily( + val color: Color, + val onColor: Color, + val colorContainer: Color, + val onColorContainer: Color +) + +val unspecified_scheme = ColorFamily( + Color.Unspecified, Color.Unspecified, Color.Unspecified, Color.Unspecified +) + +@Composable +fun SimdTheme( + content: @Composable() () -> Unit +) { + MaterialTheme( + colorScheme = darkScheme, + typography = buildTypography(), + content = content + ) +} + diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Type.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Type.kt new file mode 100644 index 0000000..4821b3e --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/theme/Type.kt @@ -0,0 +1,43 @@ +package com.jaytux.simd.frontend.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Typography +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontFamily +import com.jaytux.simd.frontend.App +import frontend.composeapp.generated.resources.Alegreya +import frontend.composeapp.generated.resources.Res +import frontend.composeapp.generated.resources.Roboto_Mono +import frontend.composeapp.generated.resources.allFontResources +import org.jetbrains.compose.resources.Font + +@Composable +fun Roboto() = FontFamily(Font(Res.font.Roboto_Mono)) + +@Composable +fun Alegreya() = FontFamily(Font(Res.font.Alegreya)) + +@Composable +fun buildTypography(): Typography { + val baseline = MaterialTheme.typography + val displayFontFamily = Alegreya() + val bodyFontFamily = Roboto() + val AppTypography = Typography( + displayLarge = baseline.displayLarge.copy(fontFamily = displayFontFamily), + displayMedium = baseline.displayMedium.copy(fontFamily = displayFontFamily), + displaySmall = baseline.displaySmall.copy(fontFamily = displayFontFamily), + headlineLarge = baseline.headlineLarge.copy(fontFamily = displayFontFamily), + headlineMedium = baseline.headlineMedium.copy(fontFamily = displayFontFamily), + headlineSmall = baseline.headlineSmall.copy(fontFamily = displayFontFamily), + titleLarge = baseline.titleLarge.copy(fontFamily = displayFontFamily), + titleMedium = baseline.titleMedium.copy(fontFamily = displayFontFamily), + titleSmall = baseline.titleSmall.copy(fontFamily = displayFontFamily), + bodyLarge = baseline.bodyLarge.copy(fontFamily = bodyFontFamily), + bodyMedium = baseline.bodyMedium.copy(fontFamily = bodyFontFamily), + bodySmall = baseline.bodySmall.copy(fontFamily = bodyFontFamily), + labelLarge = baseline.labelLarge.copy(fontFamily = bodyFontFamily), + labelMedium = baseline.labelMedium.copy(fontFamily = bodyFontFamily), + labelSmall = baseline.labelSmall.copy(fontFamily = bodyFontFamily), + ) + return AppTypography +} \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/DataState.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/DataState.kt new file mode 100644 index 0000000..4b9c32c --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/DataState.kt @@ -0,0 +1,175 @@ +package com.jaytux.simd.frontend.ui + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import com.jaytux.simd.frontend.Either +import com.jaytux.simd.frontend.client.Client +import com.jaytux.simd.frontend.client.Loader +import com.jaytux.simd.frontend.client.Loader.loadAll +import com.jaytux.simd.frontend.immutable +import com.jaytux.simd.frontend.left +import com.jaytux.simd.frontend.right +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.launch +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid + +@OptIn(ExperimentalUuidApi::class) +class DataState( + val scope: CoroutineScope, + val addSnackBar: suspend (message: String) -> Unit, +) { + data class SubState( + val stateMut: MutableState = mutableStateOf(""), + val dataMut: MutableState> = mutableStateOf(listOf()) + ) { + val state = stateMut.immutable() + val data = dataMut.immutable() + } + + // --- Intrinsic Summaries --- + private val _summary = SubState() + val summaryState = _summary.state + val summaries = _summary.data + + // --- CPUIDs --- + private val _cpuid = SubState() + val cpuidState = _cpuid.state + val cpuid = _cpuid.data + private val _selectedCpuids = mutableStateOf(listOf()) + val selectedCpuids = _selectedCpuids.immutable() + + // --- Techs --- + private val _techs = SubState() + val techsState = _techs.state + val techs = _techs.data + private val _selectedTechs = mutableStateOf(listOf()) + val selectedTechs = _selectedTechs.immutable() + + // --- CppTypes --- + private val _cppTypes = SubState() + val cppTypesState = _cppTypes.state + val cppTypes = _cppTypes.data + private var filterByType: String? = null + + // --- Categories --- + private val _categories = SubState() + val categoriesState = _categories.state + val categories = _categories.data + private val _selectedCats = mutableStateOf(listOf()) + val selectedCats = _selectedCats.immutable() + + // --- Details --- + private val _intrinsics = mutableMapOf?>>() + private val _intrinsicLoaders = mutableMapOf() + + // --- Version --- + private val _version = mutableStateOf(null) + val version = _version.immutable() + + // --- Filtering --- + private var _filterJob: Job? = null + private val _filterData = mutableStateOf(listOf()) + val filterData = _filterData.immutable() + + init { + _filterJob = scope.loadAll( + client = { Client.getAll() }, + onError = addSnackBar, + onFinishSuccess = { /*_summary.dataMut.value = it*/ _filterData.value = it }, + onStatusChange = { _summary.stateMut.value = it }, + onProgress = { /*_summary.dataMut.value = it*/ _filterData.value = it } + ) + scope.loadAll( + client = { Client.getCpuid() }, + onError = addSnackBar, + onFinishSuccess = { _cpuid.dataMut.value = it }, + onStatusChange = { _cpuid.stateMut.value = it } + ) + scope.loadAll( + client = { Client.getTech() }, + onError = addSnackBar, + onFinishSuccess = { _techs.dataMut.value = it }, + onStatusChange = { _techs.stateMut.value = it } + ) + scope.loadAll( + client = { Client.getCategory() }, + onError = addSnackBar, + onFinishSuccess = { _categories.dataMut.value = it }, + onStatusChange = { _categories.stateMut.value = it } + ) + scope.loadAll( + client = { Client.getTypes() }, + onError = addSnackBar, + onFinishSuccess = { _cppTypes.dataMut.value = it }, + onStatusChange = { _cppTypes.stateMut.value = it } + ) + + scope.launch { + Client.getVersion().foldSuspend(addSnackBar) { + _version.value = it + } + } + } + + operator fun get(uuid: Uuid): State?> = + _intrinsics.getOrPut(uuid) { mutableStateOf(null) } + + fun toggleTech(idx: Int) { + if (idx in _selectedTechs.value) _selectedTechs.value -= idx + else _selectedTechs.value += idx + } + + fun toggleCategory(idx: Int) { + if (idx in _selectedCats.value) _selectedCats.value -= idx + else _selectedCats.value += idx + } + + fun toggleCpuid(idx: Int) { + if (idx in _selectedCpuids.value) _selectedCpuids.value -= idx + else _selectedCpuids.value += idx + } + + fun setReturn(type: String) { + filterByType = if(type !in cppTypes.value) null else type + } + + fun loadDetails(uuid: Uuid) { + val current = _intrinsicLoaders[uuid] + if(current != null && !current.isActive) return + + _intrinsicLoaders[uuid] = scope.launch { + Client.getDetails(uuid).foldSuspend({ + val msg = "Failed to load details for $uuid: $it" + addSnackBar(msg) + _intrinsics.getOrPut(uuid) { mutableStateOf(null) }.value = msg.left() + }) { + _intrinsics.getOrPut(uuid) { mutableStateOf(null) }.value = it.right() + } + } + } + + fun doFilter(name: String, desc: String) { + _filterJob?.cancel() + _filterJob = scope.loadAll( + client = { + Client.getSearch( + name = name.ifBlank { null }, + returnT = filterByType, + cpuid = _selectedCpuids.value.map { cpuid.value[it] }, + tech = _selectedTechs.value.map { techs.value[it] }, + category = _selectedCats.value.map { categories.value[it] }, + desc = desc.ifBlank { null } + ) + }, + onError = addSnackBar, + onFinishSuccess = { _filterData.value = it }, + onStatusChange = {}, + onProgress = { _filterData.value = it }, + throttleBefore = 250L + ) + } +} \ No newline at end of file diff --git a/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/Widgets.kt b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/Widgets.kt new file mode 100644 index 0000000..a648121 --- /dev/null +++ b/frontend/composeApp/src/commonMain/kotlin/com/jaytux/simd/frontend/ui/Widgets.kt @@ -0,0 +1,386 @@ +package com.jaytux.simd.frontend.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.PopupProperties +import com.composables.icons.lucide.* +import com.jaytux.simd.frontend.OrError +import com.jaytux.simd.frontend.client.Client +import com.jaytux.simd.frontend.client.Loader +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlin.uuid.ExperimentalUuidApi + +@Composable +fun fontSizeDp(style: TextStyle = LocalTextStyle.current) = with(LocalDensity.current) { + style.fontSize.toDp() +} + +@Composable +fun Spinner(text: String, style: TextStyle = LocalTextStyle.current) = Row { + CircularProgressIndicator(Modifier.size(fontSizeDp(style) * 2).scale(0.5f)) + Spacer(Modifier.width(5.dp)) + Text(text, Modifier.align(Alignment.CenterVertically), style = style) +} + +@Composable +fun ErrorSnackBar(data: SnackbarData) { + Snackbar( + containerColor = MaterialTheme.colorScheme.error, + contentColor = MaterialTheme.colorScheme.onError, + ) { + Box(Modifier.padding(5.dp)) { + Text(data.visuals.message, modifier = Modifier.align(Alignment.Center)) + } + } +} + +@Composable +fun MicroHeader(text: String, modifier: Modifier = Modifier) = + Text(text, modifier, style = MaterialTheme.typography.bodyLarge) + +@Composable +fun Collapsible(expanded: Boolean, onClick: () -> Unit, content: @Composable () -> Unit) { + Row(Modifier.clickable { onClick() }) { + Icon(if(expanded) Lucide.ChevronDown else Lucide.ChevronRight, "Expand/Collapse") + Spacer(Modifier.width(10.dp)) + content() + } +} + +@Composable +fun Checkable(checked: Boolean, onClick: () -> Unit, content: @Composable () -> Unit) { + Row(Modifier.clickable { onClick() }) { + Icon(if(checked) Lucide.SquareCheckBig else Lucide.Square, "Check/Uncheck") + Spacer(Modifier.width(10.dp)) + content() + } +} + +@Composable +fun Indented(content: @Composable ColumnScope.() -> Unit) { + Row(Modifier.padding(start = 20.dp)) { + Column { + content() + } + } +} + +fun LazyListScope.FilterBlock( + title: String, + expanded: Boolean, + status: String, + options: List, + selected: List, + onToggleExpand: () -> Unit, + onToggleSelect: (Int) -> Unit, + renderT: @Composable (T) -> Unit +) { + item { + Collapsible(expanded, onToggleExpand) { + MicroHeader("$title (${selected.size} selected)") + } + } + + if(expanded) { + if(options.isEmpty()) { + item { + Indented { + Spinner(status) + } + } + } + else { + itemsIndexed(options) { i, t -> + Indented { + Checkable(i in selected, { onToggleSelect(i) }) { + renderT(t) + } + } + } + } + } +} + +@Composable +fun topBar(data: DataState) = Surface(tonalElevation = 10.dp, shadowElevation = 10.dp, color = MaterialTheme.colorScheme.primaryContainer) { + val version by data.version + Box(Modifier.fillMaxWidth().padding(10.dp)) { + Box(Modifier.align(Alignment.Center)) { + Text( + "C/C++ (SIMD) Intrinsics", + style = MaterialTheme.typography.headlineLarge + ) + } + + version?.let { + Column(Modifier.align(Alignment.CenterEnd)) { + Row { + Text( + "Intel data: ${it.intelVersion} (last update: ${it.intelUpdate})", + style = MaterialTheme.typography.labelSmall + ) + // TODO: add other versioning data (AMD, ARM, ...) when added to DB/backend + } + + Text("Last database update: ${it.scrapeDate}", style = MaterialTheme.typography.labelSmall) + } + } + } +} + +@Composable +fun ColumnScope.FilterColumn(data: DataState) { + var expandTech by remember { mutableStateOf(false) } + var expandCategory by remember { mutableStateOf(false) } + var expandCpuid by remember { mutableStateOf(false) } + val techs by data.techs; val techMsg by data.techsState; val techSel by data.selectedTechs + val cats by data.categories; val catMsg by data.categoriesState; val catSel by data.selectedCats + val cpuid by data.cpuid; val cpuidMsg by data.cpuidState; val cpuidSel by data.selectedCpuids + + Text("Filter intrinsics by:", style = MaterialTheme.typography.headlineSmall) + + LazyColumn { + FilterBlock( + "ISA extensions", expandTech, techMsg, techs, techSel, + { expandTech = !expandTech }, { data.toggleTech(it) } + ) { Text(it) } + FilterBlock( + "Categories", expandCategory, catMsg, cats, catSel, + { expandCategory = !expandCategory }, { data.toggleCategory(it) } + ) { Text(it) } + FilterBlock( + "CPUIDs", expandCpuid, cpuidMsg, cpuid, cpuidSel, + { expandCpuid = !expandCpuid }, { data.toggleCpuid(it) } + ) { Text(it) } + } +} + +@Composable +fun IntrinsicCard( + summary: Client.IntrinsicSummary, + details: OrError?, + requestLoad: suspend (Client.IntrinsicSummary) -> Unit +) { + var expanded by remember { mutableStateOf(false) } + val scope = rememberCoroutineScope() + Surface( + Modifier.fillMaxWidth().padding(5.dp).clickable { + expanded = !expanded + if(expanded && details == null) scope.launch { requestLoad(summary) } + }, + tonalElevation = 2.dp, + shadowElevation = 2.dp, + shape = MaterialTheme.shapes.medium + ) { + Column(Modifier.padding(10.dp)) { + Text(summary.name, style = MaterialTheme.typography.headlineSmall) + if(expanded) { + Indented { + details?.foldCompose({ + Text(it, color = MaterialTheme.colorScheme.error) + }) { + Text("Synopsis") + Indented { + Text("${it.returnType} ${it.name}(${it.params.joinToString(", ") { p -> "${p.type} ${p.name}" }}) [${it.category}]") + it.cpuid?.let { cpuid -> Text("CPUID: $cpuid") } + } + + Spacer(Modifier.height(5.dp)) + Text("Description") + Indented { + Text(it.description) + it.instructions?.let { insn -> + Text("Instruction(s):") + Indented { + insn.forEach { ins -> + Text("${ins.mnemonic} ${ins.form ?: ""}") + } + } + } + } + + it.operations?.let { ops -> + Spacer(Modifier.height(5.dp)) + Text("Operations") + Indented { + Surface(Modifier.fillMaxWidth(), color = MaterialTheme.colorScheme.surfaceDim) { + Text(ops) + } + } + } + + it.performance?.let { perf -> + if(perf.isEmpty()) return@let + Spacer(Modifier.height(5.dp)) + Text("Performance") + Indented { + Row { + Column { + Text("Architecture") + perf.forEach { p -> Text(p.platform) } + } + + Spacer(Modifier.width(20.dp)) + + Column { + Text("Latency (cycles)") + perf.forEach { p -> Text(p.latency?.toString() ?: "-") } + } + + Spacer(Modifier.width(20.dp)) + + Column { + Text("Throughput (CPI)") + perf.forEach { p -> Text(p.throughput?.toString() ?: "-") } + } + } + } + } + } ?: Text("Loading details...", style = MaterialTheme.typography.bodySmall) + } + } + } + } +} + +@OptIn(ExperimentalUuidApi::class) +@Composable +fun ColumnScope.IntrinsicColumn(data: DataState) { + var nameFilter by remember { mutableStateOf("") } + var descFilter by remember { mutableStateOf("") } + var retFilter by remember { mutableStateOf("") } + val intrinsicState by data.summaryState + val intrinsicList by data.filterData + val typeOptions by data.cppTypes + val typeMsg by data.cppTypesState + + var expandFilter by remember { mutableStateOf(false) } + + OutlinedTextField( + nameFilter, { nameFilter = it; data.doFilter(nameFilter, descFilter) }, + Modifier.fillMaxWidth(), + leadingIcon = { Icon(Lucide.SearchCode, "Search") }, + label = { Text("Filter by intrinsic name...") } + ) + + Text( + (if (expandFilter) "Hide" else "Show") + " additional filters", + Modifier.clickable { expandFilter = !expandFilter }.align(Alignment.End), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary, + textDecoration = TextDecoration.Underline + ) + + if (expandFilter) { + var showingOptions by remember { mutableStateOf(false) } + OutlinedTextField( + retFilter, { retFilter = it; showingOptions = true }, + Modifier.clickable { showingOptions = true }.fillMaxWidth(0.66f).onFocusChanged { + showingOptions = it.isFocused + if(!it.isFocused) data.setReturn(retFilter) + }, + trailingIcon = { + Icon(if (showingOptions) Lucide.ChevronUp else Lucide.ChevronDown, "Show options") + }, + label = { Text("Filter by return type...") }, + isError = retFilter !in typeOptions + ) + DropdownMenu( + showingOptions, { showingOptions = false }, + properties = PopupProperties() + ) { + if (typeOptions.isEmpty()) { + DropdownMenuItem( + { Spinner(typeMsg) }, { retFilter = "" } + ) + } else { + DropdownMenuItem( + { Text("(none)") }, { retFilter = "" } + ) + typeOptions.filter{ retFilter in it }.take(10).forEach { it -> + DropdownMenuItem( + { Text(it) }, { retFilter = it } + ) + } + } + } + + OutlinedTextField( + descFilter, + { descFilter = it; data.doFilter(nameFilter, descFilter) }, + Modifier.fillMaxWidth(), + label = { Text("Filter by description...") }) + } + + if(intrinsicList.isEmpty()) { + Box(Modifier.fillMaxSize()) { + Column(Modifier.align(Alignment.Center)) { + Text("Loading intrinsics...") + Spinner(intrinsicState) + } + } + } + else { + if(intrinsicState != Loader.progressFinished) { + Spinner(intrinsicState, MaterialTheme.typography.bodySmall) + } + + LazyColumn { + items(intrinsicList) { it -> + val details by data[it.id] + IntrinsicCard(it, details) { data.loadDetails(it.id) } + } + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/MainView.jvm.kt b/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/MainView.jvm.kt new file mode 100644 index 0000000..b38b2ab --- /dev/null +++ b/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/MainView.jvm.kt @@ -0,0 +1,35 @@ +package com.jaytux.simd.frontend + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CornerSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.jaytux.simd.frontend.ui.DataState +import com.jaytux.simd.frontend.ui.FilterColumn +import com.jaytux.simd.frontend.ui.IntrinsicColumn +import com.jaytux.simd.frontend.ui.topBar + +@Composable +actual fun mainView(data: DataState) = Row { + Surface( + Modifier.weight(0.25f).fillMaxSize(), + tonalElevation = 3.dp, + shadowElevation = 3.dp, + color = MaterialTheme.colorScheme.primary, + shape = MaterialTheme.shapes.medium.copy(topStart = CornerSize(0.dp), topEnd = CornerSize(0.dp)) + ) { + Column(Modifier.padding(5.dp)) { + FilterColumn(data) + } + } + Column(Modifier.weight(0.66f).padding(15.dp)) { + IntrinsicColumn(data) + } +} \ No newline at end of file diff --git a/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/Platform.jvm.kt b/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/Platform.jvm.kt index b7fddb1..0794c28 100644 --- a/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/Platform.jvm.kt +++ b/frontend/composeApp/src/desktopMain/kotlin/com/jaytux/simd/frontend/Platform.jvm.kt @@ -2,5 +2,9 @@ package com.jaytux.simd.frontend import io.ktor.client.* import io.ktor.client.engine.cio.* +import java.awt.Desktop +import java.net.URI -actual fun getKtorClient(): HttpClient = HttpClient(CIO) \ No newline at end of file +actual fun getKtorClient(builder: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(CIO) { + builder() +} \ No newline at end of file diff --git a/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/MainView.wasmJs.kt b/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/MainView.wasmJs.kt new file mode 100644 index 0000000..104417a --- /dev/null +++ b/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/MainView.wasmJs.kt @@ -0,0 +1,14 @@ +package com.jaytux.simd.frontend + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import com.jaytux.simd.frontend.ui.DataState +import com.jaytux.simd.frontend.ui.topBar + +@Composable +actual fun mainView(data: DataState) = Row { + Column { } + Column { } +} \ No newline at end of file diff --git a/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/Platform.wasmJs.kt b/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/Platform.wasmJs.kt index a12ba8d..b0c4e4b 100644 --- a/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/Platform.wasmJs.kt +++ b/frontend/composeApp/src/wasmJsMain/kotlin/com/jaytux/simd/frontend/Platform.wasmJs.kt @@ -1,6 +1,10 @@ package com.jaytux.simd.frontend +import androidx.compose.runtime.Composable import io.ktor.client.* import io.ktor.client.engine.js.* +import kotlinx.browser.window -actual fun getKtorClient(): HttpClient = HttpClient(Js) \ No newline at end of file +actual fun getKtorClient(builder: HttpClientConfig<*>.() -> Unit): HttpClient = HttpClient(Js) { + builder() +} \ No newline at end of file diff --git a/frontend/gradle/libs.versions.toml b/frontend/gradle/libs.versions.toml index 34b12b8..f0e8658 100644 --- a/frontend/gradle/libs.versions.toml +++ b/frontend/gradle/libs.versions.toml @@ -9,6 +9,7 @@ dotenv = "6.5.1" serialization = "1.8.1" logback = "1.5.6" json = "20231013" +ui-text-google-fonts = "1.8.0" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -22,14 +23,17 @@ ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" } ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } +ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } -dotenv = { module = "io.github.cdimascio:dotenv-kotlin", version.ref = "dotenv" } json = { module = "org.json:json", version.ref = "json" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version = "0.6.2" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" } logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } +material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-multiplatform" } +lucide = { module = "com.composables:icons-lucide", version="1.0.0" } + [plugins] composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }