├── gradle.properties ├── .gitignore ├── img └── image.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── jsMain │ ├── resources │ │ ├── favicon-32x32.png │ │ ├── filetree │ │ │ ├── icon.png │ │ │ └── src.css │ │ ├── binaries │ │ │ └── gradle-wrapper │ │ ├── ic_info.svg │ │ ├── ic_fb.svg │ │ ├── ic_jb_blog.svg │ │ ├── ic_feed.svg │ │ ├── ic_insta.svg │ │ ├── ic_twitter.svg │ │ ├── ic_linkedin.svg │ │ ├── ic_youtube.svg │ │ ├── index.html │ │ ├── ic_lang.svg │ │ ├── ic_kotlin_logo.svg │ │ ├── hljs.css │ │ ├── filetree.css │ │ ├── i1.svg │ │ └── logos.css │ └── kotlin │ │ └── org │ │ └── jetbrains │ │ └── webwiz │ │ ├── FileSaverJs.kt │ │ ├── HighlightJs.kt │ │ ├── JSZip.kt │ │ ├── style │ │ ├── WtSection.kt │ │ ├── WtContainer.kt │ │ ├── WtRow.kt │ │ ├── Stylesheet.kt │ │ ├── WtCol.kt │ │ ├── WtOffest.kt │ │ └── WtText.kt │ │ ├── content │ │ ├── Header.kt │ │ ├── IntroSection.kt │ │ ├── CodeSamplesSwitcher.kt │ │ ├── Footer.kt │ │ ├── Chips.kt │ │ └── WizardSection.kt │ │ ├── components │ │ └── Layout.kt │ │ └── Main.kt ├── commonMain │ └── kotlin │ │ └── org │ │ └── jetbrains │ │ └── webwiz │ │ ├── models │ │ ├── KotlinVersions.kt │ │ ├── SourceSetType.kt │ │ ├── NativeTargetLibrary.kt │ │ ├── GradlePlugins.kt │ │ ├── Targets.kt │ │ ├── SingleTargetLibrary.kt │ │ ├── ProjectInfo.kt │ │ └── KmpLibraries.kt │ │ └── generator │ │ ├── files │ │ ├── Gitignore.kt │ │ ├── AndroidManifestXml.kt │ │ ├── SettingsGradle.kt │ │ ├── ApplicationKt.kt │ │ ├── GradleProperties.kt │ │ ├── GradleWrapper.kt │ │ ├── PlatformKt.kt │ │ ├── RootBuildGradle.kt │ │ ├── PlatformTestKt.kt │ │ ├── GradleBat.kt │ │ ├── Gradlew.kt │ │ └── ModuleBuildGradle.kt │ │ └── generator.kt └── commonTest │ └── kotlin │ └── org │ └── jetbrains │ └── webwiz │ └── generator │ └── ProjectBuilderTest.kt ├── settings.gradle.kts ├── .github └── workflows │ └── publish.yaml ├── README.md ├── gradlew.bat └── gradlew /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | local.properties 3 | .gradle 4 | .idea -------------------------------------------------------------------------------- /img/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oianmol/kmp-web-wizard/master/img/image.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oianmol/kmp-web-wizard/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/jsMain/resources/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oianmol/kmp-web-wizard/master/src/jsMain/resources/favicon-32x32.png -------------------------------------------------------------------------------- /src/jsMain/resources/filetree/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oianmol/kmp-web-wizard/master/src/jsMain/resources/filetree/icon.png -------------------------------------------------------------------------------- /src/jsMain/resources/binaries/gradle-wrapper: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oianmol/kmp-web-wizard/master/src/jsMain/resources/binaries/gradle-wrapper -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | } 6 | } 7 | rootProject.name = "kmp-web-wizard" -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/KotlinVersions.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | enum class KotlinVersion(val versionName: String) { 4 | Stable("1.6.0"), 5 | EAP("1.6.0"), 6 | Dev("1.6.20-dev-967") 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/jsMain/resources/ic_info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/FileSaverJs.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz 2 | 3 | import org.w3c.files.Blob 4 | 5 | @JsModule("file-saver") 6 | @JsNonModule 7 | external class FileSaverJs { 8 | companion object { 9 | fun saveAs(blob: Blob, fileName: String) 10 | } 11 | } -------------------------------------------------------------------------------- /src/jsMain/resources/ic_fb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/jsMain/resources/ic_jb_blog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/SourceSetType.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | enum class SourceSetType(val sourceSetTypeName: String) { 4 | MAIN("Main"), 5 | TEST("Test") 6 | } 7 | 8 | enum class SourceSetDelegate(val delegate: String) { 9 | CREATING("creating"), 10 | GETTING("getting") 11 | } -------------------------------------------------------------------------------- /src/jsMain/resources/ic_feed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/jsMain/resources/ic_insta.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/HighlightJs.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz 2 | 3 | import org.w3c.dom.HTMLElement 4 | 5 | @JsName("hljs") 6 | @JsModule("highlight.js") 7 | @JsNonModule 8 | external class HighlightJs { 9 | companion object { 10 | fun highlightElement(block: HTMLElement) 11 | } 12 | } 13 | 14 | fun HTMLElement.setHighlightedCode(code: String) { 15 | innerText = code 16 | HighlightJs.highlightElement(this) 17 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/JSZip.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz 2 | 3 | import org.khronos.webgl.ArrayBuffer 4 | import kotlin.js.Promise 5 | 6 | @JsModule("jszip") 7 | @JsNonModule 8 | external class JSZip { 9 | fun file(name: String, content: String): JSZip 10 | fun file(name: String, content: String, options: dynamic): JSZip 11 | fun file(name: String, content: ArrayBuffer): JSZip 12 | fun generateAsync(type: dynamic): Promise 13 | } 14 | -------------------------------------------------------------------------------- /src/jsMain/resources/ic_twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/Gitignore.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class Gitignore : ProjectFile { 6 | override val path = ".gitignore" 7 | override val content: String 8 | get() = """ 9 | *.iml 10 | .gradle 11 | /local.properties 12 | .idea 13 | .DS_Store 14 | /build 15 | */build 16 | /captures 17 | .externalNativeBuild 18 | .cxx 19 | local.properties 20 | """.trimIndent() 21 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/NativeTargetLibrary.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | import org.jetbrains.webwiz.models.SourceSetType.MAIN 4 | 5 | // Dependencies in here will be available for all native targets 6 | enum class NativeTargetLibrary( 7 | val userName: String, 8 | val dep: String, 9 | val sourceSetType: SourceSetType 10 | ) { 11 | SQLDELIGHT_DRIVER_NATIVE( 12 | "SQDelight Native Driver", 13 | "com.squareup.sqldelight:native-driver:1.5.3", 14 | MAIN 15 | ), 16 | } -------------------------------------------------------------------------------- /src/jsMain/resources/ic_linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/AndroidManifestXml.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | import org.jetbrains.webwiz.models.ProjectInfo 5 | 6 | class AndroidManifestXml(val projectInfo: ProjectInfo) : ProjectFile { 7 | override val path = "${projectInfo.moduleName}/src/androidMain/AndroidManifest.xml" 8 | override val content: String 9 | get() = """ 10 | 11 | 12 | """.trimIndent() 13 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/SettingsGradle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class SettingsGradle(val projectName: String, val moduleName: String) : ProjectFile { 6 | override val path = "settings.gradle.kts" 7 | override val content: String 8 | get() = """ 9 | pluginManagement { 10 | repositories { 11 | google() 12 | gradlePluginPortal() 13 | mavenCentral() 14 | } 15 | } 16 | 17 | rootProject.name = "${projectName.replace(' ', '_')}" 18 | include(":$moduleName") 19 | """.trimIndent() 20 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/ApplicationKt.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | import org.jetbrains.webwiz.models.ProjectInfo 5 | 6 | class ApplicationKt(val projectInfo: ProjectInfo) : ProjectFile { 7 | override val path = "${projectInfo.moduleName}/src/jvmMain/kotlin" + 8 | "/${projectInfo.packageName.replace('.', '/')}" + 9 | "/Application.kt" 10 | override val content: String 11 | get() = """ 12 | package ${projectInfo.packageName} 13 | 14 | fun main() { 15 | println("Hello world!") 16 | } 17 | """.trimIndent() 18 | } -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | build-and-deploy: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2.3.1 17 | 18 | - name: Test 19 | run: | 20 | ./gradlew check 21 | 22 | - name: Build 23 | run: | 24 | ./gradlew jsBrowserProductionWebpack 25 | 26 | - name: Deploy 27 | uses: JamesIves/github-pages-deploy-action@4.1.5 28 | with: 29 | branch: gh-pages 30 | folder: build/distributions 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin Multiplatform Wizard 2 | 3 | [![](https://raw.githubusercontent.com/terrakok/kmp-web-wizard/e41ac0245f9e1aabb17206b3e2eaa831559dcad2/img/image.png)](https://terrakok.github.io/kmp-web-wizard/) 4 | 5 | This is JB hackathon project. 6 | Try it out [here](https://terrakok.github.io/kmp-web-wizard/) 7 | 8 | It is a fun project with bleeding-edge technologies: Kotlin JS + Compose for Web. 9 | 10 | If you see some problems (especially with CSS 😅) or want to add some cool feature PR is welcome! :) 11 | 12 | Team: 13 | [@terrakok](https://github.com/terrakok) 14 | [@vkormushkin](https://github.com/vkormushkin) 15 | [@ALD110](https://github.com/ALD110) 16 | [@atyrin](https://github.com/atyrin) -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/GradleProperties.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class GradleProperties : ProjectFile { 6 | override val path = "gradle.properties" 7 | override val content: String 8 | get() = """ 9 | #Gradle 10 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" 11 | 12 | #Kotlin 13 | kotlin.code.style=official 14 | 15 | #Android 16 | android.useAndroidX=true 17 | 18 | #MPP 19 | kotlin.mpp.enableGranularSourceSetsMetadata=true 20 | kotlin.native.enableDependencyPropagation=false 21 | kotlin.mpp.enableCInteropCommonization=true 22 | """.trimIndent() 23 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/GradlePlugins.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | enum class GradlePlugin( 4 | val mandatory: Set, 5 | val forbidden: Set, 6 | val userName: String 7 | ) { 8 | PUBLISH( 9 | emptySet(), 10 | emptySet(), 11 | "Maven Publish" 12 | ), 13 | APPLICATION( 14 | setOf(Target.JVM), 15 | setOf(Target.ANDROID), 16 | "JVM Application" 17 | ), 18 | SQL_DELIGHT( 19 | emptySet(), 20 | setOf(Target.WASM), 21 | "SQLDelight" 22 | ); 23 | 24 | fun canBeApplied(targets: Set): Boolean = 25 | targets.containsAll(mandatory) && !targets.any { it in forbidden } 26 | } -------------------------------------------------------------------------------- /src/jsMain/resources/ic_youtube.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/jsMain/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kotlin MPP Web Wizard 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/GradleWrapper.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class GradleWrapperProperties(val gradleVersion: String) : ProjectFile { 6 | override val path = "gradle/wrapper/gradle-wrapper.properties" 7 | override val content: String 8 | get() = """ 9 | distributionBase=GRADLE_USER_HOME 10 | distributionPath=wrapper/dists 11 | distributionUrl=https\://services.gradle.org/distributions/gradle-$gradleVersion-bin.zip 12 | zipStoreBase=GRADLE_USER_HOME 13 | zipStorePath=wrapper/dists 14 | """.trimIndent() 15 | } 16 | 17 | class GradleWrapperJar : ProjectFile { 18 | override val path = "gradle/wrapper/gradle-wrapper.jar" 19 | override val content = "/* binary file */" 20 | } -------------------------------------------------------------------------------- /src/jsMain/resources/ic_lang.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtSection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.* 4 | 5 | object WtSections : StyleSheet(AppStylesheet) { 6 | 7 | val wtSection by style { 8 | boxSizing("border-box") 9 | paddingBottom(96.px) 10 | paddingTop(1.px) 11 | property( 12 | propertyName = "padding-bottom", 13 | value = "calc(4*${AppCSSVariables.wtOffsetTopUnit.value(24.px)})" 14 | ) 15 | backgroundColor(Color("#fff")) 16 | } 17 | 18 | val wtSectionBgGrayLight by style { 19 | backgroundColor(Color("#f4f4f4")) 20 | backgroundColor(AppCSSVariables.wtColorGreyLight.value()) 21 | } 22 | 23 | val wtSectionBgGrayDark by style { 24 | backgroundColor(Color("#323236")) 25 | backgroundColor(AppCSSVariables.wtColorGreyDark.value()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/jsMain/resources/ic_kotlin_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/jsMain/resources/filetree/src.css: -------------------------------------------------------------------------------- 1 | /* glue: 0.11.1 hash: ff145c7220 */ 2 | .sprite-src-folder-c, 3 | .sprite-src-folder-o { 4 | background-image: url('icon.png'); 5 | background-repeat: no-repeat; 6 | } 7 | 8 | .sprite-src-folder-c { 9 | background-position: 0 0; 10 | width: 33px; 11 | height: 33px; 12 | } 13 | 14 | .sprite-src-folder-o { 15 | background-position: 0 -33px; 16 | width: 30px; 17 | height: 30px; 18 | } 19 | 20 | @media screen and (-webkit-min-device-pixel-ratio: 1.0), screen and (min--moz-device-pixel-ratio: 1.0), screen and (-o-min-device-pixel-ratio: 100/100), screen and (min-device-pixel-ratio: 1.0), screen and (min-resolution: 1.0dppx) { 21 | .sprite-src-folder-c, 22 | .sprite-src-folder-o { 23 | background-image: url('icon.png'); 24 | -webkit-background-size: 33px 63px; 25 | -moz-background-size: 33px 63px; 26 | background-size: 33px 63px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtContainer.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.* 4 | 5 | object WtContainer : StyleSheet(AppStylesheet) { 6 | val wtContainer by style { 7 | property("margin-left", "auto") 8 | property("margin-right", "auto") 9 | boxSizing("border-box") 10 | paddingLeft(22.px) 11 | paddingRight(22.px) 12 | maxWidth(1276.px) 13 | 14 | media(mediaMaxWidth(640.px)) { 15 | self style { 16 | maxWidth(100.percent) 17 | paddingLeft(6.px) 18 | paddingRight(16.px) 19 | } 20 | } 21 | 22 | media(mediaMaxWidth(1276.px)) { 23 | self style { 24 | maxWidth(996.px) 25 | paddingLeft(2.px) 26 | paddingRight(22.px) 27 | } 28 | } 29 | 30 | media(mediaMaxWidth(1000.px)) { 31 | self style { 32 | maxWidth(100.percent) 33 | paddingLeft(2.px) 34 | paddingRight(22.px) 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtRow.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.* 4 | 5 | object WtRows : StyleSheet(AppStylesheet) { 6 | 7 | val wtRow by style { 8 | AppCSSVariables.wtHorizontalLayoutGutter(0.px) 9 | display(DisplayStyle.Flex) 10 | flexWrap(FlexWrap.Wrap) 11 | 12 | property( 13 | "margin-right", 14 | "calc(-1*${AppCSSVariables.wtHorizontalLayoutGutter.value()})" 15 | ) 16 | property( 17 | "margin-left", 18 | "calc(-1*${AppCSSVariables.wtHorizontalLayoutGutter.value()})" 19 | ) 20 | boxSizing("border-box") 21 | } 22 | 23 | val wtRowSizeM by style { 24 | AppCSSVariables.wtHorizontalLayoutGutter(16.px) 25 | 26 | media(mediaMaxWidth(640.px)) { 27 | self style { 28 | AppCSSVariables.wtHorizontalLayoutGutter(8.px) 29 | } 30 | } 31 | } 32 | 33 | val wtRowSizeXs by style { 34 | AppCSSVariables.wtHorizontalLayoutGutter(6.px) 35 | } 36 | 37 | val wtRowSmAlignItemsCenter by style { 38 | self style { 39 | alignItems(AlignItems.Center) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/Header.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.attributes.ATarget 5 | import org.jetbrains.compose.web.attributes.target 6 | import org.jetbrains.compose.web.dom.A 7 | import org.jetbrains.compose.web.dom.Div 8 | import org.jetbrains.compose.web.dom.Section 9 | import org.jetbrains.webwiz.style.WtCols 10 | import org.jetbrains.webwiz.style.WtContainer 11 | import org.jetbrains.webwiz.style.WtRows 12 | import org.jetbrains.webwiz.style.WtSections 13 | 14 | @Composable 15 | fun Header() { 16 | Section(attrs = { 17 | classes(WtSections.wtSectionBgGrayDark) 18 | }) { 19 | Div({ classes(WtContainer.wtContainer) }) { 20 | Div({ 21 | classes(WtRows.wtRow, WtRows.wtRowSizeM) 22 | }) { 23 | Logo() 24 | } 25 | } 26 | } 27 | } 28 | 29 | @Composable 30 | private fun Logo() { 31 | Div(attrs = { 32 | classes(WtCols.wtColInline) 33 | }) { 34 | A(attrs = { 35 | target(ATarget.Blank) 36 | }, href = "https://www.jetbrains.com/") { 37 | Div(attrs = { 38 | classes("jetbrains-logo", "_logo-jetbrains-square", "_size-3") 39 | }) {} 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/jsMain/resources/hljs.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * StackOverflow.com light style 3 | * 4 | * @stackoverflow/stacks v0.56.0 5 | * https://github.com/StackExchange/Stacks 6 | */ 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: .5em; 11 | color: #2f3337; 12 | background: #f6f6f6 13 | } 14 | 15 | .hljs-comment { 16 | color: #656e77 17 | } 18 | 19 | .hljs-attr, .hljs-doctag, .hljs-keyword, .hljs-meta, .hljs-meta-keyword, .hljs-section, .hljs-selector-class, .hljs-selector-pseudo, .hljs-selector-tag { 20 | color: #015692; 21 | font-weight: bold; 22 | } 23 | 24 | .hljs-attribute { 25 | color: #803378 26 | } 27 | 28 | .hljs-built_in, .hljs-literal, .hljs-name, .hljs-number, .hljs-quote, .hljs-selector-id, .hljs-template-tag, .hljs-title, .hljs-type { 29 | color: #b75501 30 | } 31 | 32 | .hljs-title { 33 | font-style: italic; 34 | } 35 | 36 | .hljs-link, .hljs-meta-string, .hljs-regexp, .hljs-selector-attr, .hljs-string, .hljs-symbol, .hljs-template-variable, .hljs-variable { 37 | color: #54790d 38 | } 39 | 40 | .hljs-bullet, .hljs-code { 41 | color: #535a60 42 | } 43 | 44 | .hljs-deletion { 45 | color: #c02d2e 46 | } 47 | 48 | .hljs-addition { 49 | color: #2f6f44 50 | } 51 | 52 | .hljs-emphasis { 53 | font-style: italic 54 | } 55 | 56 | .hljs-strong { 57 | font-weight: 700 58 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/Targets.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | enum class Target(val targetName: String, val userName: String) { 4 | JVM("jvm", "JVM"), 5 | ANDROID("android", "Android"), 6 | JS("js", "JS"), 7 | IOS("ios", "iOS"), 8 | TV_OS("tvos", "tvOS"), 9 | WATCH_OS("watchos", "watchOS"), 10 | LINUX("linux", "Linux"), 11 | MACOS("macos", "macOS"), 12 | WINDOWS("windows", "Windows"), 13 | WASM("wasm", "WASM"), 14 | ANDROID_NATIVE("androidNative", "Android Native") 15 | } 16 | 17 | private val NativeTargets = setOf( 18 | Target.WASM, 19 | Target.ANDROID_NATIVE, 20 | Target.LINUX, 21 | Target.MACOS, 22 | Target.IOS, 23 | Target.TV_OS, 24 | Target.WATCH_OS, 25 | Target.WINDOWS 26 | ) 27 | 28 | private val CommonNativeTargets = setOf( 29 | Target.LINUX, 30 | Target.MACOS, 31 | Target.IOS, 32 | Target.TV_OS, 33 | Target.WATCH_OS, 34 | Target.WINDOWS 35 | ) 36 | 37 | fun Target.isJvm() = this in setOf(Target.JVM, Target.ANDROID) 38 | 39 | fun Set.isNativeTargetPresent() = this.any { it in NativeTargets } 40 | fun Set.isCommonNativeTargetPresent() = this.any { it in CommonNativeTargets } 41 | fun Set.isAndroidTargetPresent() = this.any { it == Target.ANDROID } 42 | fun Set.isJvmTargetPresent() = this.any { it.isJvm() } 43 | -------------------------------------------------------------------------------- /src/jsMain/resources/filetree.css: -------------------------------------------------------------------------------- 1 | /** 2 | * filetree.css 3 | * */ 4 | 5 | .filetree input[type="checkbox"] { 6 | display: none; 7 | } 8 | 9 | .filetree ul { 10 | height: 0; 11 | overflow: hidden; 12 | } 13 | 14 | .filetree > li input:checked ~ ul { 15 | height: auto; 16 | } 17 | 18 | .filetree li { 19 | list-style: none; 20 | } 21 | 22 | .filetree label { 23 | padding-left: 33px; 24 | line-height: 33px; 25 | display: inline-block; 26 | } 27 | 28 | /** 29 | * Icon 30 | * */ 31 | .filetree label { 32 | background-image: url('./filetree/icon.png'); 33 | background-repeat: no-repeat; 34 | } 35 | 36 | .filetree input[type="checkbox"] + label { 37 | background-position: 0 0; 38 | width: 33px; 39 | height: 33px; 40 | } 41 | 42 | .filetree input[type="checkbox"]:checked + label { 43 | background-position: 0 -33px; 44 | width: 30px; 45 | height: 30px; 46 | } 47 | 48 | @media screen and (-webkit-min-device-pixel-ratio: 1.0), screen and (min--moz-device-pixel-ratio: 1.0), screen and (-o-min-device-pixel-ratio: 100/100), screen and (min-device-pixel-ratio: 1.0), screen and (min-resolution: 1.0dppx) { 49 | filetree label { 50 | background-image: url('./filetree/icon.png'); 51 | -webkit-background-size: 33px 63px; 52 | -moz-background-size: 33px 63px; 53 | background-size: 33px 63px; 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/SingleTargetLibrary.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | import org.jetbrains.webwiz.models.SourceSetType.MAIN 4 | 5 | enum class SingleTargetLibrary( 6 | val target: Target, 7 | val userName: String, 8 | val dep: String, 9 | val sourceSetType: SourceSetType 10 | ) { 11 | KTOR_CLIENT_IOS( 12 | Target.IOS, 13 | "Ktor iOS Client", 14 | "io.ktor:ktor-client-ios:1.6.7", 15 | MAIN 16 | ), 17 | KTOR_CLIENT_OKHTTP( 18 | Target.ANDROID, 19 | "Ktor OkHttp Client", 20 | "io.ktor:ktor-client-okhttp:1.6.7", 21 | MAIN 22 | ), 23 | KTOR_CLIENT_JVM( 24 | Target.JVM, 25 | "Ktor JVM Client", 26 | "io.ktor:ktor-client-jvm:1.6.7", 27 | MAIN 28 | ), 29 | KTOR_CLIENT_JS( 30 | Target.JS, 31 | "Ktor JS Client", 32 | "io.ktor:ktor-client-js:1.6.7", 33 | MAIN 34 | ), 35 | SQLDELIGHT_DRIVER_ANDROID( 36 | Target.ANDROID, 37 | "SQLDelight Android Driver", 38 | "com.squareup.sqldelight:android-driver:1.5.3", 39 | MAIN 40 | ), 41 | SQLDELIGHT_DRIVER_JVM( 42 | Target.JVM, 43 | "SQLDelight JVM Driver", 44 | "com.squareup.sqldelight:sqlite-driver:1.5.3", 45 | MAIN 46 | ), 47 | SQLDELIGHT_DRIVER_JS( 48 | Target.JS, 49 | "SQDelight JS Driver", 50 | "com.squareup.sqldelight:sqljs-driver:1.5.3", 51 | MAIN 52 | ), 53 | } 54 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/components/Layout.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.components 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.css.* 5 | import org.jetbrains.compose.web.dom.Div 6 | import org.jetbrains.compose.web.dom.Main 7 | import org.jetbrains.compose.web.dom.Section 8 | import org.jetbrains.webwiz.style.WtContainer 9 | import org.jetbrains.webwiz.style.WtOffsets 10 | import org.jetbrains.webwiz.style.WtSections 11 | 12 | @Composable 13 | fun Layout(content: @Composable () -> Unit) { 14 | Div({ 15 | style { 16 | display(DisplayStyle.Flex) 17 | flexDirection(FlexDirection.Column) 18 | height(100.percent) 19 | margin(0.px) 20 | boxSizing("border-box") 21 | } 22 | }) { 23 | content() 24 | } 25 | } 26 | 27 | @Composable 28 | fun MainContentLayout(content: @Composable () -> Unit) { 29 | Main({ 30 | style { 31 | flex("1 0 auto") 32 | boxSizing("border-box") 33 | } 34 | }) { 35 | content() 36 | } 37 | } 38 | 39 | @Composable 40 | fun ContainerInSection(sectionThemeStyleClass: String? = null, content: @Composable () -> Unit) { 41 | Section({ 42 | if (sectionThemeStyleClass != null) { 43 | classes(WtSections.wtSection, sectionThemeStyleClass) 44 | } else { 45 | classes(WtSections.wtSection) 46 | } 47 | }) { 48 | Div({ 49 | classes(WtContainer.wtContainer, WtOffsets.wtTopOffset96) 50 | }) { 51 | content() 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/PlatformKt.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | import org.jetbrains.webwiz.models.ProjectInfo 5 | import org.jetbrains.webwiz.models.Target 6 | 7 | class CommonPlatformKt(val projectInfo: ProjectInfo) : ProjectFile { 8 | override val path = "${projectInfo.moduleName}/src/commonMain/kotlin" + 9 | "/${projectInfo.packageName.replace('.', '/')}" + 10 | "/Platform.kt" 11 | override val content: String 12 | get() = """ 13 | package ${projectInfo.packageName} 14 | 15 | expect val platform: String 16 | 17 | class Greeting { 18 | fun greeting() = "Hello, ${'$'}platform!" 19 | } 20 | """.trimIndent() 21 | } 22 | 23 | class TargetPlatformKt(val target: Target, val projectInfo: ProjectInfo) : ProjectFile { 24 | override val path = "${projectInfo.moduleName}/src/${target.targetName}Main/kotlin" + 25 | "/${projectInfo.packageName.replace('.', '/')}" + 26 | "/Platform.kt" 27 | override val content: String 28 | get() = """ 29 | package ${projectInfo.packageName} 30 | 31 | actual val platform: String = "${target.targetName}" 32 | """.trimIndent() 33 | } 34 | 35 | class IntermediatePlatformKt(val intermediateName: String, val projectInfo: ProjectInfo) : ProjectFile { 36 | override val path = "${projectInfo.moduleName}/src/${intermediateName}Main/kotlin" + 37 | "/${projectInfo.packageName.replace('.', '/')}" + 38 | "/Platform.kt" 39 | override val content: String 40 | get() = """ 41 | package ${projectInfo.packageName} 42 | 43 | """.trimIndent() 44 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/ProjectInfo.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | data class ProjectInfo( 4 | val projectName: String, 5 | val moduleName: String, 6 | val packageName: String, 7 | val kotlinVersion: KotlinVersion, 8 | val targets: Set, 9 | val dependencies: Set, 10 | val singleTargetDependencies: Set, 11 | val nativeTargetLibraries: Set, 12 | val gradlePlugins: Set, 13 | val enableTests: Boolean 14 | ) { 15 | fun validate() { 16 | require(!moduleName.contains(' ')) { 17 | "module name contains space character" 18 | } 19 | require(gradlePlugins.all { it.canBeApplied(targets) }) { 20 | "incorrect gradle plugin was used for current set of targets" 21 | } 22 | require(dependencies.all { dep -> dep.targets == null || targets.all { dep.targets.contains(it) } }) { 23 | "incorrect dependency was used for current set of targets" 24 | } 25 | require(singleTargetDependencies.all { dep -> dep.target in targets}) { 26 | "incorrect dependency was used for current set of targets" 27 | } 28 | } 29 | 30 | fun normalize() = copy( 31 | moduleName = moduleName.replace(' ', '_'), 32 | gradlePlugins = gradlePlugins.filter { it.canBeApplied(targets) }.toSet(), 33 | dependencies = dependencies 34 | .filter { dep -> dep.targets == null || targets.all { dep.targets.contains(it) } }.toSet(), 35 | singleTargetDependencies = singleTargetDependencies 36 | .filter { dep -> dep.target in targets }.toSet(), 37 | nativeTargetLibraries = if (this.targets.isNativeTargetPresent()) nativeTargetLibraries else emptySet() 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/RootBuildGradle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.NAN 4 | import org.jetbrains.webwiz.generator.ProjectFile 5 | import org.jetbrains.webwiz.generator.deleteNans 6 | import org.jetbrains.webwiz.models.GradlePlugin 7 | import org.jetbrains.webwiz.models.KmpLibrary 8 | import org.jetbrains.webwiz.models.KotlinVersion 9 | import org.jetbrains.webwiz.models.ProjectInfo 10 | import org.jetbrains.webwiz.models.Target 11 | 12 | class RootBuildGradle(val projectInfo: ProjectInfo) : ProjectFile { 13 | override val path = "build.gradle.kts" 14 | override val content: String 15 | get() = 16 | """ 17 | buildscript { 18 | repositories { 19 | gradlePluginPortal() 20 | google() 21 | mavenCentral() 22 | ${if (projectInfo.kotlinVersion == KotlinVersion.Dev) "maven(\"https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/\")" else NAN} 23 | } 24 | dependencies { 25 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${projectInfo.kotlinVersion.versionName}") 26 | ${if (projectInfo.dependencies.contains(KmpLibrary.SERIALIZATION)) "classpath(\"org.jetbrains.kotlin:kotlin-serialization:${projectInfo.kotlinVersion.versionName}\")" else NAN} 27 | ${if (projectInfo.targets.contains(Target.ANDROID)) "classpath(\"com.android.tools.build:gradle:7.0.2\")" else NAN} 28 | ${if (GradlePlugin.SQL_DELIGHT in projectInfo.gradlePlugins) "classpath(\"com.squareup.sqldelight:gradle-plugin:1.5.3\")" else NAN} 29 | } 30 | } 31 | 32 | allprojects { 33 | repositories { 34 | google() 35 | mavenCentral() 36 | ${if (projectInfo.kotlinVersion == KotlinVersion.Dev) "maven(\"https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/\")" else NAN} 37 | } 38 | } 39 | """.trimIndent().deleteNans() 40 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/generator.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator 2 | 3 | import org.jetbrains.webwiz.generator.files.* 4 | import org.jetbrains.webwiz.models.GradlePlugin 5 | import org.jetbrains.webwiz.models.ProjectInfo 6 | import org.jetbrains.webwiz.models.Target.ANDROID 7 | import org.jetbrains.webwiz.models.isNativeTargetPresent 8 | 9 | interface ProjectFile { 10 | val path: String 11 | val content: String 12 | } 13 | 14 | fun ProjectInfo.generate(): List = mutableListOf().apply { 15 | val info = this@generate.normalize() 16 | 17 | add(Gitignore()) 18 | add(Gradlew()) 19 | add(GradleBat()) 20 | add(GradleWrapperProperties("7.3")) 21 | add(GradleWrapperJar()) 22 | 23 | add(RootBuildGradle(info)) 24 | add(SettingsGradle(projectName, moduleName)) 25 | add(GradleProperties()) 26 | 27 | add(ModuleBuildGradle(info)) 28 | 29 | add(CommonPlatformKt(info)) 30 | info.targets.forEach { target -> 31 | add(TargetPlatformKt(target, info)) 32 | } 33 | if (info.targets.isNativeTargetPresent()) { 34 | add(IntermediatePlatformKt("native", info)) 35 | } 36 | 37 | if (info.gradlePlugins.contains(GradlePlugin.APPLICATION)) { 38 | add(ApplicationKt(info)) 39 | } 40 | 41 | if (info.targets.contains(ANDROID)) { 42 | add(AndroidManifestXml(info)) 43 | } 44 | 45 | if (info.enableTests) { 46 | add(CommonPlatformTestKt(info)) 47 | info.targets.forEach { target -> 48 | add(TargetPlatformTestKt(target, info)) 49 | } 50 | if (info.targets.isNativeTargetPresent()) { 51 | add(IntermediatePlatformTestKt("native", info)) 52 | } 53 | } 54 | } 55 | 56 | internal const val NAN = "®®®" 57 | internal fun String.deleteNans(): String = 58 | lines().filter { !it.contains(NAN) }.joinToString("\n") 59 | 60 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/Main.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.browser.window 2 | import org.jetbrains.compose.common.foundation.layout.Box 3 | import org.jetbrains.compose.common.ui.ExperimentalComposeWebWidgetsApi 4 | import org.jetbrains.compose.web.css.Style 5 | import org.jetbrains.compose.web.renderComposable 6 | import org.jetbrains.webwiz.FileSaverJs 7 | import org.jetbrains.webwiz.JSZip 8 | import org.jetbrains.webwiz.components.Layout 9 | import org.jetbrains.webwiz.components.MainContentLayout 10 | import org.jetbrains.webwiz.content.Header 11 | import org.jetbrains.webwiz.content.Intro 12 | import org.jetbrains.webwiz.content.PageFooter 13 | import org.jetbrains.webwiz.content.WizardSection 14 | import org.jetbrains.webwiz.generator.files.GradleWrapperJar 15 | import org.jetbrains.webwiz.generator.files.Gradlew 16 | import org.jetbrains.webwiz.generator.generate 17 | import org.jetbrains.webwiz.models.ProjectInfo 18 | import org.jetbrains.webwiz.style.AppStylesheet 19 | import org.w3c.files.Blob 20 | 21 | @OptIn(ExperimentalComposeWebWidgetsApi::class) 22 | fun main() { 23 | renderComposable(rootElementId = "root") { 24 | Box { 25 | Style(AppStylesheet) 26 | 27 | Layout { 28 | Header() 29 | MainContentLayout { 30 | Intro() 31 | WizardSection { generateProject(it) } 32 | } 33 | PageFooter() 34 | } 35 | } 36 | } 37 | } 38 | 39 | private fun generateProject(project: ProjectInfo) { 40 | window.fetch("./binaries/gradle-wrapper") 41 | .then { response -> response.arrayBuffer() } 42 | .then { gradleWrapperBlob -> 43 | val zip = JSZip() 44 | project.generate().forEach { file -> 45 | when (file) { 46 | is GradleWrapperJar -> zip.file( 47 | file.path, 48 | gradleWrapperBlob 49 | ) 50 | is Gradlew -> zip.file( 51 | file.path, 52 | file.content, 53 | js("""{unixPermissions:"774"}""") //execution rights 54 | ) 55 | else -> zip.file( 56 | file.path, 57 | file.content 58 | ) 59 | } 60 | } 61 | //execution rights require UNIX mode 62 | zip.generateAsync(js("""{type:"blob",platform:"UNIX"}""")).then { blob -> 63 | FileSaverJs.saveAs(blob, "${project.projectName}.zip") 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/IntroSection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.attributes.ATarget 5 | import org.jetbrains.compose.web.attributes.target 6 | import org.jetbrains.compose.web.css.* 7 | import org.jetbrains.compose.web.dom.A 8 | import org.jetbrains.compose.web.dom.Div 9 | import org.jetbrains.compose.web.dom.H1 10 | import org.jetbrains.compose.web.dom.Img 11 | import org.jetbrains.compose.web.dom.P 12 | import org.jetbrains.compose.web.dom.Text 13 | import org.jetbrains.webwiz.components.ContainerInSection 14 | import org.jetbrains.webwiz.style.AppStylesheet 15 | import org.jetbrains.webwiz.style.WtCols 16 | import org.jetbrains.webwiz.style.WtOffsets 17 | import org.jetbrains.webwiz.style.WtRows 18 | import org.jetbrains.webwiz.style.WtTexts 19 | 20 | @Composable 21 | fun Intro() { 22 | ContainerInSection { 23 | Div({ 24 | classes(WtRows.wtRow, WtRows.wtRowSizeM, WtRows.wtRowSmAlignItemsCenter) 25 | }) { 26 | 27 | Div({ 28 | classes(WtCols.wtCol2, WtCols.wtColMd3) 29 | style { 30 | alignSelf(AlignSelf.Start) 31 | } 32 | }) { 33 | Img(src = "ic_kotlin_logo.svg", attrs = { classes(AppStylesheet.composeLogo) }) 34 | } 35 | 36 | Div({ 37 | classes( 38 | WtCols.wtCol10, 39 | WtCols.wtColMd8, 40 | WtCols.wtColSm12, 41 | WtOffsets.wtTopOffsetSm12 42 | ) 43 | }) { 44 | H1(attrs = { classes(WtTexts.wtHero) }) { 45 | Text("Kotlin Multiplatform Wizard") 46 | } 47 | Div { 48 | IntroAboutKMP() 49 | } 50 | } 51 | } 52 | 53 | } 54 | } 55 | 56 | @Composable 57 | private fun IntroAboutKMP() { 58 | Div({ 59 | classes(WtRows.wtRow, WtRows.wtRowSizeM) 60 | }) { 61 | Div({ 62 | classes(WtCols.wtCol9, WtCols.wtColMd9, WtCols.wtColSm12) 63 | }) { 64 | P({ classes(WtTexts.wtSubtitle2, WtOffsets.wtTopOffset24) }) { 65 | Text("Support for multiplatform programming is one of Kotlin’s key benefits. ") 66 | 67 | Text("Learn more about ") 68 | 69 | A(href = "https://kotlinlang.org/docs/multiplatform.html", attrs = { 70 | classes(WtTexts.wtLink) 71 | target(ATarget.Blank) 72 | }) { 73 | Text("Kotlin Multiplatform benefits") 74 | } 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/Stylesheet.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.* 4 | import org.jetbrains.compose.web.css.selectors.CSSSelector 5 | 6 | object AppCSSVariables { 7 | val wtColorGreyLight by variable() 8 | val wtColorGreyDark by variable() 9 | 10 | val wtOffsetTopUnit by variable() 11 | val wtHorizontalLayoutGutter by variable() 12 | val wtFlowUnit by variable() 13 | 14 | val wtHeroFontSize by variable() 15 | val wtHeroLineHeight by variable() 16 | val wtSubtitle2FontSize by variable() 17 | val wtSubtitle2LineHeight by variable() 18 | val wtH2FontSize by variable() 19 | val wtH2LineHeight by variable() 20 | val wtH3FontSize by variable() 21 | val wtH3LineHeight by variable() 22 | 23 | val wtColCount by variable() 24 | } 25 | 26 | 27 | object AppStylesheet : StyleSheet() { 28 | val composeLogo by style { 29 | maxWidth(100.percent) 30 | } 31 | 32 | init { 33 | "label, a, button" style { 34 | property( 35 | "font-family", 36 | "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 37 | ) 38 | } 39 | 40 | CSSSelector.Universal style { 41 | AppCSSVariables.wtColorGreyLight(Color("#f4f4f4")) 42 | AppCSSVariables.wtColorGreyDark(Color("#323236")) 43 | AppCSSVariables.wtOffsetTopUnit(24.px) 44 | 45 | margin(0.px) 46 | } 47 | 48 | media(mediaMaxWidth(640.px)) { 49 | CSSSelector.Universal style { 50 | AppCSSVariables.wtOffsetTopUnit(16.px) 51 | AppCSSVariables.wtFlowUnit(16.px) 52 | } 53 | } 54 | 55 | CSSSelector.Attribute( 56 | name = "class", 57 | value = "wtCol", 58 | operator = CSSSelector.Attribute.Operator.Contains 59 | ) style { 60 | marginRight(AppCSSVariables.wtHorizontalLayoutGutter.value()) 61 | marginLeft(AppCSSVariables.wtHorizontalLayoutGutter.value()) 62 | 63 | property( 64 | "flex-basis", 65 | "calc(8.33333%*${AppCSSVariables.wtColCount.value()} - ${AppCSSVariables.wtHorizontalLayoutGutter.value()}*2)" 66 | ) 67 | property( 68 | "max-width", 69 | "calc(8.33333%*${AppCSSVariables.wtColCount.value()} - ${AppCSSVariables.wtHorizontalLayoutGutter.value()}*2)" 70 | ) 71 | boxSizing("border-box") 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/PlatformTestKt.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | import org.jetbrains.webwiz.models.ProjectInfo 5 | import org.jetbrains.webwiz.models.Target 6 | import org.jetbrains.webwiz.models.isJvm 7 | 8 | class CommonPlatformTestKt(val projectInfo: ProjectInfo) : ProjectFile { 9 | override val path = "${projectInfo.moduleName}/src/commonTest/kotlin" + 10 | "/${projectInfo.packageName.replace('.', '/')}" + 11 | "/CommonTest.kt" 12 | override val content: String 13 | get() = """ 14 | package ${projectInfo.packageName} 15 | 16 | import kotlin.test.Test 17 | import kotlin.test.assertTrue 18 | 19 | class CommonTest { 20 | 21 | @Test 22 | fun testExample() { 23 | assertTrue(Greeting().greeting().contains("Hello"), "Check 'Hello' is mentioned") 24 | } 25 | } 26 | """.trimIndent() 27 | } 28 | 29 | class TargetPlatformTestKt(val target: Target, val projectInfo: ProjectInfo) : 30 | ProjectFile { 31 | override val path = "${projectInfo.moduleName}/src/${target.targetName}Test/kotlin" + 32 | "/${projectInfo.packageName.replace('.', '/')}" + 33 | "/PlatformTest.kt" 34 | override val content: String = if (target.isJvm()) { 35 | """ 36 | package ${projectInfo.packageName} 37 | 38 | import org.junit.Assert.assertTrue 39 | import org.junit.Test 40 | 41 | class PlatformTest { 42 | 43 | @Test 44 | fun testExample() { 45 | assertTrue("Check ${target.targetName} is mentioned", Greeting().greeting().contains("${target.targetName}")) 46 | } 47 | } 48 | """.trimIndent() 49 | } else { 50 | """ 51 | package ${projectInfo.packageName} 52 | 53 | import kotlin.test.Test 54 | import kotlin.test.assertTrue 55 | 56 | class PlatformTest { 57 | 58 | @Test 59 | fun testExample() { 60 | assertTrue(Greeting().greeting().contains("${target.targetName}"), "Check ${target.targetName} is mentioned") 61 | } 62 | } 63 | """.trimIndent() 64 | } 65 | } 66 | 67 | class IntermediatePlatformTestKt( 68 | val intermediateName: String, 69 | val projectInfo: ProjectInfo 70 | ) : ProjectFile { 71 | private val interName = intermediateName.lowercase().replaceFirstChar { it.uppercaseChar() } 72 | 73 | override val path = "${projectInfo.moduleName}/src/${intermediateName.lowercase()}Test/kotlin" + 74 | "/${projectInfo.packageName.replace('.', '/')}" + 75 | "/${interName}Test.kt" 76 | override val content: String 77 | get() = """ 78 | package ${projectInfo.packageName} 79 | 80 | import kotlin.test.Test 81 | import kotlin.test.assertTrue 82 | 83 | class ${interName}Test { 84 | 85 | @Test 86 | fun testExample() { 87 | assertTrue(Greeting().greeting().contains("Hello"), "Check 'Hello' is mentioned") 88 | } 89 | } 90 | """.trimIndent() 91 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/CodeSamplesSwitcher.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.attributes.InputType 5 | import org.jetbrains.compose.web.attributes.name 6 | import org.jetbrains.compose.web.css.* 7 | import org.jetbrains.compose.web.css.selectors.CSSSelector 8 | import org.jetbrains.compose.web.css.selectors.descendant 9 | import org.jetbrains.compose.web.css.selectors.selector 10 | import org.jetbrains.compose.web.dom.Form 11 | import org.jetbrains.compose.web.dom.Input 12 | import org.jetbrains.compose.web.dom.Label 13 | import org.jetbrains.compose.web.dom.Text 14 | import org.jetbrains.webwiz.models.KotlinVersion 15 | import org.jetbrains.webwiz.style.AppStylesheet 16 | 17 | private object SwitcherVariables { 18 | val labelWidth by variable() 19 | val labelPadding by variable() 20 | } 21 | 22 | @Composable 23 | fun KotlinVersionSwitcher(state: KotlinVersion, onSelect: (KotlinVersion) -> Unit) { 24 | Form(attrs = { 25 | classes(KotlinSwitcherStylesheet.boxed) 26 | }) { 27 | KotlinVersion.values().filter { it != KotlinVersion.Dev }.forEach { version -> 28 | Input(type = InputType.Radio, attrs = { 29 | name("code-snippet") 30 | value("snippet$version") 31 | id("snippet$version") 32 | checked(version == state) 33 | onClick { onSelect(version) } 34 | }) 35 | Label(forId = "snippet$version") { Text("${version.name}") } 36 | } 37 | } 38 | } 39 | 40 | 41 | object KotlinSwitcherStylesheet : StyleSheet(AppStylesheet) { 42 | val boxed by style { 43 | 44 | backgroundColor(Color("rgb(244,244,244)")) 45 | 46 | descendant(self, CSSSelector.Type("label")) style { 47 | display(DisplayStyle.InlineBlock) 48 | width(SwitcherVariables.labelWidth.value(100.px)) 49 | padding(SwitcherVariables.labelPadding.value(5.px)) 50 | property("transition", "all 0.3s") 51 | textAlign("center") 52 | boxSizing("border-box") 53 | 54 | border { 55 | style(LineStyle.Solid) 56 | width(3.px) 57 | color(Color("transparent")) 58 | borderRadius(20.px, 20.px, 20.px) 59 | } 60 | 61 | } 62 | 63 | border { 64 | style(LineStyle.Solid) 65 | width(0.px) 66 | color(Color("#aaa")) 67 | padding(0.px) 68 | borderRadius(22.px, 22.px, 22.px) 69 | } 70 | 71 | descendant(self, selector("input[type=\"radio\"]")) style { 72 | display(DisplayStyle.None) 73 | 74 | } 75 | 76 | descendant(self, selector("input[type=\"radio\"]:checked + label")) style { 77 | border { 78 | style(LineStyle.Solid) 79 | width(3.px) 80 | color(Color("#167dff")) 81 | property("background-color", "#167dff") 82 | borderRadius(20.px, 20.px, 20.px) 83 | } 84 | color(Color("white")) 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/jsMain/resources/i1.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 8 | 10 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/GradleBat.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class GradleBat : ProjectFile { 6 | override val path = "gradle.bat" 7 | override val content: String 8 | get() = """ 9 | @rem 10 | @rem Copyright 2015 the original author or authors. 11 | @rem 12 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 13 | @rem you may not use this file except in compliance with the License. 14 | @rem You may obtain a copy of the License at 15 | @rem 16 | @rem https://www.apache.org/licenses/LICENSE-2.0 17 | @rem 18 | @rem Unless required by applicable law or agreed to in writing, software 19 | @rem distributed under the License is distributed on an "AS IS" BASIS, 20 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | @rem See the License for the specific language governing permissions and 22 | @rem limitations under the License. 23 | @rem 24 | 25 | @if "%DEBUG%" == "" @echo off 26 | @rem ########################################################################## 27 | @rem 28 | @rem Gradle startup script for Windows 29 | @rem 30 | @rem ########################################################################## 31 | 32 | @rem Set local scope for the variables with windows NT shell 33 | if "%OS%"=="Windows_NT" setlocal 34 | 35 | set DIRNAME=%~dp0 36 | if "%DIRNAME%" == "" set DIRNAME=. 37 | set APP_BASE_NAME=%~n0 38 | set APP_HOME=%DIRNAME% 39 | 40 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 41 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 42 | 43 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 44 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 45 | 46 | @rem Find java.exe 47 | if defined JAVA_HOME goto findJavaFromJavaHome 48 | 49 | set JAVA_EXE=java.exe 50 | %JAVA_EXE% -version >NUL 2>&1 51 | if "%ERRORLEVEL%" == "0" goto execute 52 | 53 | echo. 54 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 55 | echo. 56 | echo Please set the JAVA_HOME variable in your environment to match the 57 | echo location of your Java installation. 58 | 59 | goto fail 60 | 61 | :findJavaFromJavaHome 62 | set JAVA_HOME=%JAVA_HOME:"=% 63 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 64 | 65 | if exist "%JAVA_EXE%" goto execute 66 | 67 | echo. 68 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 69 | echo. 70 | echo Please set the JAVA_HOME variable in your environment to match the 71 | echo location of your Java installation. 72 | 73 | goto fail 74 | 75 | :execute 76 | @rem Setup the command line 77 | 78 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 79 | 80 | 81 | @rem Execute Gradle 82 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 83 | 84 | :end 85 | @rem End local scope for the variables with windows NT shell 86 | if "%ERRORLEVEL%"=="0" goto mainEnd 87 | 88 | :fail 89 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 90 | rem the _cmd.exe /c_ return code! 91 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 92 | exit /b 1 93 | 94 | :mainEnd 95 | if "%OS%"=="Windows_NT" endlocal 96 | 97 | :omega 98 | """.trimIndent() 99 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/models/KmpLibraries.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.models 2 | 3 | import org.jetbrains.webwiz.models.SourceSetType.MAIN 4 | 5 | enum class KmpLibrary( 6 | val targets: Set?, //null means any target 7 | val userName: String, 8 | val dep: String, 9 | val sourceSetType: SourceSetType 10 | ) { 11 | COROUTINES( 12 | setOf( 13 | Target.ANDROID, 14 | Target.JVM, 15 | Target.JS, 16 | Target.MACOS, 17 | Target.IOS, 18 | Target.TV_OS, 19 | Target.WATCH_OS, 20 | Target.LINUX, 21 | Target.WINDOWS 22 | ), 23 | "KotlinX Coroutines", 24 | "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2", 25 | MAIN 26 | ), 27 | SERIALIZATION( 28 | setOf( 29 | Target.ANDROID, 30 | Target.JVM, 31 | Target.JS, 32 | Target.MACOS, 33 | Target.IOS, 34 | Target.TV_OS, 35 | Target.WATCH_OS, 36 | Target.LINUX, 37 | Target.WINDOWS 38 | ), 39 | "KotlinX Serialization", 40 | "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1", 41 | MAIN 42 | ), 43 | DATE_TIME( 44 | setOf( 45 | Target.ANDROID, 46 | Target.JVM, 47 | Target.JS, 48 | Target.MACOS, 49 | Target.IOS, 50 | Target.TV_OS, 51 | Target.WATCH_OS, 52 | Target.LINUX, 53 | Target.WINDOWS 54 | ), 55 | "KotlinX DateTime", 56 | "org.jetbrains.kotlinx:kotlinx-datetime:0.3.1", 57 | MAIN 58 | ), 59 | KERMIT_LOGGER( 60 | setOf( 61 | Target.ANDROID, 62 | Target.JVM, 63 | Target.JS, 64 | Target.MACOS, 65 | Target.IOS, 66 | Target.TV_OS, 67 | Target.WATCH_OS, 68 | Target.LINUX, 69 | Target.WINDOWS 70 | ), 71 | "Kermit Logger", 72 | "co.touchlab:kermit:1.0.0", 73 | MAIN 74 | ), 75 | NAPIER_LOGGER( 76 | setOf( 77 | Target.ANDROID, 78 | Target.JVM, 79 | Target.JS, 80 | Target.MACOS, 81 | Target.IOS, 82 | Target.TV_OS, 83 | Target.WATCH_OS 84 | ), 85 | "Napier logger", 86 | "io.github.aakira:napier:2.1.0", 87 | MAIN 88 | ), 89 | SQLDELIGHT_COROUTINES( 90 | setOf( 91 | Target.ANDROID, 92 | Target.JVM, 93 | Target.JS, 94 | Target.IOS, 95 | Target.LINUX, 96 | Target.MACOS, 97 | Target.WINDOWS, 98 | Target.TV_OS, 99 | Target.WATCH_OS 100 | ), 101 | "SQLDelight Coroutines", 102 | "com.squareup.sqldelight:coroutines-extensions:1.5.3", 103 | MAIN 104 | ), 105 | KTOR_CORE( 106 | setOf( 107 | Target.JVM, 108 | Target.ANDROID, 109 | Target.JS, 110 | Target.IOS, 111 | Target.LINUX, 112 | Target.MACOS, 113 | Target.WINDOWS 114 | ), 115 | "Ktor Core", 116 | "io.ktor:ktor-client-core:1.6.7", 117 | MAIN 118 | ), 119 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtCol.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.CSSBuilder 4 | import org.jetbrains.compose.web.css.CSSUnitValue 5 | import org.jetbrains.compose.web.css.GenericStyleSheetBuilder 6 | import org.jetbrains.compose.web.css.StyleSheet 7 | import org.jetbrains.compose.web.css.flexGrow 8 | import org.jetbrains.compose.web.css.maxWidth 9 | import org.jetbrains.compose.web.css.media 10 | import org.jetbrains.compose.web.css.percent 11 | import org.jetbrains.compose.web.css.px 12 | import org.jetbrains.compose.web.css.mediaMaxWidth 13 | import org.jetbrains.compose.web.css.selectors.CSSSelector 14 | 15 | fun GenericStyleSheetBuilder.mediaMaxWidth( 16 | value: CSSUnitValue, 17 | cssSelector: CSSSelector, 18 | rulesBuild: TBuilder.() -> Unit 19 | ) { 20 | media(mediaMaxWidth(value)) { 21 | cssSelector style rulesBuild 22 | } 23 | } 24 | 25 | fun CSSBuilder.forMaxWidth(value: CSSUnitValue, builder: CSSBuilder.() -> Unit) { 26 | mediaMaxWidth(value, self, builder) 27 | } 28 | 29 | object WtCols : StyleSheet(AppStylesheet) { 30 | val wtCol2 by style { 31 | AppCSSVariables.wtColCount(2) 32 | } 33 | 34 | val wtCol3 by style { 35 | AppCSSVariables.wtColCount(3) 36 | } 37 | 38 | val wtCol4 by style { 39 | AppCSSVariables.wtColCount(4) 40 | } 41 | 42 | val wtCol5 by style { 43 | AppCSSVariables.wtColCount(5) 44 | } 45 | 46 | val wtCol6 by style { 47 | AppCSSVariables.wtColCount(6) 48 | } 49 | 50 | val wtCol9 by style { 51 | AppCSSVariables.wtColCount(9) 52 | } 53 | 54 | val wtCol10 by style { 55 | AppCSSVariables.wtColCount(10) 56 | } 57 | 58 | val wtColMd3 by style { 59 | forMaxWidth(1000.px) { 60 | AppCSSVariables.wtColCount(3) 61 | } 62 | } 63 | 64 | val wtColMd4 by style { 65 | forMaxWidth(1000.px) { 66 | AppCSSVariables.wtColCount(4) 67 | } 68 | } 69 | 70 | val wtColMd8 by style { 71 | forMaxWidth(1000.px) { 72 | AppCSSVariables.wtColCount(8) 73 | } 74 | } 75 | 76 | val wtColMd9 by style { 77 | forMaxWidth(1000.px) { 78 | AppCSSVariables.wtColCount(9) 79 | } 80 | } 81 | 82 | val wtColMd10 by style { 83 | forMaxWidth(1000.px) { 84 | AppCSSVariables.wtColCount(10) 85 | } 86 | } 87 | 88 | val wtColMd11 by style { 89 | forMaxWidth(1000.px) { 90 | AppCSSVariables.wtColCount(11) 91 | } 92 | } 93 | 94 | val wtColMd6 by style { 95 | forMaxWidth(1000.px) { 96 | AppCSSVariables.wtColCount(6) 97 | } 98 | } 99 | 100 | val wtColMd12 by style { 101 | forMaxWidth(1000.px) { 102 | AppCSSVariables.wtColCount(12) 103 | } 104 | } 105 | 106 | val wtColSm12 by style { 107 | forMaxWidth(640.px) { 108 | AppCSSVariables.wtColCount(12) 109 | } 110 | } 111 | 112 | val wtColLg6 by style { 113 | forMaxWidth(1276.px) { 114 | AppCSSVariables.wtColCount(6) 115 | } 116 | } 117 | 118 | val wtColSmAutoFill by style { 119 | forMaxWidth(640.px) { 120 | AppCSSVariables.wtColCount(0) 121 | flexGrow(1) 122 | maxWidth(100.percent) 123 | } 124 | } 125 | 126 | val wtColAutoFill by style { 127 | AppCSSVariables.wtColCount(0) 128 | flexGrow(1) 129 | maxWidth(100.percent) 130 | } 131 | 132 | val wtColInline by style { 133 | AppCSSVariables.wtColCount(0) 134 | maxWidth(100.percent) 135 | property("flex-basis", "auto") 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/Footer.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.attributes.ATarget 5 | import org.jetbrains.compose.web.attributes.target 6 | import org.jetbrains.compose.web.css.* 7 | import org.jetbrains.compose.web.dom.* 8 | import org.jetbrains.webwiz.style.* 9 | 10 | 11 | @Composable 12 | fun PageFooter() { 13 | Footer({ 14 | style { 15 | flexShrink(0) 16 | boxSizing("border-box") 17 | } 18 | }) { 19 | Section({ 20 | classes(WtSections.wtSectionBgGrayDark) 21 | style { 22 | padding(24.px, 0.px) 23 | } 24 | }) { 25 | Div({ classes(WtContainer.wtContainer) }) { 26 | Div({ 27 | classes(WtRows.wtRow, WtRows.wtRowSizeM, WtRows.wtRowSmAlignItemsCenter) 28 | style { 29 | justifyContent(JustifyContent.Center) 30 | flexWrap(FlexWrap.Wrap) 31 | } 32 | }) { 33 | 34 | Div({ 35 | classes(WtCols.wtColInline) 36 | }) { 37 | P({ 38 | classes(WtTexts.wtText1, WtTexts.wtText1ThemeDark) 39 | }) { 40 | Text("Follow us") 41 | } 42 | } 43 | 44 | Div({ 45 | classes(WtCols.wtColInline) 46 | }) { 47 | getSocialLinks().forEach { SocialIconLink(it) } 48 | } 49 | } 50 | 51 | CopyrightInFooter() 52 | } 53 | } 54 | } 55 | } 56 | 57 | @Composable 58 | private fun CopyrightInFooter() { 59 | Div({ 60 | classes(WtRows.wtRow, WtRows.wtRowSizeM, WtRows.wtRowSmAlignItemsCenter, WtOffsets.wtTopOffset48) 61 | style { 62 | justifyContent(JustifyContent.SpaceEvenly) 63 | flexWrap(FlexWrap.Wrap) 64 | padding(0.px, 12.px) 65 | } 66 | }) { 67 | Span({ 68 | classes(WtTexts.wtText3, WtTexts.wtTextPale) 69 | }) { 70 | Text("Copyright © 2000-2021 JetBrains s.r.o.") 71 | } 72 | 73 | Span({ 74 | classes(WtTexts.wtText3, WtTexts.wtTextPale) 75 | }) { 76 | Text("Developed with drive and IntelliJ IDEA") 77 | } 78 | } 79 | } 80 | 81 | @Composable 82 | private fun SocialIconLink(link: SocialLink) { 83 | A(attrs = { 84 | classes(WtTexts.wtSocialButtonItem) 85 | target(ATarget.Blank) 86 | }, href = link.url) { 87 | Img(src = link.iconSvg) {} 88 | } 89 | } 90 | 91 | private data class SocialLink( 92 | val id: String, 93 | val url: String, 94 | val title: String, 95 | val iconSvg: String 96 | ) 97 | 98 | private fun getSocialLinks(): List { 99 | return listOf( 100 | SocialLink("facebook", "https://www.facebook.com/JetBrains", "JetBrains on Facebook", "ic_fb.svg"), 101 | SocialLink("twitter", "https://twitter.com/jetbrains", "JetBrains on Twitter", "ic_twitter.svg"), 102 | SocialLink( 103 | "linkedin", 104 | "https://www.linkedin.com/company/jetbrains", 105 | "JetBrains on Linkedin", 106 | "ic_linkedin.svg" 107 | ), 108 | SocialLink("youtube", "https://www.youtube.com/user/JetBrainsTV", "JetBrains on YouTube", "ic_youtube.svg"), 109 | SocialLink("instagram", "https://www.instagram.com/jetbrains/", "JetBrains on Instagram", "ic_insta.svg"), 110 | SocialLink("blog", "https://blog.jetbrains.com/", "JetBrains blog", "ic_jb_blog.svg"), 111 | SocialLink("rss", "https://blog.jetbrains.com/feed/", "JetBrains RSS Feed", "ic_feed.svg"), 112 | ) 113 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtOffest.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.ExperimentalComposeWebApi 4 | import org.jetbrains.compose.web.css.* 5 | import org.jetbrains.compose.web.css.selectors.descendant 6 | import org.jetbrains.compose.web.css.selectors.selector 7 | 8 | object WtOffsets : StyleSheet(AppStylesheet) { 9 | val wtTopOffset96 by style { 10 | marginTop(96.px) 11 | property( 12 | "margin-top", 13 | "calc(4*${AppCSSVariables.wtOffsetTopUnit.value(24.px)})" 14 | ) 15 | } 16 | 17 | val wtTopOffset24 by style { 18 | marginTop(24.px) 19 | property( 20 | "margin-top", 21 | "calc(1*${AppCSSVariables.wtOffsetTopUnit.value(24.px)})" 22 | ) 23 | } 24 | 25 | val wtTopOffset48 by style { 26 | marginTop(48.px) 27 | } 28 | 29 | val wtTopOffsetSm12 by style { 30 | media(mediaMaxWidth(640.px)) { 31 | self style { 32 | marginTop(12.px) 33 | } 34 | } 35 | } 36 | 37 | val wtTopOffsetSm24 by style { 38 | media(mediaMaxWidth(640.px)) { 39 | self style { 40 | marginTop(24.px) 41 | } 42 | } 43 | } 44 | 45 | val textInputLabelsStyle by style { 46 | width(20.percent) 47 | display(DisplayStyle.InlineBlock) 48 | } 49 | 50 | 51 | val textInputStyle by style { 52 | property("border", "1px solid rgb(170, 170, 170, 42%)") 53 | property("color", "rgb(39 40 44 / 79%)") 54 | property("font-famyly", "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif") 55 | fontSize(15.px) 56 | width(70.percent) 57 | padding(10.px) 58 | } 59 | 60 | 61 | val rowItems by style { 62 | display(DisplayStyle.LegacyInlineFlex) 63 | alignItems(AlignItems.Center) 64 | marginBottom(16.px) 65 | width(100.percent) 66 | } 67 | 68 | val rowTargetsItems by style { 69 | display(DisplayStyle.LegacyInlineFlex) 70 | alignItems("top") 71 | marginBottom(16.px) 72 | width(100.percent) 73 | } 74 | 75 | val targetsCheckboxesListStyle by style { 76 | display(DisplayStyle.Flex) 77 | property("flex-wrap","wrap") 78 | width(77.percent) 79 | } 80 | val targetsCheckboxesStyle by style { 81 | marginBottom(10.px) 82 | marginRight(10.px) 83 | 84 | descendant(self, selector("input[type=\"checkbox\"]")) style { 85 | display(DisplayStyle.None) 86 | } 87 | 88 | descendant(self, selector("input[type=\"checkbox\"] + label")) style { 89 | property("-webkit-transition","all 500ms ease") 90 | property("transition","all 500ms ease") 91 | property("font-size","18px") 92 | property("background-color","rgb(244,244,244)") 93 | property("padding","0.5rem 2rem") 94 | property("-moz-user-select","-moz-none") 95 | property("-ms-user-select","none") 96 | property("-webkit-user-select","none") 97 | property("user-select","none") 98 | cursor("pointer") 99 | borderRadius(50.px) 100 | display(DisplayStyle.InlineBlock); 101 | } 102 | 103 | descendant(self, selector("input[type=\"checkbox\"]:checked + label")) style { 104 | property("-webkit-transition: all", "500ms ease") 105 | property("transition", "all 300ms ease") 106 | property("background-color", "#167dff") 107 | property("color", "white") 108 | property("border-color", "#167dff") 109 | } 110 | 111 | descendant(self, selector("input[type=\"checkbox\"]:disabled + label")) style { 112 | property("-webkit-transition: all", "500ms ease") 113 | property("transition", "all 300ms ease") 114 | property("background-color", "rgb(244,244,244)") 115 | property("color", "#bfbfbf") 116 | property("cursor", "not-allowed") 117 | } 118 | } 119 | @OptIn(ExperimentalComposeWebApi::class) 120 | val testsCheckboxStyle by style { 121 | 122 | descendant(self, selector("input[type=\"checkbox\"]")) style { 123 | property("box-sizing", "border-box") 124 | padding(0.px) 125 | transform{scale(1.5) } 126 | } 127 | 128 | descendant(self, selector("input[type=\"checkbox\"]:checked")) style { 129 | property("box-sizing", "border-box") 130 | padding(0.px) 131 | property("border-color","#aaa") 132 | property("background-color","#aaa") 133 | } 134 | } 135 | 136 | val generateButtonStyle by style { 137 | display(DisplayStyle.Flex) 138 | justifyContent(JustifyContent.Center) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/style/WtText.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.style 2 | 3 | import org.jetbrains.compose.web.css.* 4 | import org.jetbrains.compose.web.css.selectors.hover 5 | 6 | object WtTexts : StyleSheet(AppStylesheet) { 7 | 8 | val wtHero by style { 9 | color(Color("#27282c")) 10 | fontSize(60.px) 11 | fontSize(AppCSSVariables.wtHeroFontSize.value(60.px)) 12 | letterSpacing((-1.5).px) 13 | fontWeight(900) 14 | lineHeight(64.px) 15 | lineHeight(AppCSSVariables.wtHeroLineHeight.value(64.px)) 16 | 17 | media(mediaMaxWidth(640.px)) { 18 | self style { 19 | AppCSSVariables.wtHeroFontSize(42.px) 20 | AppCSSVariables.wtHeroLineHeight(48.px) 21 | } 22 | } 23 | 24 | property( 25 | "font-family", 26 | "Gotham SSm A,Gotham SSm B,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 27 | ) 28 | } 29 | 30 | val wtSubtitle2 by style { 31 | color(Color("#27282c")) 32 | fontSize(28.px) 33 | fontSize(AppCSSVariables.wtSubtitle2FontSize.value(28.px)) 34 | letterSpacing("normal") 35 | fontWeight(300) 36 | lineHeight(40.px) 37 | lineHeight(AppCSSVariables.wtSubtitle2LineHeight.value(40.px)) 38 | 39 | media(mediaMaxWidth(640.px)) { 40 | self style { 41 | AppCSSVariables.wtSubtitle2FontSize(24.px) 42 | AppCSSVariables.wtSubtitle2LineHeight(32.px) 43 | } 44 | } 45 | 46 | property( 47 | "font-family", 48 | "Gotham SSm A,Gotham SSm B,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 49 | ) 50 | } 51 | 52 | val wtText1 by style { 53 | color(rgba(39, 40, 44, .7)) 54 | fontSize(18.px) 55 | letterSpacing("normal") 56 | fontWeight(400) 57 | lineHeight(28.px) 58 | property("width", "90%") 59 | 60 | property( 61 | "font-family", 62 | "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 63 | ) 64 | } 65 | 66 | val wtText1ThemeDark by style { 67 | color(rgba(255, 255, 255, 0.6)) 68 | minWidth(80.px) 69 | } 70 | 71 | val wtText2 by style { 72 | color(rgba(39, 40, 44, .7)) 73 | fontSize(15.px) 74 | letterSpacing("normal") 75 | fontWeight(400) 76 | lineHeight(24.px) 77 | 78 | property( 79 | "font-family", 80 | "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 81 | ) 82 | } 83 | 84 | val wtText3 by style { 85 | color(rgba(39, 40, 44, .7)) 86 | fontSize(12.px) 87 | letterSpacing("normal") 88 | fontWeight(400) 89 | lineHeight(16.px) 90 | 91 | property( 92 | "font-family", 93 | "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 94 | ) 95 | } 96 | 97 | val wtTextPale by style { 98 | color(rgba(255, 255, 255, 0.30)) 99 | } 100 | 101 | val wtText2ThemeDark by style { 102 | color(rgba(255, 255, 255, 0.6)) 103 | } 104 | 105 | val wtText3ThemeDark by style { 106 | color(rgba(255, 255, 255, 0.6)) 107 | } 108 | 109 | val wtLink by style { 110 | property("border-bottom", "1px solid transparent") 111 | property("text-decoration", "none") 112 | color(Color("#167dff")) 113 | 114 | hover(self) style { 115 | property("border-bottom-color", "#167dff") 116 | } 117 | } 118 | 119 | val wtH2 by style { 120 | color(Color("#27282c")) 121 | fontSize(31.px) 122 | fontSize(AppCSSVariables.wtH2FontSize.value(31.px)) 123 | letterSpacing((-.5).px) 124 | fontWeight(700) 125 | lineHeight(40.px) 126 | lineHeight(40.px) 127 | 128 | media(mediaMaxWidth(640.px)) { 129 | self style { 130 | AppCSSVariables.wtH2FontSize(24.px) 131 | AppCSSVariables.wtH2LineHeight(32.px) 132 | } 133 | } 134 | 135 | property( 136 | "font-family", 137 | "Gotham SSm A,Gotham SSm B,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 138 | ) 139 | } 140 | 141 | val wtH2ThemeDark by style { 142 | color(Color("#fff")) 143 | } 144 | 145 | val wtH3 by style { 146 | color(Color("#27282c")) 147 | fontSize(21.px) 148 | fontSize(AppCSSVariables.wtH3FontSize.value(20.px)) 149 | letterSpacing("normal") 150 | fontWeight(700) 151 | lineHeight(28.px) 152 | lineHeight(AppCSSVariables.wtH3LineHeight.value(28.px)) 153 | 154 | property( 155 | "font-family", 156 | "system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,Arial,sans-serif" 157 | ) 158 | } 159 | 160 | val wtH3ThemeDark by style { 161 | color(Color("#fff")) 162 | } 163 | 164 | val wtButton by style { 165 | color(Color("white")) 166 | backgroundColor(Color("#167dff")) 167 | fontSize(15.px) 168 | display(DisplayStyle.InlineBlock) 169 | textDecoration("none") 170 | borderRadius(24.px) 171 | padding(12.px, 32.px) 172 | lineHeight(24.px) 173 | fontWeight(400) 174 | border(0.px) 175 | property("width", "fit-content") 176 | 177 | hover(self) style { 178 | backgroundColor(rgba(22, 125, 255, .8)) 179 | } 180 | } 181 | 182 | val wtLangButton by style { 183 | display(DisplayStyle.LegacyInlineFlex) 184 | justifyContent(JustifyContent.Center) 185 | alignItems(AlignItems.Center) 186 | backgroundColor(Color("transparent")) 187 | border(0.px) 188 | 189 | outline("none") 190 | 191 | hover(self) style { 192 | backgroundColor(rgba(255, 255, 255, 0.1)) 193 | } 194 | } 195 | 196 | val wtButtonContrast by style { 197 | color(Color("white")) 198 | backgroundColor(Color("#27282c")) 199 | 200 | hover(self) style { 201 | backgroundColor(rgba(39, 40, 44, .7)) 202 | } 203 | } 204 | 205 | val wtSocialButtonItem by style { 206 | marginRight(16.px) 207 | marginLeft(16.px) 208 | padding(12.px) 209 | backgroundColor(Color("transparent")) 210 | display(DisplayStyle.LegacyInlineFlex) 211 | 212 | hover(self) style { 213 | backgroundColor(rgba(255, 255, 255, 0.1)) 214 | borderRadius(24.px) 215 | } 216 | 217 | media(mediaMaxWidth(640.px)) { 218 | self style { 219 | marginRight(8.px) 220 | marginLeft(8.px) 221 | } 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/Gradlew.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.ProjectFile 4 | 5 | class Gradlew : ProjectFile { 6 | override val path = "gradlew" 7 | override val content: String 8 | get() = """ 9 | #!/usr/bin/env sh 10 | 11 | # 12 | # Copyright 2015 the original author or authors. 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); 15 | # you may not use this file except in compliance with the License. 16 | # You may obtain a copy of the License at 17 | # 18 | # https://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, 22 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | # See the License for the specific language governing permissions and 24 | # limitations under the License. 25 | # 26 | 27 | ############################################################################## 28 | ## 29 | ## Gradle start up script for UN*X 30 | ## 31 | ############################################################################## 32 | 33 | # Attempt to set APP_HOME 34 | # Resolve links: ${'$'}{'$'}0 may be a link 35 | PRG="${'$'}0" 36 | # Need this for relative symlinks. 37 | while [ -h "${'$'}PRG" ] ; do 38 | ls=`ls -ld "${'$'}PRG"` 39 | link=`expr "${'$'}ls" : '.*-> \(.*\)${'$'}{'$'}'` 40 | if expr "${'$'}link" : '/.*' > /dev/null; then 41 | PRG="${'$'}link" 42 | else 43 | PRG=`dirname "${'$'}PRG"`"/${'$'}link" 44 | fi 45 | done 46 | SAVED="`pwd`" 47 | cd "`dirname \"${'$'}PRG\"`/" >/dev/null 48 | APP_HOME="`pwd -P`" 49 | cd "${'$'}SAVED" >/dev/null 50 | 51 | APP_NAME="Gradle" 52 | APP_BASE_NAME=`basename "${'$'}0"` 53 | 54 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 55 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 56 | 57 | # Use the maximum available, or set MAX_FD != -1 to use that value. 58 | MAX_FD="maximum" 59 | 60 | warn () { 61 | echo "${'$'}{'$'}*" 62 | } 63 | 64 | die () { 65 | echo 66 | echo "${'$'}{'$'}*" 67 | echo 68 | exit 1 69 | } 70 | 71 | # OS specific support (must be 'true' or 'false'). 72 | cygwin=false 73 | msys=false 74 | darwin=false 75 | nonstop=false 76 | case "`uname`" in 77 | CYGWIN* ) 78 | cygwin=true 79 | ;; 80 | Darwin* ) 81 | darwin=true 82 | ;; 83 | MSYS* | MINGW* ) 84 | msys=true 85 | ;; 86 | NONSTOP* ) 87 | nonstop=true 88 | ;; 89 | esac 90 | 91 | CLASSPATH=${'$'}APP_HOME/gradle/wrapper/gradle-wrapper.jar 92 | 93 | 94 | # Determine the Java command to use to start the JVM. 95 | if [ -n "${'$'}JAVA_HOME" ] ; then 96 | if [ -x "${'$'}JAVA_HOME/jre/sh/java" ] ; then 97 | # IBM's JDK on AIX uses strange locations for the executables 98 | JAVACMD="${'$'}JAVA_HOME/jre/sh/java" 99 | else 100 | JAVACMD="${'$'}JAVA_HOME/bin/java" 101 | fi 102 | if [ ! -x "${'$'}JAVACMD" ] ; then 103 | die "ERROR: JAVA_HOME is set to an invalid directory: ${'$'}JAVA_HOME 104 | 105 | Please set the JAVA_HOME variable in your environment to match the 106 | location of your Java installation." 107 | fi 108 | else 109 | JAVACMD="java" 110 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 111 | 112 | Please set the JAVA_HOME variable in your environment to match the 113 | location of your Java installation." 114 | fi 115 | 116 | # Increase the maximum file descriptors if we can. 117 | if [ "${'$'}cygwin" = "false" -a "${'$'}darwin" = "false" -a "${'$'}nonstop" = "false" ] ; then 118 | MAX_FD_LIMIT=`ulimit -H -n` 119 | if [ ${'$'}? -eq 0 ] ; then 120 | if [ "${'$'}MAX_FD" = "maximum" -o "${'$'}MAX_FD" = "max" ] ; then 121 | MAX_FD="${'$'}MAX_FD_LIMIT" 122 | fi 123 | ulimit -n ${'$'}MAX_FD 124 | if [ ${'$'}? -ne 0 ] ; then 125 | warn "Could not set maximum file descriptor limit: ${'$'}MAX_FD" 126 | fi 127 | else 128 | warn "Could not query maximum file descriptor limit: ${'$'}MAX_FD_LIMIT" 129 | fi 130 | fi 131 | 132 | # For Darwin, add options to specify how the application appears in the dock 133 | if ${'$'}darwin; then 134 | GRADLE_OPTS="${'$'}GRADLE_OPTS \"-Xdock:name=${'$'}APP_NAME\" \"-Xdock:icon=${'$'}APP_HOME/media/gradle.icns\"" 135 | fi 136 | 137 | # For Cygwin or MSYS, switch paths to Windows format before running java 138 | if [ "${'$'}cygwin" = "true" -o "${'$'}msys" = "true" ] ; then 139 | APP_HOME=`cygpath --path --mixed "${'$'}APP_HOME"` 140 | CLASSPATH=`cygpath --path --mixed "${'$'}CLASSPATH"` 141 | 142 | JAVACMD=`cygpath --unix "${'$'}JAVACMD"` 143 | 144 | # We build the pattern for arguments to be converted via cygpath 145 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 146 | SEP="" 147 | for dir in ${'$'}ROOTDIRSRAW ; do 148 | ROOTDIRS="${'$'}ROOTDIRS${'$'}SEP${'$'}dir" 149 | SEP="|" 150 | done 151 | OURCYGPATTERN="(^(${'$'}ROOTDIRS))" 152 | # Add a user-defined pattern to the cygpath arguments 153 | if [ "${'$'}GRADLE_CYGPATTERN" != "" ] ; then 154 | OURCYGPATTERN="${'$'}OURCYGPATTERN|(${'$'}GRADLE_CYGPATTERN)" 155 | fi 156 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 157 | i=0 158 | for arg in "${'$'}@" ; do 159 | CHECK=`echo "${'$'}arg"|egrep -c "${'$'}OURCYGPATTERN" -` 160 | CHECK2=`echo "${'$'}arg"|egrep -c "^-"` ### Determine if an option 161 | 162 | if [ ${'$'}CHECK -ne 0 ] && [ ${'$'}CHECK2 -eq 0 ] ; then ### Added a condition 163 | eval `echo args${'$'}i`=`cygpath --path --ignore --mixed "${'$'}arg"` 164 | else 165 | eval `echo args${'$'}i`="\"${'$'}arg\"" 166 | fi 167 | i=`expr ${'$'}i + 1` 168 | done 169 | case ${'$'}i in 170 | 0) set -- ;; 171 | 1) set -- "${'$'}args0" ;; 172 | 2) set -- "${'$'}args0" "${'$'}args1" ;; 173 | 3) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" ;; 174 | 4) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" ;; 175 | 5) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" "${'$'}args4" ;; 176 | 6) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" "${'$'}args4" "${'$'}args5" ;; 177 | 7) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" "${'$'}args4" "${'$'}args5" "${'$'}args6" ;; 178 | 8) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" "${'$'}args4" "${'$'}args5" "${'$'}args6" "${'$'}args7" ;; 179 | 9) set -- "${'$'}args0" "${'$'}args1" "${'$'}args2" "${'$'}args3" "${'$'}args4" "${'$'}args5" "${'$'}args6" "${'$'}args7" "${'$'}args8" ;; 180 | esac 181 | fi 182 | 183 | # Escape application args 184 | save () { 185 | for i do printf %s\\n "${'$'}i" | sed "s/'/'\\\\''/g;1s/^/'/;\${'$'}s/\${'$'}/' \\\\/" ; done 186 | echo " " 187 | } 188 | APP_ARGS=`save "${'$'}@"` 189 | 190 | # Collect all arguments for the java command, following the shell quoting and substitution rules 191 | eval set -- ${'$'}DEFAULT_JVM_OPTS ${'$'}JAVA_OPTS ${'$'}GRADLE_OPTS "\"-Dorg.gradle.appname=${'$'}APP_BASE_NAME\"" -classpath "\"${'$'}CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "${'$'}APP_ARGS" 192 | 193 | exec "${'$'}JAVACMD" "${'$'}@" 194 | """.trimIndent() 195 | } -------------------------------------------------------------------------------- /src/commonTest/kotlin/org/jetbrains/webwiz/generator/ProjectBuilderTest.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator 2 | 3 | import org.jetbrains.webwiz.generator.files.ModuleBuildGradle 4 | import org.jetbrains.webwiz.generator.files.SettingsGradle 5 | import org.jetbrains.webwiz.models.GradlePlugin 6 | import org.jetbrains.webwiz.models.KmpLibrary 7 | import org.jetbrains.webwiz.models.KotlinVersion 8 | import org.jetbrains.webwiz.models.ProjectInfo 9 | import org.jetbrains.webwiz.models.Target.* 10 | import kotlin.test.Test 11 | import kotlin.test.assertEquals 12 | 13 | 14 | internal class ProjectBuilderTest { 15 | 16 | @Test 17 | fun testGeneratedStructure() { 18 | val projectInfo = ProjectInfo( 19 | "wizard-sample", 20 | "library", 21 | "my.test.package", 22 | KotlinVersion.Stable, 23 | setOf(JVM, JS, IOS, ANDROID), 24 | emptySet(), 25 | emptySet(), 26 | emptySet(), 27 | setOf(GradlePlugin.PUBLISH), 28 | true 29 | ) 30 | val actual = projectInfo.generate().joinToString("\n") { it.path } 31 | val expect = """ 32 | .gitignore 33 | gradlew 34 | gradle.bat 35 | gradle/wrapper/gradle-wrapper.properties 36 | gradle/wrapper/gradle-wrapper.jar 37 | build.gradle.kts 38 | settings.gradle.kts 39 | gradle.properties 40 | library/build.gradle.kts 41 | library/src/commonMain/kotlin/my/test/package/Platform.kt 42 | library/src/jvmMain/kotlin/my/test/package/Platform.kt 43 | library/src/jsMain/kotlin/my/test/package/Platform.kt 44 | library/src/iosMain/kotlin/my/test/package/Platform.kt 45 | library/src/androidMain/kotlin/my/test/package/Platform.kt 46 | library/src/nativeMain/kotlin/my/test/package/Platform.kt 47 | library/src/androidMain/AndroidManifest.xml 48 | library/src/commonTest/kotlin/my/test/package/CommonTest.kt 49 | library/src/jvmTest/kotlin/my/test/package/PlatformTest.kt 50 | library/src/jsTest/kotlin/my/test/package/PlatformTest.kt 51 | library/src/iosTest/kotlin/my/test/package/PlatformTest.kt 52 | library/src/androidTest/kotlin/my/test/package/PlatformTest.kt 53 | library/src/nativeTest/kotlin/my/test/package/NativeTest.kt 54 | """.trimIndent() 55 | assertEquals(expect, actual) 56 | } 57 | 58 | @Test 59 | fun testGeneratedBuildConfig() { 60 | val projectInfo = ProjectInfo( 61 | "wizard-sample", 62 | "lib", 63 | "my.test.package", 64 | KotlinVersion.EAP, 65 | setOf(JVM, JS, IOS, ANDROID), 66 | setOf(KmpLibrary.SERIALIZATION), 67 | emptySet(), 68 | emptySet(), 69 | setOf(GradlePlugin.PUBLISH), 70 | true 71 | ) 72 | val actual = projectInfo.generate().first { it is ModuleBuildGradle }.content 73 | val expect = """ 74 | plugins { 75 | kotlin("multiplatform") 76 | kotlin("plugin.serialization") 77 | id("com.android.library") 78 | `maven-publish` 79 | } 80 | 81 | /* required for maven publication */ 82 | group = "my.test.package" 83 | version = "0.1" 84 | 85 | kotlin { 86 | jvm() 87 | js { 88 | browser() 89 | nodejs() 90 | } 91 | iosX64() 92 | iosArm64() 93 | /* iosSimulatorArm64() sure all ios dependencies support this target */ 94 | android() 95 | 96 | sourceSets { 97 | /* Main source sets */ 98 | val commonMain by getting { 99 | dependencies { 100 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") 101 | } 102 | } 103 | val jvmMain by getting 104 | val jsMain by getting 105 | val iosX64Main by getting 106 | val iosArm64Main by getting 107 | /* val iosSimulatorArm64Main by getting */ 108 | val androidMain by getting 109 | val iosMain by creating 110 | val nativeMain by creating 111 | 112 | /* Main hierarchy */ 113 | jvmMain.dependsOn(commonMain) 114 | jsMain.dependsOn(commonMain) 115 | iosMain.dependsOn(nativeMain) 116 | iosX64Main.dependsOn(iosMain) 117 | iosArm64Main.dependsOn(iosMain) 118 | /* iosSimulatorArm64Main.dependsOn(iosMain) */ 119 | androidMain.dependsOn(commonMain) 120 | nativeMain.dependsOn(commonMain) 121 | 122 | /* Test source sets */ 123 | val commonTest by getting { 124 | dependencies { 125 | implementation(kotlin("test")) 126 | } 127 | } 128 | val jvmTest by getting 129 | val jsTest by getting 130 | val iosX64Test by getting 131 | val iosArm64Test by getting 132 | /* val iosSimulatorArm64Test by getting */ 133 | val androidTest by getting 134 | val iosTest by creating 135 | val nativeTest by creating 136 | 137 | /* Test hierarchy */ 138 | jvmTest.dependsOn(commonTest) 139 | jsTest.dependsOn(commonTest) 140 | iosTest.dependsOn(nativeTest) 141 | iosX64Test.dependsOn(iosTest) 142 | iosArm64Test.dependsOn(iosTest) 143 | /* iosSimulatorArm64Test.dependsOn(iosTest) */ 144 | androidTest.dependsOn(commonTest) 145 | nativeTest.dependsOn(commonTest) 146 | } 147 | } 148 | 149 | android { 150 | compileSdk = 31 151 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 152 | defaultConfig { 153 | minSdk = 21 154 | targetSdk = 31 155 | } 156 | } 157 | 158 | """.trimIndent() 159 | assertEquals(expect, actual) 160 | } 161 | 162 | @Test 163 | fun testGeneratedSettingsGradle() { 164 | val projectInfo = ProjectInfo( 165 | "New Project", 166 | "module", 167 | "my.test.package", 168 | KotlinVersion.EAP, 169 | setOf(JVM, JS, IOS, ANDROID), 170 | setOf(KmpLibrary.SERIALIZATION), 171 | emptySet(), 172 | emptySet(), 173 | setOf(GradlePlugin.PUBLISH), 174 | true 175 | ) 176 | val actual = projectInfo.generate().first { it is SettingsGradle }.content 177 | val expect = """ 178 | pluginManagement { 179 | repositories { 180 | google() 181 | gradlePluginPortal() 182 | mavenCentral() 183 | } 184 | } 185 | 186 | rootProject.name = "New_Project" 187 | include(":module") 188 | """.trimIndent() 189 | assertEquals(expect, actual) 190 | } 191 | 192 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/Chips.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import org.jetbrains.compose.web.attributes.disabled 5 | import org.jetbrains.compose.web.dom.CheckboxInput 6 | import org.jetbrains.compose.web.dom.Div 7 | import org.jetbrains.compose.web.dom.Label 8 | import org.jetbrains.compose.web.dom.Span 9 | import org.jetbrains.compose.web.dom.Text 10 | import org.jetbrains.webwiz.models.GradlePlugin 11 | import org.jetbrains.webwiz.models.KmpLibrary 12 | import org.jetbrains.webwiz.models.NativeTargetLibrary 13 | import org.jetbrains.webwiz.models.SingleTargetLibrary 14 | import org.jetbrains.webwiz.models.Target 15 | import org.jetbrains.webwiz.models.isCommonNativeTargetPresent 16 | import org.jetbrains.webwiz.models.isNativeTargetPresent 17 | import org.jetbrains.webwiz.style.WtOffsets 18 | 19 | @Composable 20 | fun TargetChips() { 21 | Div({ classes(WtOffsets.targetsCheckboxesListStyle) }) { 22 | Target.values().forEach { t -> 23 | Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 24 | CheckboxInput(projectInfoState.value.targets.contains(t)) { 25 | onChange { event -> 26 | val current = projectInfoState.value.targets.toMutableSet() 27 | val new: Set = when { 28 | event.value -> current.plus(t) 29 | current.size > 1 -> current.minus(t) 30 | else -> current 31 | } 32 | applyTargetsUpdate(targets = new) 33 | } 34 | id("checkbox_${t.name}") 35 | } 36 | Label(forId = "checkbox_${t.name}") { 37 | Text(t.userName) 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | 45 | @Composable 46 | fun LibrariesChips() { 47 | Div({ classes(WtOffsets.targetsCheckboxesListStyle) }) { 48 | KmpLibrary.values().forEach { t -> 49 | 50 | if (t.targets != null && projectInfoState.value.targets.any { it !in t.targets }) { 51 | return@forEach DisabledChip(t.userName) 52 | } 53 | 54 | return@forEach Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 55 | CheckboxInput(projectInfoState.value.dependencies.contains(t)) { 56 | onChange { event -> 57 | val current = projectInfoState.value.dependencies.toMutableSet() 58 | val new: Set = when { 59 | event.value -> current.plus(t) 60 | else -> current.minus(t) 61 | } 62 | projectInfoState.value = projectInfoState.value.copy(dependencies = new) 63 | } 64 | id("checkbox_${t.name}") 65 | } 66 | Label(forId = "checkbox_${t.name}") { 67 | Text(t.userName) 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | @Composable 75 | fun SingleTargetLibraryChips() { 76 | Div({ classes(WtOffsets.targetsCheckboxesListStyle) }) { 77 | SingleTargetLibrary.values().forEach { t -> 78 | 79 | if (t.target !in projectInfoState.value.targets ) { 80 | return@forEach DisabledChip(t.userName) 81 | } 82 | 83 | return@forEach Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 84 | CheckboxInput(projectInfoState.value.singleTargetDependencies.contains(t)) { 85 | onChange { event -> 86 | val current = projectInfoState.value.singleTargetDependencies.toMutableSet() 87 | val new: Set = when { 88 | event.value -> current.plus(t) 89 | else -> current.minus(t) 90 | } 91 | projectInfoState.value = projectInfoState.value.copy(singleTargetDependencies = new) 92 | } 93 | id("checkbox_${t.name}") 94 | } 95 | Label(forId = "checkbox_${t.name}") { 96 | Text(t.userName) 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | @Composable 104 | fun NativeTargetLibraryChips() { 105 | Div({ classes(WtOffsets.targetsCheckboxesListStyle) }) { 106 | NativeTargetLibrary.values().forEach { t -> 107 | 108 | if (!projectInfoState.value.targets.isCommonNativeTargetPresent() ) { 109 | return@forEach DisabledChip(t.userName) 110 | } 111 | 112 | return@forEach Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 113 | CheckboxInput(projectInfoState.value.nativeTargetLibraries.contains(t)) { 114 | onChange { event -> 115 | val current = projectInfoState.value.nativeTargetLibraries.toMutableSet() 116 | val new: Set = when { 117 | event.value -> current.plus(t) 118 | else -> current.minus(t) 119 | } 120 | projectInfoState.value = projectInfoState.value.copy(nativeTargetLibraries = new) 121 | } 122 | id("checkbox_${t.name}") 123 | } 124 | Label(forId = "checkbox_${t.name}") { 125 | Text(t.userName) 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | @Composable 133 | fun PluginsChips() { 134 | Div({ classes(WtOffsets.targetsCheckboxesListStyle) }) { 135 | GradlePlugin.values().forEach { t -> 136 | val targets = projectInfoState.value.targets 137 | 138 | if (t.mandatory.any { !targets.contains(it) } || t.forbidden.any { targets.contains(it) }) { 139 | return@forEach DisabledChip(t.userName) 140 | } 141 | 142 | return@forEach Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 143 | CheckboxInput(projectInfoState.value.gradlePlugins.contains(t)) { 144 | onChange { event -> 145 | val current = projectInfoState.value.gradlePlugins.toMutableSet() 146 | val new: Set = when { 147 | event.value -> current.plus(t) 148 | else -> current.minus(t) 149 | } 150 | projectInfoState.value = projectInfoState.value.copy(gradlePlugins = new) 151 | } 152 | id("checkbox_gradle_plugin_${t.name}") 153 | } 154 | Label(forId = "checkbox_gradle_plugin_${t.name}") { 155 | Text(t.userName) 156 | } 157 | } 158 | } 159 | } 160 | } 161 | 162 | @Composable 163 | fun DisabledChip(label: String) { 164 | Span({ classes(WtOffsets.targetsCheckboxesStyle) }) { 165 | CheckboxInput() { 166 | id("checkbox_disabled_$label") 167 | disabled() 168 | } 169 | 170 | Label(forId = "checkbox_disabled_$label") { 171 | Text(label) 172 | } 173 | } 174 | } 175 | 176 | private fun applyTargetsUpdate(targets: Set) { 177 | val currentLibraries = projectInfoState.value.dependencies.toMutableSet() 178 | val currentPlugins = projectInfoState.value.gradlePlugins.toMutableSet() 179 | 180 | for (library in KmpLibrary.values()) { 181 | if (library.targets != null && targets.any { it !in library.targets }) { 182 | currentLibraries.remove(library) 183 | } 184 | } 185 | 186 | for (plugin in GradlePlugin.values()) { 187 | if (targets.containsAll(plugin.mandatory) && !targets.any { it in plugin.forbidden }) 188 | continue 189 | if (plugin.mandatory.isNotEmpty() && targets.any { !plugin.mandatory.contains(it) }) { 190 | currentPlugins.remove(plugin) 191 | } 192 | } 193 | 194 | projectInfoState.value = projectInfoState.value.copy( 195 | targets = targets, 196 | dependencies = currentLibraries, 197 | gradlePlugins = currentPlugins 198 | ) 199 | } -------------------------------------------------------------------------------- /src/commonMain/kotlin/org/jetbrains/webwiz/generator/files/ModuleBuildGradle.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.generator.files 2 | 3 | import org.jetbrains.webwiz.generator.NAN 4 | import org.jetbrains.webwiz.generator.ProjectFile 5 | import org.jetbrains.webwiz.generator.deleteNans 6 | import org.jetbrains.webwiz.models.GradlePlugin 7 | import org.jetbrains.webwiz.models.KmpLibrary 8 | import org.jetbrains.webwiz.models.ProjectInfo 9 | import org.jetbrains.webwiz.models.SourceSetDelegate 10 | import org.jetbrains.webwiz.models.SourceSetDelegate.CREATING 11 | import org.jetbrains.webwiz.models.SourceSetDelegate.GETTING 12 | import org.jetbrains.webwiz.models.SourceSetType.MAIN 13 | import org.jetbrains.webwiz.models.Target 14 | import org.jetbrains.webwiz.models.isNativeTargetPresent 15 | 16 | class ModuleBuildGradle(val projectInfo: ProjectInfo) : ProjectFile { 17 | override val path = "${projectInfo.moduleName}/build.gradle.kts" 18 | override val content: String 19 | get() = """ 20 | ${generatePluginsBlock()} 21 | 22 | ${if (GradlePlugin.PUBLISH in projectInfo.gradlePlugins) generatePublishPluginConfig("0.1") else NAN} 23 | ${generateKotlinBlock()} 24 | 25 | ${if (Target.ANDROID in projectInfo.targets) generateAndroidPluginConfig("21", "31") else NAN} 26 | ${if (GradlePlugin.APPLICATION in projectInfo.gradlePlugins) generateApplicationPluginConfig() else NAN} 27 | """.trimIndent().deleteNans() 28 | 29 | private fun generatePluginsBlock(): String = """ 30 | plugins { 31 | kotlin("multiplatform") 32 | ${if (KmpLibrary.SERIALIZATION in projectInfo.dependencies) "kotlin(\"plugin.serialization\")" else NAN} 33 | ${if (Target.ANDROID in projectInfo.targets) "id(\"com.android.library\")" else NAN} 34 | ${if (GradlePlugin.APPLICATION in projectInfo.gradlePlugins) "application" else NAN} 35 | ${if (GradlePlugin.PUBLISH in projectInfo.gradlePlugins) "`maven-publish`" else NAN} 36 | ${if (GradlePlugin.SQL_DELIGHT in projectInfo.gradlePlugins) "id(\"com.squareup.sqldelight\")" else NAN} 37 | } 38 | """.trimIndent().deleteNans() 39 | 40 | private fun generateKotlinBlock() = """ 41 | kotlin { 42 | ${registerTargets(projectInfo.targets)} 43 | 44 | ${setupSourceSets()} 45 | } 46 | """.trimIndent() 47 | 48 | private fun registerTargets( 49 | targets: Set 50 | ) = targets.joinToString("\n ") { 51 | when (it) { 52 | Target.ANDROID -> "android()" 53 | Target.JVM -> if (projectInfo.gradlePlugins.contains(GradlePlugin.APPLICATION)) "jvm {\n withJava()\n }" else "jvm()" 54 | Target.JS -> "js {\n browser()\n nodejs()\n }" 55 | Target.WASM -> "wasm32()" 56 | Target.ANDROID_NATIVE -> "androidNativeArm64()" 57 | Target.LINUX -> "linuxX64()" 58 | Target.MACOS -> "macosX64()\n /* macosArm64() sure all macos dependencies support this target */" 59 | Target.IOS -> "iosX64()\n iosArm64()\n /* iosSimulatorArm64() sure all ios dependencies support this target */" 60 | Target.TV_OS -> "tvosX64()\n tvosArm64()\n /* tvosSimulatorArm64() sure all tvos dependencies support this target */" 61 | Target.WATCH_OS -> "watchosX64()\n watchosArm64()\n /* watchosSimulatorArm64() sure all watchos dependencies support this target */" 62 | Target.WINDOWS -> "mingwX64()" 63 | } 64 | } 65 | 66 | private fun setupSourceSets() = """ 67 | |sourceSets { 68 | | /* Main source sets */ 69 | ${commonMainSourceSet()} 70 | | ${leafSourceSets("Main")} 71 | | ${sharedSourceSets("Main")} 72 | | ${if (projectInfo.targets.isNativeTargetPresent()) nativeSourceSets("Main") else NAN} 73 | | 74 | | /* Main hierarchy */ 75 | | ${sourceSetsDependencies("Main")} 76 | | ${if (projectInfo.targets.isNativeTargetPresent()) nativeSourceSetsDependencies("Main") else NAN} 77 | | 78 | | /* Test source sets */ 79 | ${commonTestSourceSet()} 80 | | ${leafSourceSets("Test")} 81 | | ${sharedSourceSets("Test")} 82 | | ${if (projectInfo.targets.isNativeTargetPresent()) nativeSourceSets("Test") else NAN} 83 | | 84 | | /* Test hierarchy */ 85 | | ${sourceSetsDependencies("Test")} 86 | | ${if (projectInfo.targets.isNativeTargetPresent()) nativeSourceSetsDependencies("Test") else NAN} 87 | | } 88 | """.trimMargin().deleteNans() 89 | 90 | private fun commonMainSourceSet(): String { 91 | val deps = projectInfo.dependencies.filter { 92 | it.sourceSetType.sourceSetTypeName == MAIN.sourceSetTypeName 93 | }.map { "implementation(\"${it.dep}\")" } 94 | return if (deps.isEmpty()) { 95 | " | val commonMain by getting" 96 | } else { 97 | """| val commonMain by getting { 98 | | dependencies { 99 | | ${deps.joinToString("\n| ")} 100 | | } 101 | | }""" 102 | } 103 | } 104 | 105 | private fun singleSourceSet( 106 | target: Target, 107 | compilation: String, 108 | sourceSetDelegate: SourceSetDelegate 109 | ): String { 110 | val deps = projectInfo.singleTargetDependencies 111 | .filter { it.target == target && it.sourceSetType.sourceSetTypeName == compilation } 112 | .map { "implementation(\"${it.dep}\")" } 113 | return if (deps.isEmpty()) { 114 | "val ${target.targetName}$compilation by ${sourceSetDelegate.delegate}" 115 | } else { 116 | """val ${target.targetName}$compilation by ${sourceSetDelegate.delegate} { 117 | | dependencies { 118 | | ${deps.joinToString("\n| ")} 119 | | } 120 | | }""" 121 | } 122 | } 123 | 124 | private fun commonTestSourceSet() = 125 | """| val commonTest by getting { 126 | | dependencies { 127 | | implementation(kotlin("test")) 128 | | } 129 | | }""" 130 | 131 | private fun leafSourceSets(compilation: String): String { 132 | val intention = "\n| " 133 | return projectInfo.targets.joinToString(intention) { 134 | when (it) { 135 | Target.ANDROID -> singleSourceSet(Target.ANDROID, compilation, GETTING) 136 | Target.JVM -> singleSourceSet(Target.JVM, compilation, GETTING) 137 | Target.JS -> singleSourceSet(Target.JS, compilation, GETTING) 138 | Target.WASM -> "val wasm32$compilation by getting" 139 | Target.ANDROID_NATIVE -> "val androidNativeArm64$compilation by getting" 140 | Target.LINUX -> "val linuxX64$compilation by getting" 141 | Target.MACOS -> "val macosX64$compilation by getting ${intention}/* val macosArm64$compilation by getting */" 142 | Target.IOS -> "val iosX64$compilation by getting ${intention}val iosArm64$compilation by getting${intention}/* val iosSimulatorArm64$compilation by getting */" 143 | Target.TV_OS -> "val tvosX64$compilation by getting ${intention}val tvosArm64$compilation by getting ${intention}/* val tvosSimulatorArm64$compilation by getting */" 144 | Target.WATCH_OS -> "val watchosX64$compilation by getting ${intention}val watchosArm64$compilation by getting ${intention}/* val watchosSimulatorArm64$compilation by getting */" 145 | Target.WINDOWS -> "val mingwX64$compilation by getting" 146 | } 147 | } 148 | } 149 | 150 | private fun sharedSourceSets(compilation: String): String = 151 | projectInfo.targets.joinToString("\n| ") { 152 | when (it) { 153 | Target.ANDROID -> NAN 154 | Target.JVM -> NAN 155 | Target.JS -> NAN 156 | Target.WASM -> "val wasm$compilation by creating" 157 | Target.ANDROID_NATIVE -> "val androidNative$compilation by creating" 158 | Target.LINUX -> "val linux$compilation by creating" 159 | Target.MACOS -> "val macos$compilation by creating" 160 | Target.IOS -> singleSourceSet(Target.IOS, compilation, CREATING) 161 | Target.TV_OS -> "val tvos$compilation by creating" 162 | Target.WATCH_OS -> "val watchos$compilation by creating" 163 | Target.WINDOWS -> "val windows$compilation by creating" 164 | } 165 | } 166 | 167 | private fun sourceSetsDependencies(compilation: String): String { 168 | val intention = "\n| " 169 | return projectInfo.targets.joinToString(intention) { 170 | when (it) { 171 | Target.ANDROID -> "android$compilation.dependsOn(common$compilation)" 172 | Target.JVM -> "jvm$compilation.dependsOn(common$compilation)" 173 | Target.JS -> "js$compilation.dependsOn(common$compilation)" 174 | Target.WASM -> "wasm$compilation.dependsOn(native$compilation)${intention}wasm32$compilation.dependsOn(wasm$compilation)" 175 | Target.ANDROID_NATIVE -> "androidNative$compilation.dependsOn(native$compilation) ${intention}androidNativeArm64$compilation.dependsOn(androidNative$compilation)" 176 | Target.LINUX -> "linux$compilation.dependsOn(native$compilation)${intention}linuxX64$compilation.dependsOn(linux$compilation)" 177 | Target.MACOS -> "macos$compilation.dependsOn(native$compilation)${intention}macosX64$compilation.dependsOn(macos$compilation)${intention}/* macosArm64$compilation.dependsOn(macos$compilation) */" 178 | Target.IOS -> "ios$compilation.dependsOn(native$compilation)${intention}iosX64$compilation.dependsOn(ios$compilation)${intention}iosArm64$compilation.dependsOn(ios$compilation)${intention}/* iosSimulatorArm64$compilation.dependsOn(ios$compilation) */" 179 | Target.TV_OS -> "tvos$compilation.dependsOn(native$compilation)${intention}tvosX64$compilation.dependsOn(tvos$compilation)${intention}tvosArm64$compilation.dependsOn(tvos$compilation)${intention}/* tvosSimulatorArm64$compilation.dependsOn(tvos$compilation) */" 180 | Target.WATCH_OS -> "watchos$compilation.dependsOn(native$compilation)${intention}watchosX64$compilation.dependsOn(watchos$compilation)${intention}watchosArm64$compilation.dependsOn(watchos$compilation)${intention}/* watchosSimulatorArm64$compilation.dependsOn(watchos$compilation) */" 181 | Target.WINDOWS -> "windows$compilation.dependsOn(native$compilation)${intention}mingwX64$compilation.dependsOn(windows$compilation)" 182 | } 183 | } 184 | } 185 | 186 | private fun nativeUmbrellaSourceSet( 187 | compilation: String, 188 | sourceSetDelegate: SourceSetDelegate 189 | ): String { 190 | val deps = projectInfo.nativeTargetLibraries 191 | .filter { it.sourceSetType.sourceSetTypeName == compilation } 192 | .map { "implementation(\"${it.dep}\")" } 193 | return if (deps.isEmpty()) { 194 | "val native$compilation by ${sourceSetDelegate.delegate}" 195 | } else { 196 | """val native$compilation by ${sourceSetDelegate.delegate} { 197 | | dependencies { 198 | | ${deps.joinToString("\n| ")} 199 | | } 200 | | }""" 201 | } 202 | } 203 | 204 | private fun nativeSourceSets(compilation: String): String { 205 | return nativeUmbrellaSourceSet(compilation, CREATING) 206 | } 207 | private fun nativeSourceSetsDependencies(compilation: String) = "native$compilation.dependsOn(common$compilation)" 208 | 209 | private fun generateAndroidPluginConfig(minSdk: String, compileSdk: String) = """ 210 | android { 211 | compileSdk = $compileSdk 212 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 213 | defaultConfig { 214 | minSdk = $minSdk 215 | targetSdk = $compileSdk 216 | } 217 | } 218 | 219 | """.trimIndent() 220 | 221 | private fun generateApplicationPluginConfig() = """ 222 | application { 223 | mainClass.set("${projectInfo.packageName}.ApplicationKt") 224 | } 225 | 226 | """.trimIndent() 227 | 228 | private fun generatePublishPluginConfig(version: String) = """ 229 | /* required for maven publication */ 230 | group = "${projectInfo.packageName}" 231 | version = "$version" 232 | 233 | """.trimIndent() 234 | 235 | } -------------------------------------------------------------------------------- /src/jsMain/kotlin/org/jetbrains/webwiz/content/WizardSection.kt: -------------------------------------------------------------------------------- 1 | package org.jetbrains.webwiz.content 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.MutableState 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.compose.runtime.remember 7 | import org.jetbrains.compose.common.foundation.layout.Row 8 | import org.jetbrains.compose.common.ui.ExperimentalComposeWebWidgetsApi 9 | import org.jetbrains.compose.web.attributes.InputType 10 | import org.jetbrains.compose.web.css.* 11 | import org.jetbrains.compose.web.dom.* 12 | import org.jetbrains.webwiz.generator.ProjectFile 13 | import org.jetbrains.webwiz.generator.files.RootBuildGradle 14 | import org.jetbrains.webwiz.generator.generate 15 | import org.jetbrains.webwiz.models.KmpLibrary 16 | import org.jetbrains.webwiz.models.KotlinVersion 17 | import org.jetbrains.webwiz.models.ProjectInfo 18 | import org.jetbrains.webwiz.models.Target 19 | import org.jetbrains.webwiz.setHighlightedCode 20 | import org.jetbrains.webwiz.style.WtContainer 21 | import org.jetbrains.webwiz.style.WtOffsets 22 | import org.jetbrains.webwiz.style.WtSections 23 | import org.jetbrains.webwiz.style.WtTexts 24 | import kotlin.random.Random 25 | 26 | private val defaultProject = ProjectInfo( 27 | projectName = "KMP Project", 28 | moduleName = "shared", 29 | packageName = "org.sample.application", 30 | kotlinVersion = KotlinVersion.Stable, 31 | targets = setOf(Target.ANDROID, Target.IOS), 32 | enableTests = false, 33 | dependencies = setOf(KmpLibrary.SERIALIZATION), 34 | singleTargetDependencies = emptySet(), 35 | nativeTargetLibraries = emptySet(), 36 | gradlePlugins = emptySet() 37 | ).normalize() 38 | 39 | internal val projectInfoState = mutableStateOf(defaultProject) 40 | 41 | @Composable 42 | @OptIn(ExperimentalComposeWebWidgetsApi::class) 43 | fun WizardSection(callback: (projectInfo: ProjectInfo) -> Unit) = Section({ 44 | classes(WtSections.wtSection) 45 | }) { 46 | Div({ 47 | classes(WtContainer.wtContainer) 48 | }) { 49 | Div({ 50 | classes(WtTexts.wtText1) 51 | }) { 52 | Row { 53 | Div({ classes(WtOffsets.rowItems) }) { 54 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 55 | Text("Project name") 56 | } 57 | 58 | TextInput(projectInfoState.value.projectName) { 59 | 60 | onInput { event -> 61 | projectInfoState.value = projectInfoState.value.copy(projectName = event.value) 62 | } 63 | 64 | classes(WtOffsets.textInputStyle) 65 | } 66 | } 67 | } 68 | Row { 69 | Div({ classes(WtOffsets.rowItems) }) { 70 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 71 | Text("Module name") 72 | } 73 | 74 | TextInput(projectInfoState.value.moduleName) { 75 | 76 | onInput { event -> 77 | projectInfoState.value = projectInfoState.value.copy(moduleName = event.value) 78 | } 79 | 80 | classes(WtOffsets.textInputStyle) 81 | } 82 | } 83 | } 84 | Row { 85 | Div({ classes(WtOffsets.rowItems) }) { 86 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 87 | Text("Package") 88 | } 89 | TextInput(projectInfoState.value.packageName) { 90 | onInput { event -> 91 | projectInfoState.value = projectInfoState.value.copy(packageName = event.value) 92 | } 93 | classes(WtOffsets.textInputStyle) 94 | } 95 | } 96 | } 97 | Row { 98 | Div({ classes(WtOffsets.rowItems) }) { 99 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 100 | Text("Kotlin version") 101 | } 102 | 103 | Div { 104 | KotlinVersionSwitcher(projectInfoState.value.kotlinVersion) { 105 | projectInfoState.value = projectInfoState.value.copy(kotlinVersion = it) 106 | } 107 | } 108 | } 109 | } 110 | Row { 111 | Div({ classes(WtOffsets.rowItems) }) { 112 | Div({ classes(WtOffsets.rowTargetsItems) }) { 113 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 114 | Text("Targets") 115 | } 116 | TargetChips() 117 | } 118 | } 119 | } 120 | 121 | Row { 122 | Div({ classes(WtOffsets.rowTargetsItems) }) { 123 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 124 | Text("Libraries") 125 | } 126 | LibrariesChips() 127 | } 128 | } 129 | 130 | Row { 131 | Div({ classes(WtOffsets.rowTargetsItems) }) { 132 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 133 | Text("Single Target Libraries") 134 | } 135 | SingleTargetLibraryChips() 136 | } 137 | } 138 | 139 | Row { 140 | Div({ classes(WtOffsets.rowTargetsItems) }) { 141 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 142 | Text("Native Target Libraries") 143 | } 144 | NativeTargetLibraryChips() 145 | } 146 | } 147 | 148 | Row { 149 | Div({ classes(WtOffsets.rowTargetsItems) }) { 150 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 151 | Text("Plugins") 152 | } 153 | PluginsChips() 154 | } 155 | } 156 | 157 | Row { 158 | Span({ classes(WtOffsets.textInputLabelsStyle) }) { 159 | Text("Include tests") 160 | } 161 | Span({ classes(WtOffsets.testsCheckboxStyle) }) { 162 | CheckboxInput(projectInfoState.value.enableTests) { 163 | onChange { 164 | projectInfoState.value = 165 | projectInfoState.value.copy(enableTests = !projectInfoState.value.enableTests) 166 | } 167 | } 168 | } 169 | } 170 | 171 | Div({ classes(WtOffsets.generateButtonStyle) }) { 172 | Button(attrs = { 173 | classes(WtTexts.wtButton, WtTexts.wtButtonContrast, WtOffsets.wtTopOffset24) 174 | onClick { callback(projectInfoState.value) } 175 | style { 176 | cursor("pointer") 177 | } 178 | }) { 179 | Text("Download new project") 180 | } 181 | } 182 | 183 | Div({ 184 | classes(WtOffsets.wtTopOffset24) 185 | style { 186 | backgroundColor(rgba(39, 40, 44, 0.05)) 187 | borderRadius(8.px, 8.px, 8.px) 188 | padding(12.px, 16.px) 189 | property("font-family", "'JetBrains Mono', monospace") 190 | fontSize(10.pt) 191 | display(DisplayStyle.Flex) 192 | flexDirection(FlexDirection.Row) 193 | minHeight(600.pt) 194 | } 195 | }) { 196 | val structure = projectInfoState.value.generate() 197 | val selectedFile = remember(projectInfoState.value) { mutableStateOf(structure.first { it is RootBuildGradle }) } 198 | 199 | filesStructure(structure, selectedFile) 200 | Span(attrs = { 201 | style { 202 | width(1.pt) 203 | backgroundColor(Color("gray")) 204 | marginLeft(5.px) 205 | marginRight(5.px) 206 | } 207 | }) 208 | selectedFile.value.let { f -> 209 | val lang = when { 210 | f.path.endsWith(".kt") -> "kotlin" 211 | f.path.endsWith(".kts") -> "gradle" 212 | f.path.endsWith(".xml") -> "xml" 213 | else -> "text" 214 | } 215 | Pre(attrs = { 216 | style { 217 | overflow("auto") 218 | } 219 | }) { 220 | Code({ 221 | classes("language-$lang", "hljs") 222 | style { 223 | property("tab-size", 4) 224 | backgroundColor(Color("transparent")) 225 | } 226 | }) { 227 | DomSideEffect(f.content) { 228 | it.setHighlightedCode(f.content) 229 | } 230 | } 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } 237 | 238 | @Composable 239 | private fun filesStructure(list: List, selectedFile: MutableState) { 240 | fun putFileToDir(f: ProjectFile, path: List, dir: MutableMap): MutableMap { 241 | if (path.size == 1) { 242 | dir[path.first()] = f 243 | } else { 244 | val m = dir.getOrPut(path.first()) { mutableMapOf() } as MutableMap 245 | dir[path.first()] = putFileToDir(f, path.slice(1 until path.size), m) 246 | } 247 | return dir 248 | } 249 | 250 | val root = mutableMapOf() 251 | list.forEach { f -> putFileToDir(f, f.path.split('/'), root) } 252 | fileTree(0, root, selectedFile) 253 | } 254 | 255 | @Composable 256 | private fun fileTree(level: Int, map: Map, selectedFile: MutableState) { 257 | Ul(attrs = { 258 | if (level == 0) { 259 | classes("filetree") 260 | style { 261 | width(200.pt) 262 | paddingLeft(0.px) 263 | } 264 | } else { 265 | style { 266 | paddingLeft(10.px) 267 | } 268 | } 269 | }) { 270 | map.entries.sortedWith(FileEntryComparator).forEach { fileEntry -> 271 | val name = fileEntry.key 272 | val content = fileEntry.value as? Map 273 | if (content == null) { 274 | val f = fileEntry.value as ProjectFile 275 | Li(attrs = { 276 | onClick { selectedFile.value = f } 277 | style { 278 | cursor("pointer") 279 | } 280 | }) { 281 | if (selectedFile.value.path == f.path) B { Text(name) } 282 | else Text(name) 283 | } 284 | } else { 285 | Li { 286 | val id = "level-$level-$name-${Random.nextFloat()}" 287 | Input(InputType.Checkbox) { id(id) } 288 | Label(forId = id, attrs = { 289 | style { 290 | cursor("pointer") 291 | } 292 | }) { Text(name) } 293 | fileTree(level + 1, content, selectedFile) 294 | } 295 | } 296 | } 297 | } 298 | } 299 | 300 | private object FileEntryComparator : Comparator> { 301 | override fun compare(a: Map.Entry, b: Map.Entry): Int { 302 | val aIsDir = (a.value as? Map) != null 303 | val bIsDir = (b.value as? Map) != null 304 | return if (aIsDir == bIsDir) { 305 | a.key.compareTo(b.key) 306 | } else { 307 | if (aIsDir) -1 else 1 308 | } 309 | } 310 | } -------------------------------------------------------------------------------- /src/jsMain/resources/logos.css: -------------------------------------------------------------------------------- 1 | .jetbrains-logo { 2 | display: inline-block; 3 | background-color: transparent; 4 | background-repeat: no-repeat; 5 | background-size: contain; 6 | vertical-align: top; 7 | text-indent: -9000px 8 | } 9 | 10 | .jetbrains-logo._logo-jetbrains { 11 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='120.1' height='130.2' viewBox='0 0 120.1 130.2' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='31.841' y1='120.558' x2='110.24' y2='73.24'%3E%3Cstop offset='0' stop-color='%23FCEE39'/%3E%3Cstop offset='1' stop-color='%23F37B3D'/%3E%3C/linearGradient%3E%3Cpath d='M118.6,71.8c0.9-0.8,1.4-1.9,1.5-3.2c0.1-2.6-1.8-4.7-4.4-4.9 c-1.2-0.1-2.4,0.4-3.3,1.1l0,0l-83.8,45.9c-1.9,0.8-3.6,2.2-4.7,4.1c-2.9,4.8-1.3,11,3.6,13.9c3.4,2,7.5,1.8,10.7-0.2l0,0l0,0 c0.2-0.2,0.5-0.3,0.7-0.5l78-54.8C117.3,72.9,118.4,72.1,118.6,71.8L118.6,71.8L118.6,71.8z' fill='url(%23a)'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='48.361' y1='6.908' x2='119.918' y2='69.555'%3E%3Cstop offset='0' stop-color='%23EF5A6B'/%3E%3Cstop offset='.57' stop-color='%23F26F4E'/%3E%3Cstop offset='1' stop-color='%23F37B3D'/%3E%3C/linearGradient%3E%3Cpath d='M118.8,65.1L118.8,65.1L55,2.5C53.6,1,51.6,0,49.3,0 c-4.3,0-7.7,3.5-7.7,7.7v0c0,2.1,0.8,3.9,2.1,5.3l0,0l0,0c0.4,0.4,0.8,0.7,1.2,1l67.4,57.7l0,0c0.8,0.7,1.8,1.2,3,1.3 c2.6,0.1,4.7-1.8,4.9-4.4C120.2,67.3,119.7,66,118.8,65.1z' fill='url(%23b)'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='52.947' y1='63.641' x2='10.538' y2='37.156'%3E%3Cstop offset='0' stop-color='%237C59A4'/%3E%3Cstop offset='.385' stop-color='%23AF4C92'/%3E%3Cstop offset='.765' stop-color='%23DC4183'/%3E%3Cstop offset='.957' stop-color='%23ED3D7D'/%3E%3C/linearGradient%3E%3Cpath d='M57.1,59.5C57,59.5,17.7,28.5,16.9,28l0,0l0,0c-0.6-0.3-1.2-0.6-1.8-0.9 c-5.8-2.2-12.2,0.8-14.4,6.6c-1.9,5.1,0.2,10.7,4.6,13.4l0,0l0,0C6,47.5,6.6,47.8,7.3,48c0.4,0.2,45.4,18.8,45.4,18.8l0,0 c1.8,0.8,3.9,0.3,5.1-1.2C59.3,63.7,59,61,57.1,59.5z' fill='url(%23c)'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='52.174' y1='3.702' x2='10.771' y2='37.897'%3E%3Cstop offset='0' stop-color='%23EF5A6B'/%3E%3Cstop offset='.364' stop-color='%23EE4E72'/%3E%3Cstop offset='1' stop-color='%23ED3D7D'/%3E%3C/linearGradient%3E%3Cpath d='M49.3,0c-1.7,0-3.3,0.6-4.6,1.5L4.9,28.3c-0.1,0.1-0.2,0.1-0.2,0.2l-0.1,0 l0,0c-1.7,1.2-3.1,3-3.9,5.1C-1.5,39.4,1.5,45.9,7.3,48c3.6,1.4,7.5,0.7,10.4-1.4l0,0l0,0c0.7-0.5,1.3-1,1.8-1.6l34.6-31.2l0,0 c1.8-1.4,3-3.6,3-6.1v0C57.1,3.5,53.6,0,49.3,0z' fill='url(%23d)'/%3E%3Cpath fill='%23000' d='M34.6 37.4H85.6V88.4H34.6z'/%3E%3Cpath fill='%23FFF' d='M39 78.8H58.1V82H39z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M38.8,50.8l1.5-1.4c0.4,0.5,0.8,0.8,1.3,0.8c0.6,0,0.9-0.4,0.9-1.2l0-5.3l2.3,0 l0,5.3c0,1-0.3,1.8-0.8,2.3c-0.5,0.5-1.3,0.8-2.3,0.8C40.2,52.2,39.4,51.6,38.8,50.8z'/%3E%3Cpath d='M45.3,43.8l6.7,0v1.9l-4.4,0V47l4,0l0,1.8l-4,0l0,1.3l4.5,0l0,2l-6.7,0 L45.3,43.8z'/%3E%3Cpath d='M55,45.8l-2.5,0l0-2l7.3,0l0,2l-2.5,0l0,6.3l-2.3,0L55,45.8z'/%3E%3Cpath d='M39,54l4.3,0c1,0,1.8,0.3,2.3,0.7c0.3,0.3,0.5,0.8,0.5,1.4v0 c0,1-0.5,1.5-1.3,1.9c1,0.3,1.6,0.9,1.6,2v0c0,1.4-1.2,2.3-3.1,2.3l-4.3,0L39,54z M43.8,56.6c0-0.5-0.4-0.7-1-0.7l-1.5,0l0,1.5 l1.4,0C43.4,57.3,43.8,57.1,43.8,56.6L43.8,56.6z M43,59l-1.8,0l0,1.5H43c0.7,0,1.1-0.3,1.1-0.8v0C44.1,59.2,43.7,59,43,59z'/%3E%3Cpath d='M46.8,54l3.9,0c1.3,0,2.1,0.3,2.7,0.9c0.5,0.5,0.7,1.1,0.7,1.9v0 c0,1.3-0.7,2.1-1.7,2.6l2,2.9l-2.6,0l-1.7-2.5h-1l0,2.5l-2.3,0L46.8,54z M50.6,58c0.8,0,1.2-0.4,1.2-1v0c0-0.7-0.5-1-1.2-1 l-1.5,0v2H50.6z'/%3E%3Cpath d='M56.8,54l2.2,0l3.5,8.4l-2.5,0l-0.6-1.5l-3.2,0l-0.6,1.5l-2.4,0L56.8,54z M58.8,59l-0.9-2.3L57,59L58.8,59z'/%3E%3Cpath d='M62.8,54l2.3,0l0,8.3l-2.3,0L62.8,54z'/%3E%3Cpath d='M65.7,54l2.1,0l3.4,4.4l0-4.4l2.3,0l0,8.3l-2,0L68,57.8l0,4.6l-2.3,0L65.7,54z'/%3E%3Cpath d='M73.7,61.1l1.3-1.5c0.8,0.7,1.7,1,2.7,1c0.6,0,1-0.2,1-0.6v0 c0-0.4-0.3-0.5-1.4-0.8c-1.8-0.4-3.1-0.9-3.1-2.6v0c0-1.5,1.2-2.7,3.2-2.7c1.4,0,2.5,0.4,3.4,1.1l-1.2,1.6 c-0.8-0.5-1.6-0.8-2.3-0.8c-0.6,0-0.8,0.2-0.8,0.5v0c0,0.4,0.3,0.5,1.4,0.8c1.9,0.4,3.1,1,3.1,2.6v0c0,1.7-1.3,2.7-3.4,2.7 C76.1,62.5,74.7,62,73.7,61.1z'/%3E%3C/g%3E%3C/svg%3E") 12 | } 13 | 14 | .jetbrains-logo._logo-jetbrains._size-1 { 15 | width: 40px; 16 | height: 40px 17 | } 18 | 19 | .jetbrains-logo._logo-jetbrains._size-2 { 20 | width: 60px; 21 | height: 60px 22 | } 23 | 24 | .jetbrains-logo._logo-jetbrains._size-3 { 25 | width: 75px; 26 | height: 75px 27 | } 28 | 29 | .jetbrains-logo._logo-jetbrains._size-4 { 30 | width: 100px; 31 | height: 100px 32 | } 33 | 34 | .jetbrains-logo._logo-jetbrains._size-5 { 35 | width: 150px; 36 | height: 150px 37 | } 38 | 39 | .jetbrains-logo._logo-jetbrains-square { 40 | background-image: url("data:image/svg+xml,%3Csvg data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 700 700'%3E%3Ctitle%3Ejetbrains-simple_2%3C/title%3E%3Cpath d='M0 0H700V700H0z'/%3E%3Cpath fill='%23fff' d='M60.379 568.75H322.879V612.5H60.379z'/%3E%3Cpath d='M57.428,184.315L77.8,165.083c5.542,6.682,10.758,10.594,17.929,10.594,7.823,0,12.877-5.378,12.877-15.972V87.5h31.457v72.367c0,14.343-3.586,24.448-11.246,32.109-7.5,7.5-18.254,11.572-31.294,11.572C77.638,203.548,65.577,195.236,57.428,184.315Z' fill='%23fff'/%3E%3Cpath fill='%23fff' d='M147.394 87.5L239.156 87.5 239.156 114.23 178.688 114.23 178.688 131.67 233.451 131.67 233.451 156.607 178.688 156.607 178.688 174.699 239.971 174.699 239.971 201.592 147.394 201.592 147.394 87.5z'/%3E%3Cpath fill='%23fff' d='M280.491 115.208L246.427 115.208 246.427 87.5 346.338 87.5 346.338 115.208 312.111 115.208 312.111 201.592 280.491 201.592 280.491 115.208z'/%3E%3Cpath d='M139.736,282.7c10.106-4.4,17.6-12.224,17.6-25.426v-0.326A25.675,25.675,0,0,0,150,238.364c-6.682-6.52-16.788-10.106-31.131-10.106H60.362V342.35H119.2c27.218,0,43.191-11.9,43.191-31.457v-0.326C162.392,295.083,153.591,287.26,139.736,282.7Zm-48.57-29.011h20.7c9.29,0,14.343,3.422,14.343,9.779v0.326c0,6.682-5.542,9.942-15.158,9.942H91.166V253.685Zm39.607,52.808c0,6.682-5.379,10.431-15.158,10.431H91.166V295.9h24.123c10.594,0,15.484,4.075,15.484,10.269v0.326Z' fill='%23fff'/%3E%3Cpath d='M335.8,227.444H305.325l-42.63,101.193-17.833-26.056c14.18-6.031,23.469-17.6,23.469-35.205V267.05c0-11.246-3.422-19.885-10.1-26.567-7.661-7.661-19.722-12.224-37.162-12.224H167.116V342.35h31.619V307.8h14.017l22.981,34.553H290l8.15-20.536h44.169l8.149,20.536h33.9Zm-99.093,42.05c0,8.312-6.357,13.529-16.951,13.529H198.736V255.477H219.6c10.432,0,17.114,4.564,17.114,13.692v0.325ZM307.444,297.2l12.877-32.271L333.033,297.2H307.444Z' fill='%23fff'/%3E%3Cpath fill='%23fff' d='M388.119 228.258H419.73800000000006V342.35H388.119z'/%3E%3Cpath fill='%23fff' d='M427.56 228.258L457.061 228.258 504.001 288.564 504.001 228.258 535.295 228.258 535.295 342.35 507.75 342.35 458.854 279.763 458.854 342.35 427.56 342.35 427.56 228.258z'/%3E%3Cpath d='M537.277,325.4l17.6-21.025c11.409,8.964,23.8,13.691,37,13.691,8.638,0,13.2-2.934,13.2-7.824v-0.325c0-4.89-3.749-7.335-19.4-11.084-24.286-5.541-43.03-12.387-43.03-35.694v-0.326c0-21.188,16.788-36.509,44.17-36.509,19.4,0,34.553,5.216,46.94,15.158L617.956,263.79c-10.431-7.5-21.84-11.246-31.946-11.246-7.66,0-11.409,3.1-11.409,7.334V260.2c0,5.216,3.912,7.5,19.885,11.083,26.078,5.7,42.377,14.18,42.377,35.531v0.326c0,23.307-18.418,37.161-46.126,37.161C570.526,344.306,551.457,337.95,537.277,325.4Z' fill='%23fff'/%3E%3C/svg%3E") 41 | } 42 | 43 | .jetbrains-logo._logo-jetbrains-square._size-1 { 44 | width: 40px; 45 | height: 40px 46 | } 47 | 48 | .jetbrains-logo._logo-jetbrains-square._size-2 { 49 | width: 60px; 50 | height: 60px 51 | } 52 | 53 | .jetbrains-logo._logo-jetbrains-square._size-3 { 54 | width: 75px; 55 | height: 75px 56 | } 57 | 58 | .jetbrains-logo._logo-jetbrains-square._size-4 { 59 | width: 100px; 60 | height: 100px 61 | } 62 | 63 | .jetbrains-logo._logo-jetbrains-square._size-5 { 64 | width: 150px; 65 | height: 150px 66 | } 67 | 68 | .jetbrains-logo._logo-appcode { 69 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3Cpath fill='%23247CE6' d='M59.2 55L70 26.3 37.3 19 33 31.2z'/%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='20.617' y1='57.755' x2='70' y2='57.755'%3E%3Cstop offset='.194' stop-color='%2300DAF0'/%3E%3Cstop offset='.903' stop-color='%23247CE6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M70 56.1L53.5 70 20.6 61.5 29.4 45.5z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='1.274' y1='17.415' x2='38.41' y2='17.415'%3E%3Cstop offset='.194' stop-color='%2300DAF0'/%3E%3Cstop offset='.903' stop-color='%23247CE6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M9.7 34.8L1.3 10.8 38.4 0 35.4 31z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='45.876' y1='72.222' x2='11.197' y2='23.824'%3E%3Cstop offset='.091' stop-color='%231DDF93'/%3E%3Cstop offset='.484' stop-color='%2300DAF0'/%3E%3Cstop offset='.903' stop-color='%23247CE6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M61.1 40.5L50.7 22.7 50.9 22.6 38.4 0 0 41.5 0 70 69.8 56.1z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cpath d='M24.5,19h3.6l7.6,17.9h-4.1l-1.6-4h-7.5l-1.6,4h-4L24.5,19z M28.6,29.4l-2.4-5.8l-2.4,5.8H28.6z' fill='%23FFF'/%3E%3Cpath d='M34.7,28.1L34.7,28.1c0-5.2,3.9-9.4,9.4-9.4c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2 c-3,0-5.2,2.5-5.2,5.6V28c0,3.1,2.1,5.7,5.2,5.7c2.1,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.9,2-3.9,3.2-7.4,3.2 C38.6,37.3,34.7,33.2,34.7,28.1' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 70 | } 71 | 72 | .jetbrains-logo._logo-appcode._size-1 { 73 | width: 40px; 74 | height: 40px 75 | } 76 | 77 | .jetbrains-logo._logo-appcode._size-2 { 78 | width: 60px; 79 | height: 60px 80 | } 81 | 82 | .jetbrains-logo._logo-appcode._size-3 { 83 | width: 75px; 84 | height: 75px 85 | } 86 | 87 | .jetbrains-logo._logo-appcode._size-4 { 88 | width: 100px; 89 | height: 100px 90 | } 91 | 92 | .jetbrains-logo._logo-appcode._size-5 { 93 | width: 150px; 94 | height: 150px 95 | } 96 | 97 | .jetbrains-logo._logo-clion { 98 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='22.254' y1='15.137' x2='45.654' y2='15.137'%3E%3Cstop offset='0' stop-color='%23ED358C'/%3E%3Cstop offset='.155' stop-color='%23E9388C'/%3E%3Cstop offset='.297' stop-color='%23DE418C'/%3E%3Cstop offset='.433' stop-color='%23CC508C'/%3E%3Cstop offset='.566' stop-color='%23B2658D'/%3E%3Cstop offset='.697' stop-color='%2390808D'/%3E%3Cstop offset='.826' stop-color='%2367A18E'/%3E%3Cstop offset='.951' stop-color='%2337C78F'/%3E%3Cstop offset='1' stop-color='%2322D88F'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M26.9 28.4L22.3 30.3 26.4 0 42.6 8.8z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='17.8' y1='8.982' x2='7.505' y2='78.065'%3E%3Cstop offset='.091' stop-color='%2322D88F'/%3E%3Cstop offset='.903' stop-color='%23029DE0'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M24.3 42L26.7 0 6.5 12.7 0 51.5z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='63.836' y1='6.492' x2='-6.583' y2='80.865'%3E%3Cstop offset='.091' stop-color='%2322D88F'/%3E%3Cstop offset='.903' stop-color='%23029DE0'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M68.6 21L59.6 2.7 42.6 8.8 30.1 22.7 0 51.5 22.7 68 51.2 42.3z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='40.114' y1='49.366' x2='66.875' y2='53.171'%3E%3Cstop offset='.091' stop-color='%2322D88F'/%3E%3Cstop offset='.903' stop-color='%23029DE0'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M29.4 29.9L25.5 53.9 41.5 66.2 59 70 70 45z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M17.2,28.1L17.2,28.1c0-5.1,3.8-9.3,9.3-9.3c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2 c-3,0-5.2,2.5-5.2,5.6V28c0,3.1,2.1,5.6,5.2,5.6c2,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.8,2-3.9,3.2-7.3,3.2 C21.1,37.3,17.2,33.2,17.2,28.1' fill='%23FFF'/%3E%3Cpath d='M36.4,19.1h3.9v14.6h7.8v3.3H36.4V19.1z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 99 | } 100 | 101 | .jetbrains-logo._logo-clion._size-1 { 102 | width: 40px; 103 | height: 40px 104 | } 105 | 106 | .jetbrains-logo._logo-clion._size-2 { 107 | width: 60px; 108 | height: 60px 109 | } 110 | 111 | .jetbrains-logo._logo-clion._size-3 { 112 | width: 75px; 113 | height: 75px 114 | } 115 | 116 | .jetbrains-logo._logo-clion._size-4 { 117 | width: 100px; 118 | height: 100px 119 | } 120 | 121 | .jetbrains-logo._logo-clion._size-5 { 122 | width: 150px; 123 | height: 150px 124 | } 125 | 126 | .jetbrains-logo._logo-datagrip { 127 | background-image: url("data:image/svg+xml,%3Csvg version='1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3Cpath fill='%239775F8' d='M65.5 10.9L70 39.5 53 49.4 49.8 33.2z'/%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='41.069' y1='54.357' x2='46.521' y2='67.944' gradientTransform='matrix(1 0 0 -1 0 72)'%3E%3Cstop offset='0' stop-color='%239775F8'/%3E%3Cstop offset='.952' stop-color='%2322D88F'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M65.5 10.9L40.5 0 19.4 17.5 49.8 33.2z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='17.067' y1='35.739' x2='24.146' y2='4.895' gradientTransform='matrix(1 0 0 -1 0 72)'%3E%3Cstop offset='0' stop-color='%239775F8'/%3E%3Cstop offset='.214' stop-color='%23689CCE'/%3E%3Cstop offset='.423' stop-color='%2342BDAC'/%3E%3Cstop offset='.59' stop-color='%232BD197'/%3E%3Cstop offset='.694' stop-color='%2322D88F'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M47.3 70L18 30.6 9.3 36.4 0.6 62.5z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='4.9' y1='37.969' x2='66.239' y2='4.102' gradientTransform='matrix(1 0 0 -1 0 72)'%3E%3Cstop offset='.075' stop-color='%2322D88F'/%3E%3Cstop offset='.72' stop-color='%239775F8'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M52.8 50.1L32.3 36.6 0 32.3 47.3 70z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='0' y1='45.15' x2='61.646' y2='45.15' gradientTransform='matrix(1 0 0 -1 0 72)'%3E%3Cstop offset='.075' stop-color='%2322D88F'/%3E%3Cstop offset='.266' stop-color='%235AB0B4'/%3E%3Cstop offset='.565' stop-color='%23B86CF2'/%3E%3Cstop offset='1' stop-color='%23FF59E6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M0 0.5L0 32.3 60.8 53.2 65.5 10.9z'/%3E%3Cg%3E%3Cpath d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.8,19h7c5.6,0,9.5,3.9,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-7V19z M21.7,22.6v10.8h3 c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.7z'/%3E%3Cpath d='M35,28L35,28c0-5.1,4-9.3,9.4-9.3c3.2,0,5.2,0.9,7,2.5l-2.5,3c-1.4-1.2-2.6-1.8-4.7-1.8 c-2.9,0-5.1,2.5-5.1,5.6V28c0,3.3,2.2,5.7,5.4,5.7c1.4,0,2.7-0.4,3.7-1.1V30h-4v-3.4H52v7.8c-1.8,1.6-4.4,2.8-7.6,2.8 C38.8,37.2,35,33.3,35,28z'/%3E%3C/g%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3C/g%3E%3C/svg%3E") 128 | } 129 | 130 | .jetbrains-logo._logo-datagrip._size-1 { 131 | width: 40px; 132 | height: 40px 133 | } 134 | 135 | .jetbrains-logo._logo-datagrip._size-2 { 136 | width: 60px; 137 | height: 60px 138 | } 139 | 140 | .jetbrains-logo._logo-datagrip._size-3 { 141 | width: 75px; 142 | height: 75px 143 | } 144 | 145 | .jetbrains-logo._logo-datagrip._size-4 { 146 | width: 100px; 147 | height: 100px 148 | } 149 | 150 | .jetbrains-logo._logo-datagrip._size-5 { 151 | width: 150px; 152 | height: 150px 153 | } 154 | 155 | .jetbrains-logo._logo-dotcover { 156 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='37.049' y1='55.637' x2='23.558' y2='5.422'%3E%3Cstop offset='.048' stop-color='%237866FF'/%3E%3Cstop offset='.135' stop-color='%238265FA'/%3E%3Cstop offset='.281' stop-color='%239C64EE'/%3E%3Cstop offset='.467' stop-color='%23C661D9'/%3E%3Cstop offset='.608' stop-color='%23EB5FC7'/%3E%3Cstop offset='.729' stop-color='%23FA6398'/%3E%3Cstop offset='.769' stop-color='%23FF6488'/%3E%3Cstop offset='.995' stop-color='%23FF7500'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M42.8 0L0 4.8 0 26.8 10.7 62.6 64.6 48.9z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='69.11' y1='50.451' x2='57.169' y2='46.132'%3E%3Cstop offset='.247' stop-color='%237866FF'/%3E%3Cstop offset='.346' stop-color='%238F5FFA'/%3E%3Cstop offset='.531' stop-color='%23B353F1'/%3E%3Cstop offset='.705' stop-color='%23CD4AEB'/%3E%3Cstop offset='.859' stop-color='%23DD45E7'/%3E%3Cstop offset='.979' stop-color='%23E343E6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M70 41.3L65.9 22.2 56.7 34.9 50.3 54.2 48.2 70 64 60z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='57.012' y1='46.84' x2='23.73' y2='32.867'%3E%3Cstop offset='.006' stop-color='%23E343E6'/%3E%3Cstop offset='.064' stop-color='%23E649CA'/%3E%3Cstop offset='.19' stop-color='%23EF5982'/%3E%3Cstop offset='.372' stop-color='%23FD7110'/%3E%3Cstop offset='.398' stop-color='%23FF7500'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M65.9 22.2L52.5 15.8 36.8 17.2 21.4 27.9 18.3 47.1 31.8 65.5 48.2 70z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.5,19.1h7c5.6,0,9.5,3.9,9.5,8.9v0.1c0,5-3.9,8.9-9.5,8.9h-7V19.1z M21.4,22.7v10.8h3 c3.2,0,5.4-2.2,5.4-5.3v-0.1c0-3.2-2.2-5.4-5.4-5.4H21.4z'/%3E%3Cpath d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M35.4,28.1L35.4,28.1c0-5.1,3.8-9.3,9.3-9.3c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2 c-3,0-5.2,2.5-5.2,5.6v0.1c0,3.1,2.1,5.6,5.2,5.6c2,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.8,2-3.9,3.2-7.3,3.2 C39.4,37.3,35.4,33.3,35.4,28.1'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 157 | } 158 | 159 | .jetbrains-logo._logo-dotcover._size-1 { 160 | width: 40px; 161 | height: 40px 162 | } 163 | 164 | .jetbrains-logo._logo-dotcover._size-2 { 165 | width: 60px; 166 | height: 60px 167 | } 168 | 169 | .jetbrains-logo._logo-dotcover._size-3 { 170 | width: 75px; 171 | height: 75px 172 | } 173 | 174 | .jetbrains-logo._logo-dotcover._size-4 { 175 | width: 100px; 176 | height: 100px 177 | } 178 | 179 | .jetbrains-logo._logo-dotcover._size-5 { 180 | width: 150px; 181 | height: 150px 182 | } 183 | 184 | .jetbrains-logo._logo-dotmemory { 185 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='20.477' y1='18.782' x2='32.464' y2='68.958'%3E%3Cstop offset='0' stop-color='%237866FF'/%3E%3Cstop offset='.023' stop-color='%237E64FE'/%3E%3Cstop offset='.195' stop-color='%23AA56F3'/%3E%3Cstop offset='.349' stop-color='%23C94CEC'/%3E%3Cstop offset='.48' stop-color='%23DC45E8'/%3E%3Cstop offset='.57' stop-color='%23E343E6'/%3E%3Cstop offset='.641' stop-color='%23E859BC'/%3E%3Cstop offset='.819' stop-color='%23F48F58'/%3E%3Cstop offset='.942' stop-color='%23FCB019'/%3E%3Cstop offset='1' stop-color='%23FFBD00'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M8 65.1L0.1 37.6 51.7 45.2 44.3 70z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='49.418' y1='41.451' x2='32.72' y2='7.516'%3E%3Cstop offset='0' stop-color='%237866FF'/%3E%3Cstop offset='.202' stop-color='%23965CF8'/%3E%3Cstop offset='.64' stop-color='%23E343E6'/%3E%3Cstop offset='.968' stop-color='%23FFBD00'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M23.5 0.1L42.1 5.4 63.2 0 70 46.3 13.4 37.6z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='26.353' y1='53.604' x2='36.21' y2='30.222'%3E%3Cstop offset='.118' stop-color='%23E343E6'/%3E%3Cstop offset='.211' stop-color='%23C84CEC'/%3E%3Cstop offset='.338' stop-color='%23AB55F3'/%3E%3Cstop offset='.472' stop-color='%23955DF8'/%3E%3Cstop offset='.618' stop-color='%238562FC'/%3E%3Cstop offset='.781' stop-color='%237B65FE'/%3E%3Cstop offset='1' stop-color='%237866FF'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M70 46.1L67.3 28.9 25.6 14.4 0.1 19.9 0 37.7 49.6 51.3z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cpath d='M17.4,19h6.9c5.6,0,9.5,3.9,9.5,8.9V28c0,5-3.9,9-9.5,9h-6.9V19z M21.3,22.6v10.8h2.9 c3.2,0,5.4-2.2,5.4-5.4V28c0-3.2-2.2-5.4-5.4-5.4H21.3z' fill='%23FFF'/%3E%3Cpath fill='%23FFF' d='M34.8 19.1L39.1 19.1 43.7 26.6 48.4 19.1 52.6 19.1 52.6 36.9 48.7 36.9 48.7 25.2 43.7 32.8 43.6 32.8 38.7 25.3 38.7 36.9 34.8 36.9z'/%3E%3C/g%3E%3C/svg%3E") 186 | } 187 | 188 | .jetbrains-logo._logo-dotmemory._size-1 { 189 | width: 40px; 190 | height: 40px 191 | } 192 | 193 | .jetbrains-logo._logo-dotmemory._size-2 { 194 | width: 60px; 195 | height: 60px 196 | } 197 | 198 | .jetbrains-logo._logo-dotmemory._size-3 { 199 | width: 75px; 200 | height: 75px 201 | } 202 | 203 | .jetbrains-logo._logo-dotmemory._size-4 { 204 | width: 100px; 205 | height: 100px 206 | } 207 | 208 | .jetbrains-logo._logo-dotmemory._size-5 { 209 | width: 150px; 210 | height: 150px 211 | } 212 | 213 | .jetbrains-logo._logo-dotpeek { 214 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='10.879' y1='26.793' x2='47.049' y2='63.717'%3E%3Cstop offset='.097' stop-color='%23E343E6'/%3E%3Cstop offset='.108' stop-color='%23D948E8'/%3E%3Cstop offset='.165' stop-color='%23AC5DEF'/%3E%3Cstop offset='.222' stop-color='%23876FF5'/%3E%3Cstop offset='.279' stop-color='%236B7DF9'/%3E%3Cstop offset='.336' stop-color='%235687FC'/%3E%3Cstop offset='.392' stop-color='%234A8DFE'/%3E%3Cstop offset='.446' stop-color='%23468FFF'/%3E%3Cstop offset='.935' stop-color='%2300CAFF'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M44.3 20.9L5.2 30.3 0 40.8 14.1 70 49.3 63.9z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='9.66' y1='55.746' x2='32.843' y2='36.427'%3E%3Cstop offset='.097' stop-color='%23E343E6'/%3E%3Cstop offset='.118' stop-color='%23DE45E7'/%3E%3Cstop offset='.289' stop-color='%23B951F0'/%3E%3Cstop offset='.462' stop-color='%239D5AF6'/%3E%3Cstop offset='.632' stop-color='%238861FB'/%3E%3Cstop offset='.802' stop-color='%237C65FE'/%3E%3Cstop offset='.968' stop-color='%237866FF'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M65.8 31.5L38.2 14 0 22.1 0 40.8 62.6 53.3z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='39.855' y1='16.927' x2='56.356' y2='50.653'%3E%3Cstop offset='.199' stop-color='%23E343E6'/%3E%3Cstop offset='.31' stop-color='%23DA46E8'/%3E%3Cstop offset='.491' stop-color='%23C24EEE'/%3E%3Cstop offset='.718' stop-color='%239A5BF7'/%3E%3Cstop offset='.887' stop-color='%237866FF'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M70 31.3L39.6 0 15.8 7.2 23.6 30.9 62.6 53.3z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='19.875' y1='18.305' x2='61.328' y2='8.256'%3E%3Cstop offset='.097' stop-color='%23E343E6'/%3E%3Cstop offset='.175' stop-color='%23DA48E7'/%3E%3Cstop offset='.302' stop-color='%23C157EA'/%3E%3Cstop offset='.464' stop-color='%23996FEE'/%3E%3Cstop offset='.653' stop-color='%236290F4'/%3E%3Cstop offset='.863' stop-color='%231CB9FC'/%3E%3Cstop offset='.941' stop-color='%2300CAFF'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M64.5 19.6L61.8 0 51.3 0 39.6 0 15.8 7.2 23.6 30.9z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.5,19.1h7c5.6,0,9.5,3.9,9.5,8.9v0.1c0,5-3.9,8.9-9.5,8.9h-7V19.1z M21.4,22.7v10.8h3 c3.2,0,5.4-2.2,5.4-5.3v-0.1c0-3.2-2.2-5.4-5.4-5.4H21.4z'/%3E%3Cpath d='M35.6,19.1h7.3c4.3,0,6.9,2.5,6.9,6.2v0.1c0,4.1-3.2,6.3-7.2,6.3h-3V37h-3.9V19.1z M42.6,28.1 c2,0,3.1-1.2,3.1-2.7v-0.1c0-1.8-1.2-2.7-3.2-2.7h-3v5.5H42.6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 215 | } 216 | 217 | .jetbrains-logo._logo-dotpeek._size-1 { 218 | width: 40px; 219 | height: 40px 220 | } 221 | 222 | .jetbrains-logo._logo-dotpeek._size-2 { 223 | width: 60px; 224 | height: 60px 225 | } 226 | 227 | .jetbrains-logo._logo-dotpeek._size-3 { 228 | width: 75px; 229 | height: 75px 230 | } 231 | 232 | .jetbrains-logo._logo-dotpeek._size-4 { 233 | width: 100px; 234 | height: 100px 235 | } 236 | 237 | .jetbrains-logo._logo-dotpeek._size-5 { 238 | width: 150px; 239 | height: 150px 240 | } 241 | 242 | .jetbrains-logo._logo-dottrace { 243 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='-1.332' y1='43.737' x2='67.042' y2='26.097'%3E%3Cstop offset='.124' stop-color='%237866FF'/%3E%3Cstop offset='.538' stop-color='%23FE2EB6'/%3E%3Cstop offset='.855' stop-color='%23FD0486'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M67.3 16L43.7 0 0 31.1 11.1 70 58.9 60.3z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='45.915' y1='38.91' x2='67.658' y2='9.099'%3E%3Cstop offset='.124' stop-color='%23FF0080'/%3E%3Cstop offset='.259' stop-color='%23FE0385'/%3E%3Cstop offset='.411' stop-color='%23FA0C92'/%3E%3Cstop offset='.571' stop-color='%23F41BA9'/%3E%3Cstop offset='.736' stop-color='%23EB2FC8'/%3E%3Cstop offset='.866' stop-color='%23E343E6'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M67.3 16L43.7 0 38 15.7 38 47.8 70 47.8z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.4,19.1h6.9c5.6,0,9.5,3.8,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-6.9V19.1z M21.4,22.7v10.7h3 c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.4z'/%3E%3Cpath d='M40.3 22.7L34.9 22.7 34.9 19.1 49.6 19.1 49.6 22.7 44.2 22.7 44.2 37 40.3 37z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 244 | } 245 | 246 | .jetbrains-logo._logo-dottrace._size-1 { 247 | width: 40px; 248 | height: 40px 249 | } 250 | 251 | .jetbrains-logo._logo-dottrace._size-2 { 252 | width: 60px; 253 | height: 60px 254 | } 255 | 256 | .jetbrains-logo._logo-dottrace._size-3 { 257 | width: 75px; 258 | height: 75px 259 | } 260 | 261 | .jetbrains-logo._logo-dottrace._size-4 { 262 | width: 100px; 263 | height: 100px 264 | } 265 | 266 | .jetbrains-logo._logo-dottrace._size-5 { 267 | width: 150px; 268 | height: 150px 269 | } 270 | 271 | .jetbrains-logo._logo-gogland { 272 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='218.31' y1='276.731' x2='206.336' y2='294.988' gradientTransform='translate(-286.906 -405.031) scale(1.5625)'%3E%3Cstop offset='.174' stop-color='%23078EFC'/%3E%3Cstop offset='.204' stop-color='%23118AFC'/%3E%3Cstop offset='.435' stop-color='%235971FC'/%3E%3Cstop offset='.627' stop-color='%238E5EFC'/%3E%3Cstop offset='.77' stop-color='%23AF52FC'/%3E%3Cstop offset='.849' stop-color='%23BB4EFC'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M57.274,22.361l9.541,21.197l-13.49,23.045L20.922,40.202L37.493,24.23L57.274,22.361z'/%3E%3Cpath fill='%23BB4EFC' d='M43.499,42.747l9.826,23.857L23.39,56.314l-2.468-16.111L43.499,42.747z'/%3E%3Cpath fill='%23078EFC' d='M24.281,9.433l13.776,7.06l-12.398,37.54L0.69,53.773l5.364-11.895L0.69,26.677L24.281,9.433z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='188.25' y1='278.506' x2='212.533' y2='260.237' gradientTransform='translate(-286.906 -405.031) scale(1.5625)'%3E%3Cstop offset='.174' stop-color='%23078EFC'/%3E%3Cstop offset='.204' stop-color='%23118AFC'/%3E%3Cstop offset='.435' stop-color='%235971FC'/%3E%3Cstop offset='.627' stop-color='%238E5EFC'/%3E%3Cstop offset='.77' stop-color='%23AF52FC'/%3E%3Cstop offset='.849' stop-color='%23BB4EFC'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M41.563,0.479l6.515,22.17L0.69,26.677L15.761,0.479H41.563z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='189.941' y1='296.496' x2='220.469' y2='276.879' gradientTransform='translate(-286.906 -405.031) scale(1.5625)'%3E%3Cstop offset='0' stop-color='%23078EFC'/%3E%3Cstop offset='.106' stop-color='%2315A7D3'/%3E%3Cstop offset='.228' stop-color='%2323BFAA'/%3E%3Cstop offset='.348' stop-color='%232DD28B'/%3E%3Cstop offset='.463' stop-color='%2335DF74'/%3E%3Cstop offset='.573' stop-color='%2339E767'/%3E%3Cstop offset='.67' stop-color='%233BEA62'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M66.815 14.519L39.091 21.099 0.69 53.773 25.458 66.604 46.973 44.423z'/%3E%3Cg%3E%3Cpath d='M11.711 11.5H55.794V55.583H11.711z'/%3E%3Cpath fill='%23FFF' d='M16.119 48.309H32.65V50.954H16.119z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M14.607,25.88v-0.054c-0.18-5.295,3.967-9.734,9.262-9.913c0.09-0.003,0.179-0.005,0.269-0.005 c2.64-0.135,5.22,0.815,7.142,2.63l-2.52,3.206c-1.251-1.272-2.969-1.975-4.753-1.945c-3.083,0.226-5.41,2.889-5.22,5.974v0.054 c-0.258,3.091,2.039,5.805,5.13,6.063c0.125,0.01,0.251,0.017,0.377,0.019c1.347,0.04,2.67-0.365,3.765-1.151v-2.74h-4.025v-3.643 h7.895v8.328c-2.113,1.955-4.886,3.041-7.765,3.043c-5.162,0.123-9.446-3.963-9.569-9.125c0,0,0,0,0,0 C14.59,26.374,14.594,26.127,14.607,25.88z'/%3E%3Cpath d='M33.609,25.88v-0.054c-0.141-5.335,4.069-9.774,9.405-9.915s9.774,4.069,9.915,9.405 c0.004,0.152,0.004,0.305,0.001,0.457v0.054c0.141,5.335-4.069,9.774-9.405,9.915c-5.335,0.141-9.774-4.069-9.915-9.405l0,0 C33.606,26.185,33.606,26.033,33.609,25.88z M48.75,25.88v-0.054c0.186-3.14-2.209-5.835-5.349-6.021 c-0.053-0.003-0.105-0.005-0.158-0.007c-3.096,0.078-5.542,2.65-5.464,5.746c0,0,0,0,0,0c0.002,0.076,0.005,0.152,0.01,0.229 v0.054c-0.186,3.14,2.209,5.835,5.349,6.021c0.053,0.003,0.105,0.005,0.158,0.007c3.096-0.078,5.542-2.65,5.464-5.746c0,0,0,0,0,0 C48.758,26.033,48.755,25.956,48.75,25.88z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 273 | } 274 | 275 | .jetbrains-logo._logo-gogland._size-1 { 276 | width: 40px; 277 | height: 40px 278 | } 279 | 280 | .jetbrains-logo._logo-gogland._size-2 { 281 | width: 60px; 282 | height: 60px 283 | } 284 | 285 | .jetbrains-logo._logo-gogland._size-3 { 286 | width: 75px; 287 | height: 75px 288 | } 289 | 290 | .jetbrains-logo._logo-gogland._size-4 { 291 | width: 100px; 292 | height: 100px 293 | } 294 | 295 | .jetbrains-logo._logo-gogland._size-5 { 296 | width: 150px; 297 | height: 150px 298 | } 299 | 300 | .jetbrains-logo._logo-hub { 301 | background-image: url("data:image/svg+xml,%3Csvg version='1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' viewBox='0 0 70 70' width='70' height='70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='40.415' y1='69.001' x2='39.585' y2='30.566' gradientTransform='matrix(1 0 0 -1 0 69.89)'%3E%3Cstop offset='.328' stop-color='%2300B8F1'/%3E%3Cstop offset='.973' stop-color='%239758FB'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M61.3,0.9c-1.7-0.8-3.6-1-5.5-0.8c-0.3,0-45.3,3.8-45.3,3.8l31.8,37.5l5.8,0.3L66.3,22 C72.4,15.9,71.1,5,61.3,0.9z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='58.345' y1='64.017' x2='11.932' y2='13.636'%3E%3Cstop offset='0' stop-color='%23FFEE45'/%3E%3Cstop offset='1' stop-color='%239758FB'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M53.6,47.2l-1.3,2l-16-19.5L20.8,40.1L46.5,68c0.5,0.5,1.2,0.9,1.9,1.3c1.4,0.7,3,0.9,4.6,0.4 c1.5-0.4,2.6-1.2,3.5-2.1c0.1-0.1,10.8-10.7,10.8-10.7L53.6,47.2z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='31.025' y1='60.401' x2='21.392' y2='39.808' gradientTransform='matrix(1 0 0 -1 0 69.89)'%3E%3Cstop offset='.328' stop-color='%2300B8F1'/%3E%3Cstop offset='.79' stop-color='%239758FB'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M45.7,41.6L19.6,8.4l0,0c-1.1-1.6-2.8-2.9-5-3.8c-1.7-0.7-3.7-0.9-5.5-0.5 C-0.5,6.2-2.7,16.7,3.5,22.3l18.1,18.6L45.7,41.6z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='-3.259' y1='17.766' x2='68.816' y2='17.766' gradientTransform='matrix(1 0 0 -1 0 69.89)'%3E%3Cstop offset='0' stop-color='%2300B8F1'/%3E%3Cstop offset='.306' stop-color='%239758FB'/%3E%3Cstop offset='.989' stop-color='%23FFEE45'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M63.2,40.5c-3.4-1-5.3-0.7-9.8-0.8l-38-5.4L4.5,44.7c-6.9,6.8-5.8,18.7,4.4,23.8 c2.6,1.3,5.5,1.7,8.2,1.3l0,0c19.3-3.6,43.5-9.4,43.7-9.4c0.4-0.1,0.9-0.2,1.3-0.3c6.3-1.9,8.9-7.8,7.4-12.8 C68.7,44.5,66.5,41.5,63.2,40.5z'/%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.4,19.1h4v7.2h7.4v-7.2h4v18.1h-4v-7.3h-7.4v7.3h-4V19.1z'/%3E%3Cpath d='M35.7,19.1h8.4c2.1,0,3.7,0.6,4.7,1.6c0.8,0.8,1.2,1.8,1.2,3.1v0.1c0,2-1.1,3.2-2.4,3.9 c2.1,0.8,3.4,2,3.4,4.5v0.1c0,3.3-2.7,5-6.8,5h-8.6V19.1H35.7z M46.2,24.4c0-1.2-0.9-1.9-2.6-1.9h-3.9v3.8h3.7 C45.1,26.4,46.2,25.8,46.2,24.4L46.2,24.4z M44.2,29.7h-4.6v4h4.7c1.8,0,2.8-0.6,2.8-2v-0.1C47.2,30.5,46.3,29.7,44.2,29.7z'/%3E%3C/g%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3C/svg%3E") 302 | } 303 | 304 | .jetbrains-logo._logo-hub._size-1 { 305 | width: 40px; 306 | height: 40px 307 | } 308 | 309 | .jetbrains-logo._logo-hub._size-2 { 310 | width: 60px; 311 | height: 60px 312 | } 313 | 314 | .jetbrains-logo._logo-hub._size-3 { 315 | width: 75px; 316 | height: 75px 317 | } 318 | 319 | .jetbrains-logo._logo-hub._size-4 { 320 | width: 100px; 321 | height: 100px 322 | } 323 | 324 | .jetbrains-logo._logo-hub._size-5 { 325 | width: 150px; 326 | height: 150px 327 | } 328 | 329 | .jetbrains-logo._logo-intellij-idea { 330 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='.79' y1='40.089' x2='33.317' y2='40.089'%3E%3Cstop offset='.258' stop-color='%23F97A12'/%3E%3Cstop offset='.459' stop-color='%23B07B58'/%3E%3Cstop offset='.724' stop-color='%23577BAE'/%3E%3Cstop offset='.91' stop-color='%231E7CE5'/%3E%3Cstop offset='1' stop-color='%23087CFA'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M17.7 54.6L0.8 41.2 9.2 25.6 33.3 35z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='25.767' y1='24.88' x2='79.424' y2='54.57'%3E%3Cstop offset='0' stop-color='%23F97A12'/%3E%3Cstop offset='.072' stop-color='%23CB7A3E'/%3E%3Cstop offset='.154' stop-color='%239E7B6A'/%3E%3Cstop offset='.242' stop-color='%23757B91'/%3E%3Cstop offset='.334' stop-color='%23537BB1'/%3E%3Cstop offset='.432' stop-color='%23387CCC'/%3E%3Cstop offset='.538' stop-color='%23237CE0'/%3E%3Cstop offset='.655' stop-color='%23147CEF'/%3E%3Cstop offset='.792' stop-color='%230B7CF7'/%3E%3Cstop offset='1' stop-color='%23087CFA'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M70 18.7L68.7 59.2 41.8 70 25.6 59.6 49.3 35 38.9 12.3 48.2 1.1z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='63.228' y1='42.915' x2='48.29' y2='-1.719'%3E%3Cstop offset='0' stop-color='%23FE315D'/%3E%3Cstop offset='.078' stop-color='%23CB417E'/%3E%3Cstop offset='.16' stop-color='%239E4E9B'/%3E%3Cstop offset='.247' stop-color='%23755BB4'/%3E%3Cstop offset='.339' stop-color='%235365CA'/%3E%3Cstop offset='.436' stop-color='%23386DDB'/%3E%3Cstop offset='.541' stop-color='%232374E9'/%3E%3Cstop offset='.658' stop-color='%231478F3'/%3E%3Cstop offset='.794' stop-color='%230B7BF8'/%3E%3Cstop offset='1' stop-color='%23087CFA'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M70 18.7L48.7 43.9 38.9 12.3 48.2 1.1z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='10.72' y1='16.473' x2='55.524' y2='90.58'%3E%3Cstop offset='0' stop-color='%23FE315D'/%3E%3Cstop offset='.04' stop-color='%23F63462'/%3E%3Cstop offset='.104' stop-color='%23DF3A71'/%3E%3Cstop offset='.167' stop-color='%23C24383'/%3E%3Cstop offset='.291' stop-color='%23AD4A91'/%3E%3Cstop offset='.55' stop-color='%23755BB4'/%3E%3Cstop offset='.917' stop-color='%231D76ED'/%3E%3Cstop offset='1' stop-color='%23087CFA'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M33.7 58.1L5.6 68.3 10.1 52.5 16 33.1 0 27.7 10.1 0 32.1 2.7 53.7 27.4z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.7 13.5H56.900000000000006V56.7H13.7z'/%3E%3Cpath fill='%23FFF' d='M17.7 48.6H33.9V51.300000000000004H17.7z'/%3E%3Cpath fill='%23FFF' d='M29.4 22.4L29.4 19.1 20.4 19.1 20.4 22.4 23 22.4 23 33.7 20.4 33.7 20.4 37 29.4 37 29.4 33.7 26.9 33.7 26.9 22.4z'/%3E%3Cpath d='M38,37.3c-1.4,0-2.6-0.3-3.5-0.8c-0.9-0.5-1.7-1.2-2.3-1.9l2.5-2.8c0.5,0.6,1,1,1.5,1.3 c0.5,0.3,1.1,0.5,1.7,0.5c0.7,0,1.3-0.2,1.8-0.7c0.4-0.5,0.6-1.2,0.6-2.3V19.1h4v11.7c0,1.1-0.1,2-0.4,2.8c-0.3,0.8-0.7,1.4-1.3,2 c-0.5,0.5-1.2,1-2,1.2C39.8,37.1,39,37.3,38,37.3' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 331 | } 332 | 333 | .jetbrains-logo._logo-intellij-idea._size-1 { 334 | width: 40px; 335 | height: 40px 336 | } 337 | 338 | .jetbrains-logo._logo-intellij-idea._size-2 { 339 | width: 60px; 340 | height: 60px 341 | } 342 | 343 | .jetbrains-logo._logo-intellij-idea._size-3 { 344 | width: 75px; 345 | height: 75px 346 | } 347 | 348 | .jetbrains-logo._logo-intellij-idea._size-4 { 349 | width: 100px; 350 | height: 100px 351 | } 352 | 353 | .jetbrains-logo._logo-intellij-idea._size-5 { 354 | width: 150px; 355 | height: 150px 356 | } 357 | 358 | .jetbrains-logo._logo-kotlin { 359 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' viewBox='0 0 60 60' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='15.959' y1='-13.014' x2='44.307' y2='15.333' gradientTransform='matrix(1 0 0 -1 0 61)'%3E%3Cstop offset='.097' stop-color='%230095D5'/%3E%3Cstop offset='.301' stop-color='%23238AD9'/%3E%3Cstop offset='.621' stop-color='%23557BDE'/%3E%3Cstop offset='.864' stop-color='%237472E2'/%3E%3Cstop offset='1' stop-color='%23806EE3'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M0 60L30.1 29.9 60 60z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='4.209' y1='48.941' x2='20.673' y2='65.405' gradientTransform='matrix(1 0 0 -1 0 61)'%3E%3Cstop offset='.118' stop-color='%230095D5'/%3E%3Cstop offset='.418' stop-color='%233C83DC'/%3E%3Cstop offset='.696' stop-color='%236D74E1'/%3E%3Cstop offset='.833' stop-color='%23806EE3'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M0 0L30.1 0 0 32.5z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='-10.102' y1='5.836' x2='45.731' y2='61.669' gradientTransform='matrix(1 0 0 -1 0 61)'%3E%3Cstop offset='.107' stop-color='%23C757BC'/%3E%3Cstop offset='.214' stop-color='%23D0609A'/%3E%3Cstop offset='.425' stop-color='%23E1725C'/%3E%3Cstop offset='.605' stop-color='%23EE7E2F'/%3E%3Cstop offset='.743' stop-color='%23F58613'/%3E%3Cstop offset='.823' stop-color='%23F88909'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M30.1 0L0 31.7 0 60 30.1 29.9 60 0z'/%3E%3C/svg%3E") 360 | } 361 | 362 | .jetbrains-logo._logo-kotlin._size-1 { 363 | width: 40px; 364 | height: 40px 365 | } 366 | 367 | .jetbrains-logo._logo-kotlin._size-2 { 368 | width: 60px; 369 | height: 60px 370 | } 371 | 372 | .jetbrains-logo._logo-kotlin._size-3 { 373 | width: 75px; 374 | height: 75px 375 | } 376 | 377 | .jetbrains-logo._logo-kotlin._size-4 { 378 | width: 100px; 379 | height: 100px 380 | } 381 | 382 | .jetbrains-logo._logo-kotlin._size-5 { 383 | width: 150px; 384 | height: 150px 385 | } 386 | 387 | .jetbrains-logo._logo-mps { 388 | background-image: url("data:image/svg+xml,%3Csvg data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 140 140'%3E%3Cdefs%3E%3ClinearGradient id='a' x1='105.979' y1='186.085' x2='-27.244' y2='15.44' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.091' stop-color='%230b8fff'/%3E%3Cstop offset='.208' stop-color='%230d94f6'/%3E%3Cstop offset='.396' stop-color='%2311a3de'/%3E%3Cstop offset='.633' stop-color='%2318bbb7'/%3E%3Cstop offset='.871' stop-color='%2321d789'/%3E%3C/linearGradient%3E%3ClinearGradient id='b' x1='178.605' y1='129.386' x2='45.382' y2='-41.259' xlink:href='%23a'/%3E%3ClinearGradient id='c' x1='78.586' y1='105.516' x2='126.297' y2='-22.788' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.123' stop-color='%2321d789'/%3E%3Cstop offset='.132' stop-color='%2327d788'/%3E%3Cstop offset='.216' stop-color='%2359d87b'/%3E%3Cstop offset='.303' stop-color='%2385d970'/%3E%3Cstop offset='.394' stop-color='%23abda67'/%3E%3Cstop offset='.487' stop-color='%23cadb5f'/%3E%3Cstop offset='.585' stop-color='%23e1db59'/%3E%3Cstop offset='.688' stop-color='%23f2dc55'/%3E%3Cstop offset='.802' stop-color='%23fcdc53'/%3E%3Cstop offset='.946' stop-color='%23ffdc52'/%3E%3C/linearGradient%3E%3C/defs%3E%3Ctitle%3Emps_logo%3C/title%3E%3Cpath fill='url(%23a)' d='M0 140L140 140 70 70 0 0 0 140z'/%3E%3Cpath data-name='<Path>' fill='url(%23b)' d='M140 140L70 70 140 0 140 140z'/%3E%3Cpath data-name='<Path>' fill='url(%23c)' d='M102 102L70 70 140 0 102 102z'/%3E%3C/svg%3E") 389 | } 390 | 391 | .jetbrains-logo._logo-mps._size-1 { 392 | width: 40px; 393 | height: 40px 394 | } 395 | 396 | .jetbrains-logo._logo-mps._size-2 { 397 | width: 60px; 398 | height: 60px 399 | } 400 | 401 | .jetbrains-logo._logo-mps._size-3 { 402 | width: 75px; 403 | height: 75px 404 | } 405 | 406 | .jetbrains-logo._logo-mps._size-4 { 407 | width: 100px; 408 | height: 100px 409 | } 410 | 411 | .jetbrains-logo._logo-mps._size-5 { 412 | width: 150px; 413 | height: 150px 414 | } 415 | 416 | .jetbrains-logo._logo-phpstorm { 417 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='.558' y1='46.846' x2='29.947' y2='8.026'%3E%3Cstop offset='.016' stop-color='%23765AF8'/%3E%3Cstop offset='.382' stop-color='%23B345F1'/%3E%3Cstop offset='.758' stop-color='%23FA3293'/%3E%3Cstop offset='.941' stop-color='%23FF318C'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M39.6 15.2L36.3 5.2 11.9 0 0 13.5 37.2 32.5z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='2.73' y1='48.379' x2='32.072' y2='9.621'%3E%3Cstop offset='.016' stop-color='%23765AF8'/%3E%3Cstop offset='.382' stop-color='%23B345F1'/%3E%3Cstop offset='.758' stop-color='%23FA3293'/%3E%3Cstop offset='.941' stop-color='%23FF318C'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M28 41.4L27.3 20.6 0 13.5 6.7 53.6 28 53.4z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='50.857' y1='46.405' x2='34.274' y2='7.048'%3E%3Cstop offset='.183' stop-color='%23765AF8'/%3E%3Cstop offset='.238' stop-color='%238655F6'/%3E%3Cstop offset='.345' stop-color='%239F4CF3'/%3E%3Cstop offset='.443' stop-color='%23AE47F2'/%3E%3Cstop offset='.522' stop-color='%23B345F1'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M22.1 41L23.4 24.5 43.2 4.2 60.9 7.4 70 30.1 60.5 39.5 45 37 35.4 47.1z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='63.266' y1='57.339' x2='24.698' y2='27.516'%3E%3Cstop offset='.016' stop-color='%23765AF8'/%3E%3Cstop offset='.382' stop-color='%23B345F1'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M43.2 4.2L14.8 29.4 20.3 61.8 43.9 70 70 54.4z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M17.3,19h7.3c4.3,0,6.9,2.5,6.9,6.2v0.1c0,4.2-3.2,6.3-7.3,6.3h-3l0,5.4h-3.9L17.3,19z M24.4,28 c2,0,3.1-1.2,3.1-2.7v-0.1c0-1.8-1.2-2.7-3.2-2.7h-3V28H24.4z' fill='%23FFF'/%3E%3Cpath d='M32.5,34.4l2.3-2.8c1.6,1.3,3.3,2.2,5.4,2.2c1.6,0,2.6-0.6,2.6-1.7V32c0-1-0.6-1.5-3.6-2.3 c-3.6-0.9-6-1.9-6-5.5v-0.1c0-3.3,2.6-5.4,6.3-5.4c2.6,0,4.9,0.8,6.7,2.3l-2.1,3c-1.6-1.1-3.2-1.8-4.7-1.8c-1.5,0-2.3,0.7-2.3,1.6 v0.1c0,1.2,0.8,1.6,3.9,2.4c3.6,1,5.7,2.3,5.7,5.4v0.1c0,3.6-2.7,5.6-6.6,5.6C37.4,37.3,34.7,36.3,32.5,34.4' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 418 | } 419 | 420 | .jetbrains-logo._logo-phpstorm._size-1 { 421 | width: 40px; 422 | height: 40px 423 | } 424 | 425 | .jetbrains-logo._logo-phpstorm._size-2 { 426 | width: 60px; 427 | height: 60px 428 | } 429 | 430 | .jetbrains-logo._logo-phpstorm._size-3 { 431 | width: 75px; 432 | height: 75px 433 | } 434 | 435 | .jetbrains-logo._logo-phpstorm._size-4 { 436 | width: 100px; 437 | height: 100px 438 | } 439 | 440 | .jetbrains-logo._logo-phpstorm._size-5 { 441 | width: 150px; 442 | height: 150px 443 | } 444 | 445 | .jetbrains-logo._logo-pycharm { 446 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='24.998' y1='27.046' x2='66.656' y2='27.046'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='1' stop-color='%2307C3F2'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M49.1 11L69.5 28.1 62.2 43 49.8 39.6 39.2 39.6z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='-24.559' y1='59.081' x2='61.22' y2='-4.241'%3E%3Cstop offset='.011' stop-color='%23FCF84A'/%3E%3Cstop offset='.112' stop-color='%23A7EB62'/%3E%3Cstop offset='.206' stop-color='%235FE077'/%3E%3Cstop offset='.273' stop-color='%2332DA84'/%3E%3Cstop offset='.306' stop-color='%2321D789'/%3E%3Cstop offset='.577' stop-color='%2321D789'/%3E%3Cstop offset='.597' stop-color='%2321D789'/%3E%3Cstop offset='.686' stop-color='%2320D68C'/%3E%3Cstop offset='.763' stop-color='%231ED497'/%3E%3Cstop offset='.835' stop-color='%2319D1A9'/%3E%3Cstop offset='.904' stop-color='%2313CCC2'/%3E%3Cstop offset='.971' stop-color='%230BC6E1'/%3E%3Cstop offset='1' stop-color='%2307C3F2'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M28.5 22.1L24.5 43 24.1 50.2 14.2 54.5 0 56 4.3 10.7 29.9 0 45.7 10.4z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='9.33' y1='77.654' x2='23.637' y2='32.76'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='.164' stop-color='%2324D788'/%3E%3Cstop offset='.305' stop-color='%232FD886'/%3E%3Cstop offset='.437' stop-color='%2341DA82'/%3E%3Cstop offset='.564' stop-color='%235ADC7D'/%3E%3Cstop offset='.688' stop-color='%237AE077'/%3E%3Cstop offset='.809' stop-color='%23A1E36E'/%3E%3Cstop offset='.925' stop-color='%23CFE865'/%3E%3Cstop offset='1' stop-color='%23F1EB5E'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M28.5 22.1L30.4 62.5 24 70 0 56 19.7 26.6z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='28.275' y1='38.623' x2='59.409' y2='-3.236'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='.061' stop-color='%2324D788'/%3E%3Cstop offset='.113' stop-color='%232FD886'/%3E%3Cstop offset='.162' stop-color='%2341DA82'/%3E%3Cstop offset='.209' stop-color='%235ADD7D'/%3E%3Cstop offset='.255' stop-color='%2379E077'/%3E%3Cstop offset='.258' stop-color='%237CE076'/%3E%3Cstop offset='.499' stop-color='%238CE173'/%3E%3Cstop offset='.925' stop-color='%23B2E56B'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M54.9 19.1L30.6 19.1 52.1 0z'/%3E%3ClinearGradient id='e' gradientUnits='userSpaceOnUse' x1='75.889' y1='43.95' x2='13.158' y2='43.369'%3E%3Cstop offset='.387' stop-color='%23FCF84A'/%3E%3Cstop offset='.536' stop-color='%23ECF451'/%3E%3Cstop offset='.826' stop-color='%23C2E964'/%3E%3Cstop offset='.925' stop-color='%23B2E56B'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23e)' d='M70 62.6L48.6 69.9 20.2 61.9 28.5 22.1 31.8 19.1 49.1 17.5 47.5 34.9 61.3 29.6z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M17.3,19.1h7.3c4.3,0,6.9,2.5,6.9,6.2v0.1c0,4.1-3.2,6.3-7.2,6.3h-3V37h-3.9V19.1z M24.4,28.1 c2,0,3.1-1.2,3.1-2.7v-0.1c0-1.8-1.2-2.7-3.2-2.7h-3v5.5H24.4z' fill='%23FFF'/%3E%3Cpath d='M33.1,28.1L33.1,28.1c0-5.1,3.8-9.3,9.3-9.3c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2 c-3,0-5.2,2.5-5.2,5.6V28c0,3.1,2.1,5.6,5.2,5.6c2,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.8,2-3.9,3.2-7.3,3.2C37,37.3,33.1,33.2,33.1,28.1' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 447 | } 448 | 449 | .jetbrains-logo._logo-pycharm._size-1 { 450 | width: 40px; 451 | height: 40px 452 | } 453 | 454 | .jetbrains-logo._logo-pycharm._size-2 { 455 | width: 60px; 456 | height: 60px 457 | } 458 | 459 | .jetbrains-logo._logo-pycharm._size-3 { 460 | width: 75px; 461 | height: 75px 462 | } 463 | 464 | .jetbrains-logo._logo-pycharm._size-4 { 465 | width: 100px; 466 | height: 100px 467 | } 468 | 469 | .jetbrains-logo._logo-pycharm._size-5 { 470 | width: 150px; 471 | height: 150px 472 | } 473 | 474 | .jetbrains-logo._logo-pycharm-edu { 475 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='24.998' y1='27.046' x2='66.656' y2='27.046'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='1' stop-color='%2307C3F2'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M49.1 11L69.5 28.1 62.2 43 49.8 39.6 39.2 39.6z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='-24.559' y1='59.081' x2='61.22' y2='-4.241'%3E%3Cstop offset='.011' stop-color='%23FCF84A'/%3E%3Cstop offset='.112' stop-color='%23A7EB62'/%3E%3Cstop offset='.206' stop-color='%235FE077'/%3E%3Cstop offset='.273' stop-color='%2332DA84'/%3E%3Cstop offset='.306' stop-color='%2321D789'/%3E%3Cstop offset='.577' stop-color='%2321D789'/%3E%3Cstop offset='.597' stop-color='%2321D789'/%3E%3Cstop offset='.686' stop-color='%2320D68C'/%3E%3Cstop offset='.763' stop-color='%231ED497'/%3E%3Cstop offset='.835' stop-color='%2319D1A9'/%3E%3Cstop offset='.904' stop-color='%2313CCC2'/%3E%3Cstop offset='.971' stop-color='%230BC6E1'/%3E%3Cstop offset='1' stop-color='%2307C3F2'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M28.5 22.1L24.5 43 24.1 50.2 14.2 54.5 0 56 4.3 10.7 29.9 0 45.7 10.4z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='9.33' y1='77.654' x2='23.637' y2='32.76'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='.164' stop-color='%2324D788'/%3E%3Cstop offset='.305' stop-color='%232FD886'/%3E%3Cstop offset='.437' stop-color='%2341DA82'/%3E%3Cstop offset='.564' stop-color='%235ADC7D'/%3E%3Cstop offset='.688' stop-color='%237AE077'/%3E%3Cstop offset='.809' stop-color='%23A1E36E'/%3E%3Cstop offset='.925' stop-color='%23CFE865'/%3E%3Cstop offset='1' stop-color='%23F1EB5E'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M28.5 22.1L30.4 62.5 24 70 0 56 19.7 26.6z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='28.275' y1='38.623' x2='59.409' y2='-3.236'%3E%3Cstop offset='0' stop-color='%2321D789'/%3E%3Cstop offset='.061' stop-color='%2324D788'/%3E%3Cstop offset='.113' stop-color='%232FD886'/%3E%3Cstop offset='.162' stop-color='%2341DA82'/%3E%3Cstop offset='.209' stop-color='%235ADD7D'/%3E%3Cstop offset='.255' stop-color='%2379E077'/%3E%3Cstop offset='.258' stop-color='%237CE076'/%3E%3Cstop offset='.499' stop-color='%238CE173'/%3E%3Cstop offset='.925' stop-color='%23B2E56B'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M54.9 19.1L30.6 19.1 52.1 0z'/%3E%3ClinearGradient id='e' gradientUnits='userSpaceOnUse' x1='75.889' y1='43.95' x2='13.158' y2='43.369'%3E%3Cstop offset='.387' stop-color='%23FCF84A'/%3E%3Cstop offset='.536' stop-color='%23ECF451'/%3E%3Cstop offset='.826' stop-color='%23C2E964'/%3E%3Cstop offset='.925' stop-color='%23B2E56B'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23e)' d='M70 62.6L48.6 69.9 20.2 61.9 28.5 22.1 31.8 19.1 49.1 17.5 47.5 34.9 61.3 29.6z'/%3E%3Cg%3E%3Cpath d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M17.3,19.1h7.3c4.3,0,6.9,2.5,6.9,6.2v0.1c0,4.1-3.2,6.3-7.2,6.3h-3V37h-3.9V19.1z M24.4,28.1 c2,0,3.1-1.2,3.1-2.7v-0.1c0-1.8-1.2-2.7-3.2-2.7h-3v5.5H24.4z' fill='%23FFF'/%3E%3Cpath d='M33.6,19.1h13.5v3.5h-9.6v3.6H46v3.5h-8.4v3.8h9.7V37H33.6V19.1z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 476 | } 477 | 478 | .jetbrains-logo._logo-pycharm-edu._size-1 { 479 | width: 40px; 480 | height: 40px 481 | } 482 | 483 | .jetbrains-logo._logo-pycharm-edu._size-2 { 484 | width: 60px; 485 | height: 60px 486 | } 487 | 488 | .jetbrains-logo._logo-pycharm-edu._size-3 { 489 | width: 75px; 490 | height: 75px 491 | } 492 | 493 | .jetbrains-logo._logo-pycharm-edu._size-4 { 494 | width: 100px; 495 | height: 100px 496 | } 497 | 498 | .jetbrains-logo._logo-pycharm-edu._size-5 { 499 | width: 150px; 500 | height: 150px 501 | } 502 | 503 | .jetbrains-logo._logo-rider { 504 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3Cdefs%3E%3ClinearGradient id='a' x1='70.226' y1='27.799' x2='-5.13' y2='63.122' gradientTransform='matrix(1 0 0 -1 0 71.28)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23c90f5e'/%3E%3Cstop offset='.221' stop-color='%23c90f5e'/%3E%3Cstop offset='.236' stop-color='%23c90f5e'/%3E%3Cstop offset='.356' stop-color='%23ca135c'/%3E%3Cstop offset='.466' stop-color='%23ce1e57'/%3E%3Cstop offset='.574' stop-color='%23d4314e'/%3E%3Cstop offset='.678' stop-color='%23dc4b41'/%3E%3Cstop offset='.782' stop-color='%23e66d31'/%3E%3Cstop offset='.883' stop-color='%23f3961d'/%3E%3Cstop offset='.942' stop-color='%23fcb20f'/%3E%3C/linearGradient%3E%3ClinearGradient id='b' x1='24.659' y1='61.996' x2='46.048' y2='2.934' gradientTransform='matrix(1 0 0 -1 0 71.28)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.042' stop-color='%23077cfb'/%3E%3Cstop offset='.445' stop-color='%23c90f5e'/%3E%3Cstop offset='.958' stop-color='%23077cfb'/%3E%3C/linearGradient%3E%3ClinearGradient id='c' x1='17.396' y1='63.346' x2='33.194' y2='7.201' gradientTransform='matrix(1 0 0 -1 0 71.28)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.277' stop-color='%23c90f5e'/%3E%3Cstop offset='.974' stop-color='%23fcb20f'/%3E%3C/linearGradient%3E%3C/defs%3E%3Ctitle%3Erider%3C/title%3E%3Cpath fill='url(%23a)' d='M70 27.237L63.391 23.75 20.926 0 3.827 17.921 21.619 41.068 60.537 44.397 70 27.237z'/%3E%3Cpath fill='url(%23b)' d='M50.423 16.132L44.271 1.107 27.643 17.471 11.768 50.194 49.411 70 70 57.98 50.423 16.132z'/%3E%3Cpath fill='url(%23c)' d='M20.926 0L0 14.095 7.779 62.172 27.848 69.889 53.78 48.823 20.926 0z'/%3E%3Cg%3E%3Cpath d='M13.302 13.193H56.916V56.806999999999995H13.302z'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M17.22741,18.86293h8.39564a7.38416,7.38416,0,0,1,5.34268,1.85358,5.86989,5.86989,0,0,1,1.52648,4.1433h0A5.74339,5.74339,0,0,1,28.567,30.5296l4.47041,6.54206H28.34891L24.42368,31.1838h-3.162v5.88785H17.22741V18.86293h0ZM25.296,27.69471c1.96262,0,3.053-1.09034,3.053-2.61682h0c0-1.74455-1.19938-2.61682-3.162-2.61682H21.15265v5.23365H25.296Z'/%3E%3Cpath d='M36.09034,18.86293H43.2866c5.77882,0,9.70405,3.92523,9.70405,9.15888h0c0,5.12461-3.92523,9.15888-9.70405,9.15888H36.09034V18.86293Zm4.03427,3.59813V33.47352h3.162a5.23727,5.23727,0,0,0,5.56075-5.45171h0a5.26493,5.26493,0,0,0-5.56075-5.56075h-3.162Z'/%3E%3C/g%3E%3Cpath fill='%23fff' d='M17.227 48.629H33.582V51.355H17.227z'/%3E%3C/g%3E%3C/svg%3E") 505 | } 506 | 507 | .jetbrains-logo._logo-rider._size-1 { 508 | width: 40px; 509 | height: 40px 510 | } 511 | 512 | .jetbrains-logo._logo-rider._size-2 { 513 | width: 60px; 514 | height: 60px 515 | } 516 | 517 | .jetbrains-logo._logo-rider._size-3 { 518 | width: 75px; 519 | height: 75px 520 | } 521 | 522 | .jetbrains-logo._logo-rider._size-4 { 523 | width: 100px; 524 | height: 100px 525 | } 526 | 527 | .jetbrains-logo._logo-rider._size-5 { 528 | width: 150px; 529 | height: 150px 530 | } 531 | 532 | .jetbrains-logo._logo-resharper { 533 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='22.945' y1='75.787' x2='74.787' y2='20.642'%3E%3Cstop offset='.016' stop-color='%23B35BA3'/%3E%3Cstop offset='.404' stop-color='%23C41E57'/%3E%3Cstop offset='.468' stop-color='%23C41E57'/%3E%3Cstop offset='.65' stop-color='%23EB8523'/%3E%3Cstop offset='.952' stop-color='%23FEBD11'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M49.8 15.2L36 36.7 58.4 70 70 23.1z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='17.719' y1='73.292' x2='69.556' y2='18.152'%3E%3Cstop offset='.016' stop-color='%23B35BA3'/%3E%3Cstop offset='.404' stop-color='%23C41E57'/%3E%3Cstop offset='.468' stop-color='%23C41E57'/%3E%3Cstop offset='.704' stop-color='%23EB8523'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M51.1 15.7L49 0 18.8 33.6 27.6 42.3 20.8 70 58.4 70z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='1.828' y1='53.428' x2='48.825' y2='9.226'%3E%3Cstop offset='.016' stop-color='%23B35BA3'/%3E%3Cstop offset='.661' stop-color='%23C41E57'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M49 0L11.6 0 0 47.1 55.6 47.1z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='49.894' y1='-11.557' x2='48.859' y2='24.035'%3E%3Cstop offset='.5' stop-color='%23C41E57'/%3E%3Cstop offset='.667' stop-color='%23D13F48'/%3E%3Cstop offset='.795' stop-color='%23D94F39'/%3E%3Cstop offset='.866' stop-color='%23DD5433'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23d)' d='M55.3 47.1L51.1 15.7 49 0 41.7 23z'/%3E%3Cg%3E%3Cpath transform='matrix(-1 .00258 -.00258 -1 70.029 70.081)' fill='%23000' d='M13.4 13.5H56.6V56.7H13.4z'/%3E%3Cpath transform='rotate(-.148 25.676 49.97)' fill='%23FFF' d='M17.6 48.6H33.8V51.300000000000004H17.6z'/%3E%3Cpath d='M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5 c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7 c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z' fill='%23FFF'/%3E%3Cpath d='M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7 l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 534 | } 535 | 536 | .jetbrains-logo._logo-resharper._size-1 { 537 | width: 40px; 538 | height: 40px 539 | } 540 | 541 | .jetbrains-logo._logo-resharper._size-2 { 542 | width: 60px; 543 | height: 60px 544 | } 545 | 546 | .jetbrains-logo._logo-resharper._size-3 { 547 | width: 75px; 548 | height: 75px 549 | } 550 | 551 | .jetbrains-logo._logo-resharper._size-4 { 552 | width: 100px; 553 | height: 100px 554 | } 555 | 556 | .jetbrains-logo._logo-resharper._size-5 { 557 | width: 150px; 558 | height: 150px 559 | } 560 | 561 | .jetbrains-logo._logo-resharper-cpp { 562 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='8.063' y1='16.141' x2='29.26' y2='69.757'%3E%3Cstop offset='.22' stop-color='%23C40B55'/%3E%3Cstop offset='.683' stop-color='%23E343E6'/%3E%3Cstop offset='.925' stop-color='%23F59252'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M20.2 15.2L34 36.7 11.6 70 0 23.1z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='875.719' y1='73.292' x2='927.556' y2='18.152' gradientTransform='matrix(-1 0 0 1 928 0)'%3E%3Cstop offset='.113' stop-color='%23FFBD00'/%3E%3Cstop offset='.586' stop-color='%23E343E6'/%3E%3Cstop offset='.817' stop-color='%23EC841B'/%3E%3Cstop offset='.935' stop-color='%23FFBD00'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M18.9 15.7L21 0 51.2 33.6 42.4 42.3 49.2 70 11.6 70z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='25.5' y1='-1.93' x2='69.96' y2='51.168'%3E%3Cstop offset='.129' stop-color='%23FFBD00'/%3E%3Cstop offset='.64' stop-color='%23E343E6'/%3E%3Cstop offset='.909' stop-color='%23C40B55'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M35.3 47.1L70 47.1 58.4 0 21 0z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath d='M17.4,19h8.2c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1V25c0,1.5-0.4,2.6-1.1,3.5 c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4h-4.6l-3.7-5.5h-3.3l0,5.5h-3.9V19z M25.4,27.7c1,0,1.7-0.2,2.2-0.7c0.5-0.5,0.8-1.1,0.8-1.8 v-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6h-3.9v5.1H25.4z' fill='%23FFF'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cg%3E%3Cpath d='M43.7,24.4h-4v-3.6h4v-4h3.7v4h4v3.6h-4v4h-3.7V24.4z' fill='%23FFF'/%3E%3C/g%3E%3Cg%3E%3Cpath d='M37.1,34.6h-4V31h4v-4h3.7v4h4v3.6h-4v4h-3.7V34.6z' fill='%23FFF'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 563 | } 564 | 565 | .jetbrains-logo._logo-resharper-cpp._size-1 { 566 | width: 40px; 567 | height: 40px 568 | } 569 | 570 | .jetbrains-logo._logo-resharper-cpp._size-2 { 571 | width: 60px; 572 | height: 60px 573 | } 574 | 575 | .jetbrains-logo._logo-resharper-cpp._size-3 { 576 | width: 75px; 577 | height: 75px 578 | } 579 | 580 | .jetbrains-logo._logo-resharper-cpp._size-4 { 581 | width: 100px; 582 | height: 100px 583 | } 584 | 585 | .jetbrains-logo._logo-resharper-cpp._size-5 { 586 | width: 150px; 587 | height: 150px 588 | } 589 | 590 | .jetbrains-logo._logo-rubymine { 591 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='49.609' y1='52.554' x2='30.346' y2='7.163'%3E%3Cstop offset='.172' stop-color='%23FF1F51'/%3E%3Cstop offset='.28' stop-color='%23FF3648'/%3E%3Cstop offset='.468' stop-color='%23FF593B'/%3E%3Cstop offset='.646' stop-color='%23FF7231'/%3E%3Cstop offset='.809' stop-color='%23FF812B'/%3E%3Cstop offset='.941' stop-color='%23FF8629'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M58.2 0L38.2 7.2 22.4 0 6.9 38.9 24.7 31.8 24.4 51.5 62.5 52.2 70 13.7z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='33.259' y1='12.887' x2='25.105' y2='33.436'%3E%3Cstop offset='.022' stop-color='%239039D0'/%3E%3Cstop offset='.629' stop-color='%23FF1F51'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M50.8 22.7L25.6 6.2 5.3 18.7 49.8 35.9z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='.29' y1='11.224' x2='45.284' y2='68.42'%3E%3Cstop offset='.107' stop-color='%239039D0'/%3E%3Cstop offset='.387' stop-color='%23FF1F51'/%3E%3Cstop offset='.629' stop-color='%23FF1F51'/%3E%3Cstop offset='.66' stop-color='%23FF3648'/%3E%3Cstop offset='.714' stop-color='%23FF593B'/%3E%3Cstop offset='.765' stop-color='%23FF7231'/%3E%3Cstop offset='.812' stop-color='%23FF812B'/%3E%3Cstop offset='.85' stop-color='%23FF8629'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M29.1 68.2L55.3 64.7 47 48.7 52.5 42 53.1 37.9 25.6 6.1 0 12.4 0 49.1 14.8 70 29.1 68.2 29.1 68.2 29.1 68.2 29.1 68.2z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath fill='%23FFF' d='M34.6 19L38.9 19 43.6 26.6 48.3 19 52.6 19 52.6 36.9 48.6 36.9 48.6 25.2 43.6 32.9 43.5 32.9 38.5 25.3 38.5 36.9 34.6 36.9z'/%3E%3Cpath d='M17.4,19h8.2c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1v0.1c0,1.5-0.4,2.6-1.1,3.5 c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4h-4.6l-3.7-5.5h-3.3l0,5.5h-3.9V19z M25.4,27.7c1,0,1.7-0.2,2.2-0.7c0.5-0.5,0.8-1.1,0.8-1.8v-0.1 c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6h-3.9v5.1H25.4z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 592 | } 593 | 594 | .jetbrains-logo._logo-rubymine._size-1 { 595 | width: 40px; 596 | height: 40px 597 | } 598 | 599 | .jetbrains-logo._logo-rubymine._size-2 { 600 | width: 60px; 601 | height: 60px 602 | } 603 | 604 | .jetbrains-logo._logo-rubymine._size-3 { 605 | width: 75px; 606 | height: 75px 607 | } 608 | 609 | .jetbrains-logo._logo-rubymine._size-4 { 610 | width: 100px; 611 | height: 100px 612 | } 613 | 614 | .jetbrains-logo._logo-rubymine._size-5 { 615 | width: 150px; 616 | height: 150px 617 | } 618 | 619 | .jetbrains-logo._logo-teamcity { 620 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='1.774' y1='31.273' x2='40.166' y2='31.273'%3E%3Cstop offset='0' stop-color='%23905CFB'/%3E%3Cstop offset='.068' stop-color='%23776CF9'/%3E%3Cstop offset='.173' stop-color='%235681F7'/%3E%3Cstop offset='.286' stop-color='%233B92F5'/%3E%3Cstop offset='.41' stop-color='%23269FF4'/%3E%3Cstop offset='.547' stop-color='%2317A9F3'/%3E%3Cstop offset='.711' stop-color='%230FAEF2'/%3E%3Cstop offset='.968' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M39.7,47.9l-6.1-34c-0.4-2.4-1.2-4.8-2.7-7.1c-2-3.2-5.2-5.4-8.8-6.3 C7.9-2.9-2.6,11.3,3.6,23.9c0,0,0,0,0,0l14.8,31.7c0.4,1,1,2,1.7,2.9c1.2,1.6,2.8,2.8,4.7,3.4C34.4,64.9,42.1,56.4,39.7,47.9z' fill='url(%23a)'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='5.311' y1='9.669' x2='69.228' y2='43.866'%3E%3Cstop offset='0' stop-color='%23905CFB'/%3E%3Cstop offset='.068' stop-color='%23776CF9'/%3E%3Cstop offset='.173' stop-color='%235681F7'/%3E%3Cstop offset='.286' stop-color='%233B92F5'/%3E%3Cstop offset='.41' stop-color='%23269FF4'/%3E%3Cstop offset='.547' stop-color='%2317A9F3'/%3E%3Cstop offset='.711' stop-color='%230FAEF2'/%3E%3Cstop offset='.968' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M67.4,26.5c-1.4-2.2-3.4-3.9-5.7-4.9L25.5,1.7l0,0c-1-0.5-2.1-1-3.3-1.3 C6.7-3.2-4.4,13.8,5.5,27c1.5,2,3.6,3.6,6,4.5L48,47.9c0.8,0.5,1.6,0.8,2.5,1.1C64.5,53.4,75.1,38.6,67.4,26.5z' fill='url(%23b)'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='-19.284' y1='70.82' x2='55.983' y2='33.186'%3E%3Cstop offset='0' stop-color='%233BEA62'/%3E%3Cstop offset='.117' stop-color='%2331DE80'/%3E%3Cstop offset='.302' stop-color='%2324CEA8'/%3E%3Cstop offset='.484' stop-color='%231AC1C9'/%3E%3Cstop offset='.659' stop-color='%2312B7DF'/%3E%3Cstop offset='.824' stop-color='%230EB2ED'/%3E%3Cstop offset='.968' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M67.4,26.5c-1.8-2.8-4.6-4.8-7.9-5.6c-3.5-0.8-6.8-0.5-9.6,0.7L11.4,36.1 c0,0-0.2,0.1-0.6,0.4C0.9,40.4-4,53.3,4,64c1.8,2.4,4.3,4.2,7.1,5c5.3,1.6,10.1,1,14-1.1c0,0,0.1,0,0.1,0l37.6-20.1 c0,0,0,0,0.1-0.1C69.5,43.9,72.6,34.6,67.4,26.5z' fill='url(%23c)'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='38.944' y1='5.85' x2='5.423' y2='77.509'%3E%3Cstop offset='0' stop-color='%233BEA62'/%3E%3Cstop offset='.094' stop-color='%232FDB87'/%3E%3Cstop offset='.196' stop-color='%2324CEA8'/%3E%3Cstop offset='.306' stop-color='%231BC3C3'/%3E%3Cstop offset='.426' stop-color='%2314BAD8'/%3E%3Cstop offset='.56' stop-color='%2310B5E7'/%3E%3Cstop offset='.719' stop-color='%230DB1EF'/%3E%3Cstop offset='.968' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M50.3,12.8c1.2-2.7,1.1-6-0.9-9c-1.1-1.8-2.9-3-4.9-3.5c-4.5-1.1-8.3,1-10.1,4.2L3.5,42 c0,0,0,0,0,0.1C-0.9,47.9-1.6,56.5,4,64c1.8,2.4,4.3,4.2,7.1,5c10.5,3.3,19.3-2.5,22.1-10.8L50.3,12.8z' fill='url(%23d)'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath fill='%23FFF' d='M22.9 22.7L17.5 22.7 17.5 19.1 32.3 19.1 32.3 22.7 26.8 22.7 26.8 37 22.9 37z'/%3E%3Cpath d='M32.5,28.1L32.5,28.1c0-5.1,3.8-9.3,9.3-9.3c3.4,0,5.4,1.1,7.1,2.8l-2.5,2.9c-1.4-1.3-2.8-2-4.6-2 c-3,0-5.2,2.5-5.2,5.6V28c0,3.1,2.1,5.6,5.2,5.6c2,0,3.3-0.8,4.7-2.1l2.5,2.5c-1.8,2-3.9,3.2-7.3,3.2 C36.4,37.3,32.5,33.2,32.5,28.1' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E") 621 | } 622 | 623 | .jetbrains-logo._logo-teamcity._size-1 { 624 | width: 40px; 625 | height: 40px 626 | } 627 | 628 | .jetbrains-logo._logo-teamcity._size-2 { 629 | width: 60px; 630 | height: 60px 631 | } 632 | 633 | .jetbrains-logo._logo-teamcity._size-3 { 634 | width: 75px; 635 | height: 75px 636 | } 637 | 638 | .jetbrains-logo._logo-teamcity._size-4 { 639 | width: 100px; 640 | height: 100px 641 | } 642 | 643 | .jetbrains-logo._logo-teamcity._size-5 { 644 | width: 150px; 645 | height: 150px 646 | } 647 | 648 | .jetbrains-logo._logo-toolbox { 649 | background-image: url("data:image/svg+xml,%3Csvg data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='32' height='32'%3E%3Cdefs%3E%3ClinearGradient id='a' x1='2.18' y1='23.255' x2='30.041' y2='8.782' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.043' stop-color='%23ff8618'/%3E%3Cstop offset='.382' stop-color='%23ff246e'/%3E%3Cstop offset='.989' stop-color='%23af1df5'/%3E%3C/linearGradient%3E%3C/defs%3E%3Ctitle%3EToolBox_trayIcon_colour_32-01%3C/title%3E%3Cpath d='M26,22.4713l-6.83,3.8311V23.2578L26,19.4268v3.0445Z' fill='%23fff'/%3E%3Cpath fill='%23000001' d='M16 32.076L30 24.065 30 8.057 16 16.067 16 32.076z'/%3E%3Cpath fill='%23fff' d='M18.925 24.641L18.925 27.041 25.026 23.55 25.026 21.15 18.925 24.641z'/%3E%3Cpath fill='url(%23a)' d='M16 0.076L2 8.057 2 8.057 2 8.057 2 24.065 16 32.076 16 16.067 30 8.057 16 0.076z'/%3E%3C/svg%3E") 650 | } 651 | 652 | .jetbrains-logo._logo-toolbox._size-1 { 653 | width: 40px; 654 | height: 40px 655 | } 656 | 657 | .jetbrains-logo._logo-toolbox._size-2 { 658 | width: 60px; 659 | height: 60px 660 | } 661 | 662 | .jetbrains-logo._logo-toolbox._size-3 { 663 | width: 75px; 664 | height: 75px 665 | } 666 | 667 | .jetbrains-logo._logo-toolbox._size-4 { 668 | width: 100px; 669 | height: 100px 670 | } 671 | 672 | .jetbrains-logo._logo-toolbox._size-5 { 673 | width: 150px; 674 | height: 150px 675 | } 676 | 677 | .jetbrains-logo._logo-upsource { 678 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='64.913' y1='54.385' x2='17.513' y2='47.275' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%23FF8200'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M60.5 24L9.6 26.9 9.3 7.4 55.2 0.2z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='15.675' y1='30.593' x2='20.093' y2='55.275' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%230CB0F2'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath d='M20.3,43.2l16.4-20.8L18.9,10.2l0,0c-3.1-2.8-7.8-4-12.6-2c-2.4,1-4.3,2.9-5.3,5.3 c-2.1,5-0.8,9.9,2.4,12.9l0,0L20.3,43.2z' fill='url(%23b)'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='58.335' y1='11.729' x2='26.978' y2='27.043' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%230CB0F2'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M20.3 43.2L45.5 68.1 61.2 38.8 36.7 22.4z'/%3E%3ClinearGradient id='d' gradientUnits='userSpaceOnUse' x1='60.678' y1='9.337' x2='7.352' y2='28.508' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%230CB0F2'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath d='M53.9,36.6L53.9,36.6l-41.9-2l0,0c-1.6-0.3-3.4-0.2-5.3,0.6c-1.8,0.8-3.2,2.1-3.9,3.9 c-2.1,4.9,0.4,9.6,4.5,11.2l0,0L44.8,68c0.5,0.3,3,1,3,1c2,0.6,4.2,0.9,6.2,0.9c2.5,0,5.3-0.7,8.1-2.1c2.6-1.3,4.2-3.4,5.6-6 c1.7-3,2.2-5.8,2.2-8.6C69.8,44.5,62.6,37.2,53.9,36.6z' fill='url(%23d)'/%3E%3ClinearGradient id='e' gradientUnits='userSpaceOnUse' x1='64.194' y1='59.46' x2='18.524' y2='22.651' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%23FF8200'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath d='M52.1,1.1c-0.7,0.3-1.4,0.7-2,1.1l0,0L26.9,19.7l11.5,16.8l25.2-14.1 c1.9-0.9,3.4-2.5,4.3-4.3C73.5,7.3,63.1-3.5,52.1,1.1z' fill='url(%23e)'/%3E%3Cpath fill='%23905CFB' d='M14.5 49.8L38.4 36.5 26.9 19.7 4.9 36.2z'/%3E%3ClinearGradient id='f' gradientUnits='userSpaceOnUse' x1='30.448' y1='16.152' x2='2.265' y2='26.168' gradientTransform='matrix(1 0 0 -1 0 65.395)'%3E%3Cstop offset='0' stop-color='%230CB0F2'/%3E%3Cstop offset='.973' stop-color='%23905CFB'/%3E%3C/linearGradient%3E%3Cpath d='M20.4,56.4V35L12,34.6H12c-1.6-0.3-3.4-0.2-5.3,0.6c-1.8,0.8-3.2,2.1-3.9,3.9 c-2.1,4.9,0.4,9.6,4.5,11.2h0.1L20.4,56.4z' fill='url(%23f)'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cg fill='%23FFF'%3E%3Cpath d='M17.5,29.4V19h4v10.3c0,3,1.5,4.5,3.9,4.5s3.9-1.5,3.9-4.4V19h4v10.2c0,5.5-3.1,8.2-8,8.2 C20.5,37.5,17.5,34.7,17.5,29.4z'/%3E%3Cpath d='M35.4,19h7.4c4.3,0,6.9,2.6,6.9,6.3v0.1c0,4.2-3.3,6.4-7.3,6.4h-3v5.4h-4V19z M42.6,28.2 c2,0,3.2-1.2,3.2-2.7v-0.1c0-1.8-1.2-2.7-3.2-2.7h-3.1v5.5H42.6z'/%3E%3C/g%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3C/g%3E%3C/svg%3E") 679 | } 680 | 681 | .jetbrains-logo._logo-upsource._size-1 { 682 | width: 40px; 683 | height: 40px 684 | } 685 | 686 | .jetbrains-logo._logo-upsource._size-2 { 687 | width: 60px; 688 | height: 60px 689 | } 690 | 691 | .jetbrains-logo._logo-upsource._size-3 { 692 | width: 75px; 693 | height: 75px 694 | } 695 | 696 | .jetbrains-logo._logo-upsource._size-4 { 697 | width: 100px; 698 | height: 100px 699 | } 700 | 701 | .jetbrains-logo._logo-upsource._size-5 { 702 | width: 150px; 703 | height: 150px 704 | } 705 | 706 | .jetbrains-logo._logo-webstorm { 707 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='25.068' y1='1.46' x2='43.183' y2='66.675'%3E%3Cstop offset='.285' stop-color='%2300CDD7'/%3E%3Cstop offset='.941' stop-color='%232086D7'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23a)' d='M9.4 63.3L0 7.3 17.5 0.1 28.6 6.7 38.8 1.2 60.1 9.4 48.1 70z'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='30.72' y1='9.734' x2='61.365' y2='54.671'%3E%3Cstop offset='.14' stop-color='%23FFF045'/%3E%3Cstop offset='.366' stop-color='%2300CDD7'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23b)' d='M70 23.7L61 1.4 44.6 0 19.3 24.3 26.1 55.6 38.8 64.6 70 46 62.3 31.7z'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='61.082' y1='15.29' x2='65.106' y2='29.544'%3E%3Cstop offset='.285' stop-color='%2300CDD7'/%3E%3Cstop offset='.941' stop-color='%232086D7'/%3E%3C/linearGradient%3E%3Cpath fill='url(%23c)' d='M56 20.4L62.3 31.7 70 23.7 64.4 9.8z'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.5 48.5H33.7V51.2H17.5z'/%3E%3Cpath d='M38.7,34.3l2.3-2.8c1.6,1.3,3.3,2.2,5.3,2.2c1.6,0,2.5-0.6,2.5-1.7v-0.1c0-1-0.6-1.5-3.6-2.3 c-3.6-0.9-5.8-1.9-5.8-5.5v-0.1c0-3.3,2.6-5.4,6.2-5.4c2.6,0,4.8,0.8,6.6,2.3l-2,3c-1.6-1.1-3.1-1.8-4.6-1.8 c-1.5,0-2.3,0.7-2.3,1.6v0.1c0,1.2,0.8,1.6,3.8,2.4c3.6,1,5.6,2.3,5.6,5.4v0.1c0,3.6-2.7,5.6-6.5,5.6 C43.5,37.2,40.8,36.2,38.7,34.3' fill='%23FFF'/%3E%3Cpath fill='%23FFF' d='M35.2 19L32.5 29.4 29.5 19 26.5 19 23.4 29.4 20.7 19 16.6 19 21.7 36.9 25 36.9 28 26.5 30.9 36.9 34.3 36.9 39.4 19z'/%3E%3C/g%3E%3C/svg%3E") 708 | } 709 | 710 | .jetbrains-logo._logo-webstorm._size-1 { 711 | width: 40px; 712 | height: 40px 713 | } 714 | 715 | .jetbrains-logo._logo-webstorm._size-2 { 716 | width: 60px; 717 | height: 60px 718 | } 719 | 720 | .jetbrains-logo._logo-webstorm._size-3 { 721 | width: 75px; 722 | height: 75px 723 | } 724 | 725 | .jetbrains-logo._logo-webstorm._size-4 { 726 | width: 100px; 727 | height: 100px 728 | } 729 | 730 | .jetbrains-logo._logo-webstorm._size-5 { 731 | width: 150px; 732 | height: 150px 733 | } 734 | 735 | .jetbrains-logo._logo-youtrack { 736 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0' y='0' width='70' height='70' viewBox='0 0 70 70' xml:space='preserve'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='7.083' y1='16.294' x2='64.106' y2='42.288' gradientTransform='matrix(1 0 0 -1 0 71.047)'%3E%3Cstop offset='0' stop-color='%23905CFB'/%3E%3Cstop offset='.165' stop-color='%236677F8'/%3E%3Cstop offset='.378' stop-color='%233596F5'/%3E%3Cstop offset='.54' stop-color='%2317A9F3'/%3E%3Cstop offset='.632' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M66.9,47.5c-0.2-0.2-13.1-12.6-13.1-12.6s9.8-10.4,12.4-13c0.8-0.8,1.5-1.6,2-2.6 c3.6-6.1,1.5-13.9-4.6-17.5c-4.5-2.6-10.1-2.2-14.1,0.8c-0.7,0.5-1.3,1-1.9,1.6C47.3,4.6,33.7,17,21.9,27.8l22.1,14L20.8,67.9 c-1.4,1-2.8,1.6-4.3,1.9c0.3,0,0.5,0,0.8-0.1c4.6-0.7,43.9-7.3,45.8-7.7c2.3-0.4,4.4-1.8,5.7-3.9C71,54.5,70,50,66.9,47.5z' fill='url(%23a)'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='30.31' y1='42.916' x2='1.068' y2='68.744' gradientTransform='matrix(1 0 0 -1 0 71.047)'%3E%3Cstop offset='0' stop-color='%23905CFB'/%3E%3Cstop offset='.072' stop-color='%23A554E6'/%3E%3Cstop offset='.252' stop-color='%23D641B5'/%3E%3Cstop offset='.39' stop-color='%23F43597'/%3E%3Cstop offset='.468' stop-color='%23FF318C'/%3E%3C/linearGradient%3E%3Cpath d='M45.9,30.5c-0.4-2.7-1.8-4.9-3.8-6.5C40,22.4,23.8,5.6,22,3.7C19.2,1,15.2-0.5,11.1,0.2 C4.1,1.2-0.8,7.8,0.3,14.8c0.5,3.5,2.5,6.5,5.1,8.4c2.6,2,23,16,24.3,17c2.1,1.6,4.9,2.5,7.7,2C42.9,41.2,46.8,36,45.9,30.5z' fill='url(%23b)'/%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='4.983' y1='12.362' x2='74.023' y2='55.864' gradientTransform='matrix(1 0 0 -1 0 71.047)'%3E%3Cstop offset='0' stop-color='%23905CFB'/%3E%3Cstop offset='.165' stop-color='%236677F8'/%3E%3Cstop offset='.378' stop-color='%233596F5'/%3E%3Cstop offset='.54' stop-color='%2317A9F3'/%3E%3Cstop offset='.632' stop-color='%230CB0F2'/%3E%3C/linearGradient%3E%3Cpath d='M23,67.8c0.1,0,23.3-26.1,23.3-26.1L22.9,26.9c-8.3,7.6-16,14.5-17.8,16.2 c-1.1,1-2.2,2.3-3,3.7c-4.3,7.4-1.8,16.8,5.6,21.1C10.7,69.6,17.5,71.7,23,67.8z' fill='url(%23c)'/%3E%3Cg%3E%3Cpath fill='%23000' d='M13.4 13.4H56.6V56.6H13.4z'/%3E%3Cpath fill='%23FFF' d='M17.4 48.5H33.599999999999994V51.2H17.4z'/%3E%3Cpath fill='%23FFF' d='M23.8 29.9L17 19.1 21.6 19.1 25.8 26.2 30.2 19.1 34.7 19.1 27.8 29.8 27.8 37 23.8 37z'/%3E%3Cpath fill='%23FFF' d='M41.6 22.7L36.1 22.7 36.1 19.1 51 19.1 51 22.7 45.5 22.7 45.5 37 41.6 37z'/%3E%3C/g%3E%3C/svg%3E") 737 | } 738 | 739 | .jetbrains-logo._logo-youtrack._size-1 { 740 | width: 40px; 741 | height: 40px 742 | } 743 | 744 | .jetbrains-logo._logo-youtrack._size-2 { 745 | width: 60px; 746 | height: 60px 747 | } 748 | 749 | .jetbrains-logo._logo-youtrack._size-3 { 750 | width: 75px; 751 | height: 75px 752 | } 753 | 754 | .jetbrains-logo._logo-youtrack._size-4 { 755 | width: 100px; 756 | height: 100px 757 | } 758 | 759 | .jetbrains-logo._logo-youtrack._size-5 { 760 | width: 150px; 761 | height: 150px 762 | } --------------------------------------------------------------------------------