diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6f2a4a6 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,17 @@ +on: [push] + +name: Build + +jobs: + build-ubuntu: + name: Commit release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup JDK + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Build + run: ./gradlew build packageUberJarForCurrentOS diff --git a/.github/workflows/commit-release.yml b/.github/workflows/commit-release.yml index cc9cfad..98ce813 100644 --- a/.github/workflows/commit-release.yml +++ b/.github/workflows/commit-release.yml @@ -1,4 +1,7 @@ -on: [push] +on: + push: + branches: + - master name: Commit release @@ -16,9 +19,13 @@ jobs: - name: Set version from gradle.properties run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV - name: Build - run: ./gradlew packageUberJarForCurrentOS - env: - additional_version: "" + run: ./gradlew build packageUberJarForCurrentOS + - name: Publish Web + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./web/build/distributions + publish_branch: site - name: Create Release id: create_release uses: actions/create-release@v1 diff --git a/extensions.gradle b/extensions.gradle index 0c108ed..2e89947 100644 --- a/extensions.gradle +++ b/extensions.gradle @@ -15,6 +15,7 @@ allprojects { mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle" mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle" + mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle" mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle" defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle" diff --git a/mppAndroidProject.gradle b/mppAndroidProject.gradle index 20b6516..97ddb3c 100644 --- a/mppAndroidProject.gradle +++ b/mppAndroidProject.gradle @@ -1,4 +1,4 @@ -project.version = "$version" + System.getenv("additional_version") +project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "") project.group = "$group" // apply from: "$publishGradlePath" diff --git a/mppJavaProject.gradle b/mppJavaProject.gradle index 2f64097..e2d5a08 100644 --- a/mppJavaProject.gradle +++ b/mppJavaProject.gradle @@ -1,4 +1,4 @@ -project.version = "$version" + System.getenv("additional_version") +project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "") project.group = "$group" // apply from: "$publishGradlePath" diff --git a/mppJsProject.gradle b/mppJsProject.gradle new file mode 100644 index 0000000..6ee908a --- /dev/null +++ b/mppJsProject.gradle @@ -0,0 +1,34 @@ +project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "") +project.group = "$group" + +// apply from: "$publishGradlePath" + +kotlin { + js (IR) { + browser { + binaries.executable() + } + nodejs() + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version" + } + } + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + jsTest { + dependencies { + implementation kotlin('test-js') + implementation kotlin('test-junit') + } + } + } +} diff --git a/settings.gradle b/settings.gradle index b1eed1e..29bbdc6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,7 +9,8 @@ rootProject.name = 'kmppscriptbuilder' String[] includes = [ ":core", - ":desktop" + ":desktop", + ":web" ] diff --git a/web/build.gradle b/web/build.gradle new file mode 100644 index 0000000..7a3b6b1 --- /dev/null +++ b/web/build.gradle @@ -0,0 +1,17 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +apply from: "$mppJsProjectPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + implementation project(":kmppscriptbuilder.core") + implementation "dev.inmo:micro_utils.common:$micro_utils_version" + } + } + } +} diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt new file mode 100644 index 0000000..36e52f8 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/main.kt @@ -0,0 +1,83 @@ +package dev.inmo.kmppscriptbuilder.web + +import dev.inmo.kmppscriptbuilder.core.models.Config +import dev.inmo.kmppscriptbuilder.core.utils.serialFormat +import dev.inmo.kmppscriptbuilder.web.views.* +import kotlinx.browser.document +import kotlinx.dom.appendElement +import org.w3c.dom.* +import org.w3c.dom.url.URL +import org.w3c.files.* + +fun saveFile(content: String, filename: String) { + val a = document.body!!.appendElement("a") { + setAttribute("style", "visibility:hidden; display: none") + } as HTMLAnchorElement + val blob = Blob(arrayOf(content), BlobPropertyBag( + "text/plain;charset=utf-8" + )) + val url = URL.createObjectURL(blob) + a.href = url + a.download = filename + a.target = "_blank" + a.click() + URL.revokeObjectURL(url) + a.remove() +} + +fun main() { + document.addEventListener( + "DOMContentLoaded", + { + val builderView = BuilderView() + + (document.getElementById("openConfig") as HTMLElement).onclick = { + val targetInput = document.body!!.appendElement("input") { + setAttribute("style", "visibility:hidden; display: none") + } as HTMLInputElement + targetInput.type = "file" + targetInput.onchange = { + targetInput.files ?.also { files -> + for (i in (0 until files.length) ) { + files[i] ?.also { file -> + val reader = FileReader() + + reader.onload = { + val content = it.target.asDynamic().result as String + builderView.config = serialFormat.decodeFromString(Config.serializer(), content) + false + } + + reader.readAsText(file) + } + } + } + } + targetInput.click() + targetInput.remove() + false + } + (document.getElementById("saveConfig") as HTMLElement).onclick = { + val filename = "publish.kpsb" + val content = serialFormat.encodeToString(Config.serializer(), builderView.config) + + saveFile(content, filename) + + false + } + (document.getElementById("exportScript") as HTMLElement).onclick = { + val filename = "publish.gradle" + + val content = builderView.config.run { + type.buildMavenGradleConfig( + mavenConfig, + licenses + ) + } + + saveFile(content, filename) + false + } + } + ) +} diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt new file mode 100644 index 0000000..5871e05 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/UkActive.kt @@ -0,0 +1,13 @@ +package dev.inmo.kmppscriptbuilder.web.utils + +import org.w3c.dom.HTMLElement + +var HTMLElement.ukActive: Boolean + get() = classList.contains("uk-active") + set(value) { + if (value) { + classList.add("uk-active") + } else { + classList.remove("uk-active") + } + } diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt new file mode 100644 index 0000000..00d7b0e --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/utils/keepScrolling.kt @@ -0,0 +1,10 @@ +package dev.inmo.kmppscriptbuilder.web.utils + +import kotlinx.browser.document + +inline fun keepScrolling(crossinline block: () -> R): R = document.body ?.let { + val (x, y) = (it.scrollLeft to it.scrollTop) + return block().also { _ -> + it.scrollTo(x, y) + } +} ?: block() diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt new file mode 100644 index 0000000..ee06ba5 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/BuilderView.kt @@ -0,0 +1,23 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.Config +import kotlinx.browser.document +import org.w3c.dom.HTMLElement + +class BuilderView : View { + private val projectTypeView = ProjectTypeView() + private val licensesView = LicensesView(document.getElementById("licensesListDiv") as HTMLElement) + private val mavenInfoTypeView = MavenProjectInfoView() + + var config: Config + get() = Config( + licensesView.licenses, + mavenInfoTypeView.mavenConfig, + projectTypeView.projectType + ) + set(value) { + licensesView.licenses = value.licenses + mavenInfoTypeView.mavenConfig = value.mavenConfig + projectTypeView.projectType = value.type + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt new file mode 100644 index 0000000..2fdc7bd --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/DevelopersView.kt @@ -0,0 +1,35 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.Developer +import org.w3c.dom.* + +class DevelopersView(rootElement: HTMLElement) : MutableListView(rootElement, "Add developer", "Remove developer") { + private val HTMLElement.usernameElement: HTMLInputElement + get() = getElementsByTagName("input")[0] as HTMLInputElement + private val HTMLElement.nameElement: HTMLInputElement + get() = getElementsByTagName("input")[1] as HTMLInputElement + private val HTMLElement.emailElement: HTMLInputElement + get() = getElementsByTagName("input")[2] as HTMLInputElement + + var developers: List + get() = elements.map { + Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value) + } + set(value) { + data = value + } + + override fun createPlainObject(): Developer = Developer("", "", "") + + override fun HTMLElement.addContentBeforeRemoveButton(value: Developer) { + createTextField("Developer ID", "Developer username").value = value.id + createTextField("Developer name", "").value = value.name + createTextField("Developer E-Mail", "").value = value.eMail + } + + override fun HTMLElement.updateElement(from: Developer, to: Developer) { + usernameElement.value = to.id + nameElement.value = to.name + emailElement.value = to.eMail + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt new file mode 100644 index 0000000..9588e26 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/LicensesView.kt @@ -0,0 +1,113 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.License +import dev.inmo.kmppscriptbuilder.core.models.getLicenses +import dev.inmo.micro_utils.coroutines.safeActor +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import io.ktor.client.HttpClient +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.SendChannel +import kotlinx.coroutines.flow.consumeAsFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.dom.appendElement +import org.w3c.dom.* + +class LicensesView( + rootElement: HTMLElement, + client: HttpClient = HttpClient(), + scope: CoroutineScope = CoroutineScope(Dispatchers.Default) +) : MutableListView(rootElement, "Add empty license", "Remove license") { + private val HTMLElement.idElement: HTMLInputElement + get() = getElementsByTagName("input")[0] as HTMLInputElement + private val HTMLElement.titleElement: HTMLInputElement + get() = getElementsByTagName("input")[1] as HTMLInputElement + private val HTMLElement.urlElement: HTMLInputElement + get() = getElementsByTagName("input")[2] as HTMLInputElement + + private class LicenseOfferList( + rootElement: HTMLElement, + private val licensesView: LicensesView, + client: HttpClient, + scope: CoroutineScope + ) : ListView(rootElement, useSimpleDiffStrategy = true) { + private var licensesTemplates: List = emptyList() + + init { + scope.launch { + licensesTemplates = client.getLicenses().values.toList() + changeActor.send(Unit) // update list of searches + } + } + + private val changeActor: SendChannel = scope.run { + val onChangeActor = Channel(Channel.CONFLATED) + onChangeActor.consumeAsFlow().subscribeSafelyWithoutExceptions(scope) { + val lowercased = searchString + data = if (lowercased.isEmpty()) { + emptyList() + } else { + licensesTemplates.filter { + val lowercasedTitle = it.title.toLowerCase() + lowercased.all { it in lowercasedTitle } + } + } + } + onChangeActor + } + private val searchElement = rootElement.createTextField("Quick add", "Type some license name part to find it").apply { + oninput = { + changeActor.offer(Unit) + false + } + } + private var searchString: String + get() = searchElement.value.toLowerCase() + set(value) { + searchElement.value = value + } + + override fun HTMLElement.placeElement(value: License) { + createCommonButton(value.title).onclick = { + searchString = "" + licensesView.licenses += value + changeActor.offer(Unit) + false + } + } + + override fun HTMLElement.updateElement(from: License, to: License) { + getElementsByTagName("button")[0] ?.remove() + placeElement(to) + } + } + + private val licensesOffersList = LicenseOfferList( + rootElement.appendElement("div") { classList.add("uk-padding-small") } as HTMLElement, + this, + client, + scope + ) + + var licenses: List + get() = elements.map { + License(it.idElement.value, it.titleElement.value, it.urlElement.value) + } + set(value) { + data = value + } + + override fun createPlainObject(): License = License("", "", "") + + override fun HTMLElement.addContentBeforeRemoveButton(value: License) { + createTextField("License Id", "Short name like \"Apache-2.0\"").value = value.id + createTextField("License Title", "Official title of license (like \"Apache Software License 2.0\")").value = value.title + createTextField("License URL", "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")").value = value.url ?: "" + } + + override fun HTMLElement.updateElement(from: License, to: License) { + idElement.value = to.id + titleElement.value = to.title + urlElement.value = to.url ?: "" + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt new file mode 100644 index 0000000..700b325 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ListView.kt @@ -0,0 +1,58 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.micro_utils.common.calculateStrictDiff +import kotlinx.dom.appendElement +import org.w3c.dom.HTMLElement + +abstract class ListView( + protected val rootElement: HTMLElement, + useSimpleDiffStrategy: Boolean = false +) : View { + protected val elements = mutableListOf() + private val diffHandling: (old: List, new: List) -> Unit = if (useSimpleDiffStrategy) { + { _, new -> + elements.forEach { it.remove() } + elements.clear() + new.forEach { + val element = instantiateElement() + elements.add(element) + element.placeElement(it) + } + } + } else { + { old, new -> + val diff = old.calculateStrictDiff(new) + diff.removed.forEach { + elements[it.index].remove() + elements.removeAt(it.index) + println(it.value) + } + diff.added.forEach { + val element = instantiateElement() + elements.add(element) + element.placeElement(it.value) + } + diff.replaced.forEach { (old, new) -> + val element = elements.getOrNull(old.index) ?.also { it.updateElement(old.value, new.value) } + if (element == null) { + val newElement = instantiateElement() + newElement.placeElement(new.value) + elements[new.index] = newElement + } + } + } + } + protected var data: List = emptyList() + set(value) { + val old = field + field = value + diffHandling(old, value) + } + + protected abstract fun HTMLElement.placeElement(value: T) + protected abstract fun HTMLElement.updateElement(from: T, to: T) + + private fun instantiateElement() = rootElement.appendElement("div") { + classList.add("uk-padding-small") + } as HTMLElement +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt new file mode 100644 index 0000000..b9cbddc --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MavenProjectInfoView.kt @@ -0,0 +1,44 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.MavenConfig +import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository +import kotlinx.browser.document +import org.w3c.dom.HTMLElement +import org.w3c.dom.HTMLInputElement + +class MavenProjectInfoView : View { + private val nameElement = document.getElementById("projectNameInput") as HTMLInputElement + private val descriptionElement = document.getElementById("projectDescriptionInput") as HTMLInputElement + private val urlElement = document.getElementById("projectUrlInput") as HTMLInputElement + private val vcsUrlElement = document.getElementById("projectVCSUrlInput") as HTMLInputElement + private val includeGpgElement = document.getElementById("includeGpgSignToggle") as HTMLInputElement + private val includeMavenCentralElement = document.getElementById("includeMavenCentralTargetRepoToggle") as HTMLInputElement + private val developersView = DevelopersView(document.getElementById("developersListDiv") as HTMLElement) + private val repositoriesView = RepositoriesView(document.getElementById("repositoriesListDiv") as HTMLElement) + + var mavenConfig: MavenConfig + get() = MavenConfig( + nameElement.value, + descriptionElement.value, + urlElement.value, + vcsUrlElement.value, + includeGpgElement.checked, + developersView.developers, + repositoriesView.repositories + if (includeMavenCentralElement.checked) { + listOf(SonatypeRepository) + } else { + emptyList() + } + ) + set(value) { + nameElement.value = value.name + descriptionElement.value = value.description + urlElement.value = value.url + vcsUrlElement.value = value.vcsUrl + includeGpgElement.checked = value.includeGpgSigning + developersView.developers = value.developers + val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository } + includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size + repositoriesView.repositories = value.repositories + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt new file mode 100644 index 0000000..05d7ee9 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/MutableListView.kt @@ -0,0 +1,41 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.web.utils.keepScrolling +import org.w3c.dom.HTMLElement + +abstract class MutableListView( + rootElement: HTMLElement, + addButtonText: String = "Add", + private val removeButtonText: String = "Remove" +) : ListView(rootElement) { + init { + rootElement.createPrimaryButton(addButtonText).apply { + onclick = { + keepScrolling { + val newObject = createPlainObject() + data += newObject + } + false + } + } + } + + protected abstract fun createPlainObject(): T + protected open fun HTMLElement.addContentBeforeRemoveButton(value: T) {} + protected open fun HTMLElement.addContentAfterRemoveButton(value: T) {} + final override fun HTMLElement.placeElement(value: T) { + addContentBeforeRemoveButton(value) + addRemoveButton() + addContentAfterRemoveButton(value) + } + + private fun HTMLElement.addRemoveButton() { + val button = createPrimaryButton(removeButtonText) + button.onclick = { + elements.indexOf(button.parentElement).takeIf { it > -1 } ?.also { + data -= data[it] + } ?: rootElement.removeChild(this@addRemoveButton) + false + } + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt new file mode 100644 index 0000000..accaaa7 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ProjectTypeView.kt @@ -0,0 +1,33 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.* +import dev.inmo.kmppscriptbuilder.web.utils.ukActive +import kotlinx.browser.document +import org.w3c.dom.HTMLElement + +class ProjectTypeView : View { + private val mppProjectTypeElement = document.getElementById("mppProjectType") as HTMLElement + private val jvmProjectTypeElement = document.getElementById("jvmProjectType") as HTMLElement + + var projectType: ProjectType + get() = if (jvmProjectTypeElement.ukActive) { + JVMProjectType + } else { + MultiplatformProjectType + } + set(value) { + mppProjectTypeElement.ukActive = value == MultiplatformProjectType + jvmProjectTypeElement.ukActive = value == JVMProjectType + } + + init { + mppProjectTypeElement.onclick = { + projectType = MultiplatformProjectType + Unit + } + jvmProjectTypeElement.onclick = { + projectType = JVMProjectType + Unit + } + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt new file mode 100644 index 0000000..93234ca --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/RepositoriesView.kt @@ -0,0 +1,31 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository +import org.w3c.dom.* + +class RepositoriesView(rootElement: HTMLElement) : MutableListView(rootElement, "Add repository", "Remove repository") { + private val HTMLElement.nameElement: HTMLInputElement + get() = getElementsByTagName("input")[0] as HTMLInputElement + private val HTMLElement.urlElement: HTMLInputElement + get() = getElementsByTagName("input")[1] as HTMLInputElement + + var repositories: List + get() = elements.map { + MavenPublishingRepository(it.nameElement.value, it.urlElement.value) + } + set(value) { + data = value + } + + override fun createPlainObject(): MavenPublishingRepository = MavenPublishingRepository("", "") + + override fun HTMLElement.addContentBeforeRemoveButton(value: MavenPublishingRepository) { + createTextField("Repository name", "This name will be used to identify repository in grade").value = value.name + createTextField("Repository URL", "For example: https://repo.maven.apache.org/maven2/").value = value.name + } + + override fun HTMLElement.updateElement(from: MavenPublishingRepository, to: MavenPublishingRepository) { + nameElement.value = to.name + urlElement.value = to.url + } +} \ No newline at end of file diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt new file mode 100644 index 0000000..cf07625 --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/View.kt @@ -0,0 +1,3 @@ +package dev.inmo.kmppscriptbuilder.web.views + +interface View diff --git a/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt new file mode 100644 index 0000000..7f70fdc --- /dev/null +++ b/web/src/jsMain/kotlin/dev/inmo/kmppscriptbuilder/web/views/ViewElements.kt @@ -0,0 +1,35 @@ +package dev.inmo.kmppscriptbuilder.web.views + +import kotlinx.dom.appendElement +import org.w3c.dom.* + +fun HTMLElement.createTextField( + label: String, + placeholder: String +): HTMLInputElement { + return appendElement("div") { + classList.add("uk-margin", "uk-width-1-1") + }.appendElement("label") { + classList.add("uk-form-label") + innerHTML = label + }.run { + val input = appendElement("input") { + classList.add("uk-input", "uk-width-expand") + setAttribute("type", "text") + setAttribute("placeholder", placeholder) + } as HTMLInputElement + input + } +} + +fun HTMLElement.createPrimaryButton(text: String): HTMLButtonElement = (appendElement("button") { + classList.add("uk-button", "uk-button-primary") +} as HTMLButtonElement).apply { + innerText = text +} + +fun HTMLElement.createCommonButton(text: String): HTMLButtonElement = (appendElement("button") { + classList.add("uk-button", "uk-button-default") +} as HTMLButtonElement).apply { + innerText = text +} diff --git a/web/src/jsMain/resources/index.html b/web/src/jsMain/resources/index.html new file mode 100644 index 0000000..4f3a5ea --- /dev/null +++ b/web/src/jsMain/resources/index.html @@ -0,0 +1,80 @@ + + + + + Kotlin Publication Scripts Builder + + + + + +
+
+ Project type +
+ +
+ Licenses +
+ + + + +
+ + Project information + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+ +
+
+ + Developers info +
+ + Repositories info +
+
+
+ + + + + + + \ No newline at end of file