total rework
@ -7,6 +7,9 @@ plugins {
|
||||
apply from: "$mppProjectWithSerializationPresetPath"
|
||||
|
||||
kotlin {
|
||||
js (IR) {
|
||||
binaries.executable()
|
||||
}
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
@ -17,10 +20,27 @@ kotlin {
|
||||
api(compose.runtime)
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(compose.web.core)
|
||||
api libs.ktor.client.js
|
||||
api libs.jsuikit
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
api libs.ktor.client.cio
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compose {
|
||||
desktop {
|
||||
application {
|
||||
mainClass = "dev.inmo.kmppscriptbuilder.desktop.BuilderKt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,18 +5,26 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultDivider
|
||||
|
||||
expect object BuilderViewDrawer : Drawer<BuilderView>
|
||||
@Composable
|
||||
expect fun TopAppBar(
|
||||
config: Config,
|
||||
saveAvailable: Boolean,
|
||||
onSaveAvailable: (Boolean) -> Unit,
|
||||
onNewConfig: (Config) -> Unit
|
||||
)
|
||||
|
||||
class BuilderView : View() {
|
||||
internal val projectTypeView = ProjectTypeView()
|
||||
internal val mavenInfoView = MavenInfoView()
|
||||
internal val licensesView = LicensesView()
|
||||
internal val projectTypeView by mutableStateOf(ProjectTypeView())
|
||||
internal val mavenInfoView by mutableStateOf(MavenInfoView())
|
||||
internal val licensesView by mutableStateOf(LicensesView())
|
||||
|
||||
internal var saveAvailableState by mutableStateOf(false)
|
||||
var config: Config
|
||||
get() = Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType)
|
||||
get() {
|
||||
return Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType)
|
||||
}
|
||||
set(value) {
|
||||
licensesView.licenses = value.licenses
|
||||
mavenInfoView.mavenConfig = value.mavenConfig
|
||||
@ -26,6 +34,20 @@ class BuilderView : View() {
|
||||
|
||||
@Composable
|
||||
override fun build() {
|
||||
with(BuilderViewDrawer) { draw() }
|
||||
TopAppBar(
|
||||
config,
|
||||
saveAvailableState,
|
||||
{
|
||||
saveAvailableState = it
|
||||
}
|
||||
) {
|
||||
config = it
|
||||
}
|
||||
|
||||
projectTypeView.build()
|
||||
DefaultDivider()
|
||||
licensesView.build()
|
||||
DefaultDivider()
|
||||
mavenInfoView.build()
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
|
||||
class DeveloperState(
|
||||
id: String = "",
|
||||
@ -21,11 +23,32 @@ class DeveloperState(
|
||||
private fun Developer.toDeveloperState() = DeveloperState(id, name, eMail)
|
||||
|
||||
class DevelopersView : ListView<DeveloperState>("Developers info") {
|
||||
var developers = mutableStateListOf<Developer>()
|
||||
var developers: List<Developer>
|
||||
get() = itemsList.map { it.toDeveloper() }
|
||||
set(value) {
|
||||
itemsList.apply {
|
||||
clear()
|
||||
addAll(value.map { it.toDeveloperState() })
|
||||
}
|
||||
}
|
||||
|
||||
override val addItemText: String = "Add developer"
|
||||
override val removeItemText: String = "Remove developer"
|
||||
|
||||
override fun createItem(): DeveloperState = DeveloperState()
|
||||
|
||||
@Composable
|
||||
override fun buildView(item: DeveloperState) {
|
||||
CommonTextField(
|
||||
item.id,
|
||||
"Developer username",
|
||||
) { item.id = it }
|
||||
CommonTextField(
|
||||
item.name,
|
||||
"Developer name",
|
||||
) { item.name = it }
|
||||
CommonTextField(
|
||||
item.eMail,
|
||||
"Developer E-Mail",
|
||||
) { item.eMail = it }
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,15 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.inmo.kmppscriptbuilder.core.models.License
|
||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -38,8 +41,14 @@ class LicensesView: VerticalView("Licenses") {
|
||||
licensesListState.addAll(value.map { it.toLicenseState() })
|
||||
}
|
||||
internal val availableLicensesState = mutableStateListOf<License>()
|
||||
internal val licensesOffersToShow = mutableStateListOf<License>()
|
||||
internal var licenseSearchFilter by mutableStateOf("")
|
||||
internal val searchFieldFocused = mutableStateOf(false)
|
||||
internal val licensesOffersToShow = derivedStateOf {
|
||||
val query = licenseSearchFilter.lowercase()
|
||||
availableLicensesState.filter {
|
||||
it.title.lowercase().contains(query)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
@ -50,6 +59,16 @@ class LicensesView: VerticalView("Licenses") {
|
||||
}
|
||||
|
||||
override val content: @Composable () -> Unit = {
|
||||
CommonTextField(
|
||||
licenseSearchFilter,
|
||||
"Search filter",
|
||||
onFocusChanged = {
|
||||
searchFieldFocused.value = it
|
||||
}
|
||||
) { filterText ->
|
||||
licenseSearchFilter = filterText
|
||||
}
|
||||
|
||||
with(LicensesDrawer) { draw() }
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ abstract class ListView<T>(title: String) : VerticalView(title) {
|
||||
|
||||
protected val drawer = ListViewDrawer<T>()
|
||||
|
||||
override val content: () -> Unit = {
|
||||
override val content: @Composable () -> Unit = {
|
||||
with(drawer) {
|
||||
draw()
|
||||
}
|
||||
|
@ -2,9 +2,17 @@ package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
|
||||
import dev.inmo.kmppscriptbuilder.core.models.MavenConfig
|
||||
import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository
|
||||
import dev.inmo.kmppscriptbuilder.core.models.defaultProjectDescription
|
||||
import dev.inmo.kmppscriptbuilder.core.models.defaultProjectName
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel
|
||||
|
||||
expect object MavenInfoDrawer : Drawer<MavenInfoView>
|
||||
expect class GpgSigningOptionDrawer : Drawer<GpgSigning>
|
||||
expect fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer
|
||||
|
||||
class MavenInfoView : VerticalView("Project information") {
|
||||
internal var projectNameProperty by mutableStateOf("")
|
||||
@ -43,10 +51,46 @@ class MavenInfoView : VerticalView("Project information") {
|
||||
publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository }
|
||||
developersView.developers = value.developers
|
||||
repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository }
|
||||
// developersView.developers = value.developers
|
||||
}
|
||||
|
||||
private val gpgSigningDrawer = GpgSigningOptionDrawerWithView(this)
|
||||
|
||||
override val content: @Composable () -> Unit = {
|
||||
with (MavenInfoDrawer) { draw() }
|
||||
CommonTextField(
|
||||
projectNameProperty,
|
||||
"Public project name",
|
||||
) { projectNameProperty = it }
|
||||
CommonTextField(
|
||||
projectDescriptionProperty,
|
||||
"Public project description",
|
||||
) { projectDescriptionProperty = it }
|
||||
CommonTextField(
|
||||
projectUrlProperty,
|
||||
"Public project URL",
|
||||
) { projectUrlProperty = it }
|
||||
CommonTextField(
|
||||
projectVcsUrlProperty,
|
||||
"Public project VCS URL (with .git)",
|
||||
) { projectVcsUrlProperty = it }
|
||||
|
||||
ButtonsPanel(
|
||||
GpgSigning.Disabled,
|
||||
GpgSigning.Optional,
|
||||
GpgSigning.Enabled
|
||||
) {
|
||||
with(gpgSigningDrawer) {
|
||||
with (it) {
|
||||
draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitchWithLabel(
|
||||
"Include publication to MavenCentral",
|
||||
publishToMavenCentralProperty,
|
||||
placeSwitchAtTheStart = true
|
||||
) { publishToMavenCentralProperty = it }
|
||||
developersView.build()
|
||||
repositoriesView.build()
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,31 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.inmo.kmppscriptbuilder.core.models.JSProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.models.JVMProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
expect object ProjectTypeDrawer : Drawer<ProjectTypeView>
|
||||
expect class ProjectTypeDrawer : Drawer<ProjectType>
|
||||
expect fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer
|
||||
|
||||
class ProjectTypeView : VerticalView("Project type") {
|
||||
var projectType by mutableStateOf<ProjectType>(MultiplatformProjectType)
|
||||
private val typeDrawer = ProjectTypeDrawerWithView(this)
|
||||
|
||||
override val content: @Composable () -> Unit = {
|
||||
with(ProjectTypeDrawer) { draw() }
|
||||
ButtonsPanel(
|
||||
MultiplatformProjectType,
|
||||
JVMProjectType,
|
||||
JSProjectType
|
||||
) {
|
||||
with(typeDrawer) {
|
||||
with (it) {
|
||||
draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
class RepositoryState(
|
||||
@ -19,8 +21,6 @@ class RepositoryState(
|
||||
|
||||
private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url)
|
||||
|
||||
expect object RepositoryStateDrawer : Drawer<RepositoryState>
|
||||
|
||||
class RepositoriesView : ListView<RepositoryState>("Repositories info") {
|
||||
var repositories: List<MavenPublishingRepository>
|
||||
get() = itemsList.map { it.toRepository() }
|
||||
@ -38,7 +38,14 @@ class RepositoriesView : ListView<RepositoryState>("Repositories info") {
|
||||
|
||||
@Composable
|
||||
override fun buildView(item: RepositoryState) {
|
||||
with(RepositoryStateDrawer) { with(item) { draw() } }
|
||||
CommonTextField(
|
||||
item.name,
|
||||
"Repository name",
|
||||
) { item.name = it }
|
||||
CommonTextField(
|
||||
item.url,
|
||||
"Repository url",
|
||||
) { item.url = it }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package dev.inmo.kmppscriptbuilder.core.ui.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
interface Drawer<T> {
|
||||
fun interface Drawer<T> {
|
||||
@Composable
|
||||
fun T.draw()
|
||||
}
|
||||
|
@ -9,7 +9,12 @@ expect fun TitleText(text: String)
|
||||
expect fun CommonText(text: String, onClick: (() -> Unit)? = null)
|
||||
|
||||
@Composable
|
||||
expect fun CommonTextField(presetText: String, hint: String, onChange: (String) -> Unit)
|
||||
expect fun CommonTextField(
|
||||
presetText: String,
|
||||
hint: String,
|
||||
onFocusChanged: (Boolean) -> Unit = {},
|
||||
onChange: (String) -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
expect fun SwitchWithLabel(
|
||||
@ -19,3 +24,18 @@ expect fun SwitchWithLabel(
|
||||
switchEnabled: Boolean = true,
|
||||
onCheckedChange: (Boolean) -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
expect fun <T> ButtonsPanel(
|
||||
data: Iterable<T>,
|
||||
itemDrawer: @Composable (T) -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun <T> ButtonsPanel(
|
||||
vararg data: T,
|
||||
itemDrawer: @Composable (T) -> Unit
|
||||
) = ButtonsPanel(data.toList(), itemDrawer)
|
||||
|
||||
@Composable
|
||||
expect fun DefaultDivider()
|
||||
|
@ -5,16 +5,7 @@ import dev.inmo.micro_utils.common.MPPFile
|
||||
|
||||
internal const val appExtension = "kpsb"
|
||||
|
||||
private var lastFile: MPPFile? = null
|
||||
|
||||
fun loadConfigFile(file: MPPFile): Config {
|
||||
lastFile = file
|
||||
return serialFormat.decodeFromString(Config.serializer(), file.text())
|
||||
}
|
||||
|
||||
expect fun MPPFile.text(): String
|
||||
|
||||
expect fun loadConfig(): Config?
|
||||
expect fun openNewConfig(onParsed: (Config) -> Unit)
|
||||
|
||||
expect fun saveConfig(config: Config): Boolean
|
||||
|
||||
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 452 B |
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B |
@ -0,0 +1,14 @@
|
||||
package dev.inmo.kmppscriptbuilder.core
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.BuilderView
|
||||
import kotlinx.browser.window
|
||||
import org.jetbrains.compose.web.renderComposableInBody
|
||||
|
||||
fun main() {
|
||||
window.addEventListener("load", {
|
||||
val builder = BuilderView()
|
||||
renderComposableInBody {
|
||||
builder.build()
|
||||
}
|
||||
})
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.DefaultButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual class GpgSigningOptionDrawer(
|
||||
private val mavenInfoView: MavenInfoView
|
||||
) : Drawer<GpgSigning> {
|
||||
@Composable
|
||||
override fun GpgSigning.draw() {
|
||||
if (mavenInfoView.gpgSignProperty == this) {
|
||||
DefaultButton(name, UIKitButton.Type.Primary)
|
||||
} else {
|
||||
DefaultButton(name, UIKitButton.Type.Default) {
|
||||
mavenInfoView.gpgSignProperty = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view)
|
@ -0,0 +1,59 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.DefaultButton
|
||||
import dev.inmo.jsuikit.elements.Divider
|
||||
import dev.inmo.jsuikit.modifiers.UIKitButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.jsuikit.modifiers.builder
|
||||
import dev.inmo.jsuikit.utils.Attrs
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import org.jetbrains.compose.web.dom.Div
|
||||
|
||||
actual object LicensesDrawer : Drawer<LicensesView> {
|
||||
@Composable
|
||||
override fun LicensesView.draw() {
|
||||
dev.inmo.jsuikit.elements.List(
|
||||
licensesOffersToShow.value,
|
||||
Attrs {
|
||||
if (!searchFieldFocused.value) {
|
||||
hidden()
|
||||
}
|
||||
}
|
||||
) {
|
||||
DefaultButton(
|
||||
it.title,
|
||||
UIKitButton.Type.Text
|
||||
) { _ ->
|
||||
licensesListState.add(it.toLicenseState())
|
||||
licenseSearchFilter = ""
|
||||
}
|
||||
Divider.Common()
|
||||
}
|
||||
|
||||
DefaultButton("Add empty license", UIKitButton.Type.Primary, UIKitMargin.Small) {
|
||||
licensesListState.add(LicenseState())
|
||||
}
|
||||
|
||||
licensesListState.forEach { license ->
|
||||
Div(UIKitMargin.Small.builder()) {
|
||||
CommonTextField(
|
||||
license.id,
|
||||
"License ID",
|
||||
) { license.id = it }
|
||||
CommonTextField(
|
||||
license.title,
|
||||
"License title",
|
||||
) { license.title = it }
|
||||
CommonTextField(
|
||||
license.url ?: "",
|
||||
"License URL",
|
||||
) { license.url = it }
|
||||
DefaultButton("Remove", UIKitButton.Type.Danger, UIKitMargin.Small) {
|
||||
licensesListState.remove(license)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.DefaultButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.jsuikit.modifiers.builder
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import org.jetbrains.compose.web.dom.Div
|
||||
|
||||
actual class ListViewDrawer<T> : Drawer<ListView<T>> {
|
||||
@Composable
|
||||
override fun ListView<T>.draw() {
|
||||
DefaultButton(addItemText, UIKitButton.Type.Primary ) { itemsList.add(createItem()) }
|
||||
itemsList.forEach { item ->
|
||||
Div(UIKitMargin.Small.builder()) {
|
||||
buildView(item)
|
||||
DefaultButton(removeItemText, UIKitButton.Type.Danger, UIKitMargin.Small) {
|
||||
itemsList.remove(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.DefaultButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual class ProjectTypeDrawer(
|
||||
private val projectTypeView: ProjectTypeView
|
||||
) : Drawer<ProjectType> {
|
||||
@Composable
|
||||
override fun ProjectType.draw() {
|
||||
if (projectTypeView.projectType == this) {
|
||||
DefaultButton(name, UIKitButton.Type.Primary)
|
||||
} else {
|
||||
DefaultButton(name, UIKitButton.Type.Default) {
|
||||
projectTypeView.projectType = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view)
|
@ -0,0 +1,82 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.Icon
|
||||
import dev.inmo.jsuikit.elements.NavItemElement
|
||||
import dev.inmo.jsuikit.elements.Navbar
|
||||
import dev.inmo.jsuikit.elements.NavbarNav
|
||||
import dev.inmo.jsuikit.elements.drawAsLink
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.jsuikit.modifiers.UIKitPadding
|
||||
import dev.inmo.jsuikit.modifiers.UIKitText
|
||||
import dev.inmo.jsuikit.modifiers.UIKitTooltipModifier
|
||||
import dev.inmo.jsuikit.modifiers.builder
|
||||
import dev.inmo.jsuikit.modifiers.include
|
||||
import dev.inmo.jsuikit.utils.AttrsWithContentBuilder
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.exportGradle
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.saveConfig
|
||||
import org.jetbrains.compose.web.dom.A
|
||||
import org.jetbrains.compose.web.dom.Div
|
||||
import org.jetbrains.compose.web.dom.Img
|
||||
import org.jetbrains.compose.web.dom.Text
|
||||
|
||||
@Composable
|
||||
actual fun TopAppBar(
|
||||
config: Config,
|
||||
saveAvailable: Boolean,
|
||||
onSaveAvailable: (Boolean) -> Unit,
|
||||
onNewConfig: (Config) -> Unit
|
||||
) {
|
||||
Navbar(
|
||||
leftBuilder = AttrsWithContentBuilder {
|
||||
Div(
|
||||
{
|
||||
onClick {
|
||||
console.log(config)
|
||||
}
|
||||
include(UIKitPadding.Size.Small, UIKitText.Style.Lead)
|
||||
}
|
||||
) {
|
||||
Text("Kotlin publication scripts builder")
|
||||
}
|
||||
Div(UIKitMargin.Small.builder()) {
|
||||
A("https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder") {
|
||||
Img("https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic")
|
||||
}
|
||||
}
|
||||
},
|
||||
rightBuilder = AttrsWithContentBuilder {
|
||||
NavbarNav(
|
||||
AttrsWithContentBuilder {
|
||||
NavItemElement(
|
||||
UIKitTooltipModifier("Open file")
|
||||
) {
|
||||
Icon.Storage.Pull.drawAsLink {
|
||||
openNewConfig(onNewConfig)
|
||||
}
|
||||
}
|
||||
},
|
||||
AttrsWithContentBuilder {
|
||||
NavItemElement(
|
||||
UIKitTooltipModifier("Save config")
|
||||
) {
|
||||
Icon.Storage.Push.drawAsLink {
|
||||
saveConfig(config)
|
||||
}
|
||||
}
|
||||
},
|
||||
AttrsWithContentBuilder {
|
||||
NavItemElement(
|
||||
UIKitTooltipModifier("Export gradle script")
|
||||
) {
|
||||
Icon.Storage.Upload.drawAsLink {
|
||||
exportGradle(config)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.modifiers.UIKitForm
|
||||
import dev.inmo.jsuikit.modifiers.builder
|
||||
import org.jetbrains.compose.web.dom.Legend
|
||||
import org.jetbrains.compose.web.dom.Text
|
||||
|
||||
actual abstract class View {
|
||||
@Composable
|
||||
@ -9,4 +13,8 @@ actual abstract class View {
|
||||
|
||||
@Composable
|
||||
actual fun View.DrawVertically(title: String, block: @Composable () -> Unit) {
|
||||
Legend(UIKitForm.Legend.builder()) {
|
||||
Text(title)
|
||||
}
|
||||
block()
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.inmo.jsuikit.elements.DefaultButton
|
||||
import dev.inmo.jsuikit.elements.DefaultInput
|
||||
import dev.inmo.jsuikit.elements.Divider
|
||||
import dev.inmo.jsuikit.elements.Flex
|
||||
import dev.inmo.jsuikit.elements.Icon
|
||||
import dev.inmo.jsuikit.elements.Label
|
||||
import dev.inmo.jsuikit.elements.drawAsFormInputPart
|
||||
import dev.inmo.jsuikit.modifiers.UIKitButton
|
||||
import dev.inmo.jsuikit.modifiers.UIKitFlex
|
||||
import dev.inmo.jsuikit.modifiers.UIKitForm
|
||||
import dev.inmo.jsuikit.modifiers.UIKitInverse
|
||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
|
||||
import dev.inmo.jsuikit.modifiers.UIKitText
|
||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
|
||||
import dev.inmo.jsuikit.modifiers.builder
|
||||
import dev.inmo.jsuikit.modifiers.include
|
||||
import dev.inmo.jsuikit.utils.Attrs
|
||||
import org.jetbrains.compose.web.attributes.InputType
|
||||
import org.jetbrains.compose.web.dom.Div
|
||||
import org.jetbrains.compose.web.dom.Legend
|
||||
import org.jetbrains.compose.web.dom.Text
|
||||
|
||||
@Composable
|
||||
actual fun TitleText(text: String) {
|
||||
Legend(UIKitForm.Legend.builder()) {
|
||||
Text(text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun CommonText(text: String, onClick: (() -> Unit)?) {
|
||||
Div(
|
||||
{
|
||||
onClick ?.let {
|
||||
this.onClick { _ ->
|
||||
it()
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun CommonTextField(
|
||||
presetText: String,
|
||||
hint: String,
|
||||
onFocusChanged: (Boolean) -> Unit,
|
||||
onChange: (String) -> Unit
|
||||
) {
|
||||
DefaultInput(
|
||||
InputType.Text,
|
||||
presetText,
|
||||
false,
|
||||
placeholder = hint,
|
||||
attributesCustomizer = {
|
||||
onFocusIn { onFocusChanged(true) }
|
||||
onFocusOut { onFocusChanged(false) }
|
||||
},
|
||||
onChange = onChange
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun SwitchWithLabel(
|
||||
label: String,
|
||||
checked: Boolean,
|
||||
placeSwitchAtTheStart: Boolean,
|
||||
switchEnabled: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit
|
||||
) {
|
||||
DefaultButton(
|
||||
if (checked) {
|
||||
UIKitButton.Type.Primary
|
||||
} else {
|
||||
UIKitButton.Type.Default
|
||||
},
|
||||
disabled = !switchEnabled,
|
||||
onClick = {
|
||||
onCheckedChange(!checked)
|
||||
},
|
||||
attributesCustomizer = {
|
||||
include(UIKitUtility.Inline)
|
||||
}
|
||||
) {
|
||||
if (checked) {
|
||||
Icon.App.Check.drawAsFormInputPart(UIKitInverse.Light)
|
||||
}
|
||||
Text(label)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun <T> ButtonsPanel(data: Iterable<T>, itemDrawer: @Composable (T) -> Unit) {
|
||||
Flex(UIKitFlex.Alignment.Vertical.Middle, UIKitMargin.Small) {
|
||||
data.forEach { itemDrawer(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun DefaultDivider() {
|
||||
Divider.Common()
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.utils
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.dom.appendElement
|
||||
import org.w3c.dom.HTMLAnchorElement
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.dom.url.URL
|
||||
import org.w3c.files.Blob
|
||||
import org.w3c.files.BlobPropertyBag
|
||||
import org.w3c.files.FileReader
|
||||
import org.w3c.files.get
|
||||
|
||||
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(
|
||||
"application/*;charset=utf-8"
|
||||
))
|
||||
val url = URL.createObjectURL(blob)
|
||||
a.href = url
|
||||
a.download = filename
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
a.remove()
|
||||
}
|
||||
|
||||
actual fun openNewConfig(onParsed: (Config) -> Unit) {
|
||||
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
|
||||
onParsed(serialFormat.decodeFromString(Config.serializer(), content))
|
||||
false
|
||||
}
|
||||
|
||||
reader.readAsText(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetInput.click()
|
||||
targetInput.remove()
|
||||
}
|
||||
|
||||
actual fun saveConfig(config: Config): Boolean {
|
||||
saveFile(
|
||||
serialFormat.encodeToString(Config.serializer(), config),
|
||||
"publish.kpsb"
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
actual fun exportGradle(config: Config): Boolean {
|
||||
val filename = "publish.gradle"
|
||||
|
||||
val content = config.run {
|
||||
type.buildMavenGradleConfig(
|
||||
mavenConfig,
|
||||
licenses
|
||||
)
|
||||
}
|
||||
|
||||
saveFile(content, filename)
|
||||
return true
|
||||
}
|
||||
|
||||
actual fun saveAs(config: Config): Boolean {
|
||||
saveFile(
|
||||
serialFormat.encodeToString(Config.serializer(), config),
|
||||
"publish.kpsb"
|
||||
)
|
||||
return true
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.utils
|
||||
|
||||
actual fun openLink(link: String): Boolean {
|
||||
dev.inmo.micro_utils.common.openLink(link)
|
||||
return true
|
||||
}
|
1
core/src/jsMain/resources/css/uikit.min.css
vendored
Normal file
72
core/src/jsMain/resources/index.html
Normal file
@ -0,0 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kotlin Publication Scripts Builder</title>
|
||||
<!-- UIkit CSS -->
|
||||
<link rel="stylesheet" href="./css/uikit.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- <form class="uk-padding-small">-->
|
||||
<!-- <fieldset class="uk-fieldset">-->
|
||||
<!-- <legend class="uk-legend">Project type</legend>-->
|
||||
<!-- <div class="uk-padding-small">-->
|
||||
<!-- <ul class="uk-subnav uk-subnav-pill">-->
|
||||
<!-- <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>-->
|
||||
<!-- <li id="jvmProjectType"><a href="#">JVM</a></li>-->
|
||||
<!-- <li id="jsProjectType"><a href="#">JS</a></li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- </div>-->
|
||||
<!-- <legend class="uk-legend">Licenses</legend>-->
|
||||
<!-- <div id="licensesListDiv" class="uk-padding-small"></div>-->
|
||||
|
||||
<!-- <legend class="uk-legend">Project information</legend>-->
|
||||
|
||||
<!-- <div class="uk-padding-small">-->
|
||||
<!-- <div class="uk-margin uk-width-1-1">-->
|
||||
<!-- <label class="uk-form-label" for="projectNameInput">Public project name</label>-->
|
||||
<!-- <input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="uk-margin uk-width-1-1">-->
|
||||
<!-- <label class="uk-form-label" for="projectDescriptionInput">Public project description</label>-->
|
||||
<!-- <input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="uk-margin uk-width-1-1">-->
|
||||
<!-- <label class="uk-form-label" for="projectUrlInput">Public project URL</label>-->
|
||||
<!-- <input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme">-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="uk-margin uk-width-1-1">-->
|
||||
<!-- <label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label>-->
|
||||
<!-- <input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file">-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="uk-margin">-->
|
||||
<!-- <label>GPG Signing</label>-->
|
||||
|
||||
<!-- <div class="uk-padding-small">-->
|
||||
<!-- <ul class="uk-subnav uk-subnav-pill">-->
|
||||
<!-- <li id="disableGpgSigning" class="uk-active" uk-tooltip="title: Signing will not be added"><a href="#">Disabled</a></li>-->
|
||||
<!-- <li id="optionalGpgSigning" uk-tooltip="title: Signing will be added, but disabled in case of absence 'signatory.keyId'"><a href="#">Optional</a></li>-->
|
||||
<!-- <li id="enableGpgSigning" uk-tooltip="title: Signing will be always enabled"><a href="#">Enabled</a></li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="uk-margin">-->
|
||||
<!-- <label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <legend class="uk-legend">Developers info</legend>-->
|
||||
<!-- <div id="developersListDiv" class="uk-padding-small"></div>-->
|
||||
|
||||
<!-- <legend class="uk-legend">Repositories info</legend>-->
|
||||
<!-- <div id="repositoriesListDiv" class="uk-padding-small"></div>-->
|
||||
<!-- </fieldset>-->
|
||||
<!-- </form>-->
|
||||
<!-- UIkit JS -->
|
||||
<script src="./js/uikit.min.js"></script>
|
||||
<script src="./js/uikit-icons.min.js"></script>
|
||||
<!-- Internal JS -->
|
||||
<script src="kmppscriptbuilder.core.js"></script>
|
||||
</body>
|
||||
</html>
|
1
core/src/jsMain/resources/js/uikit-icons.min.js
vendored
Normal file
1
core/src/jsMain/resources/js/uikit.min.js
vendored
Normal file
@ -1,4 +1,4 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop
|
||||
package dev.inmo.kmppscriptbuilder.core
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
@ -9,9 +9,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.init
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.loadConfigFile
|
||||
import dev.inmo.kmppscriptbuilder.desktop.views.BuilderView
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.BuilderView
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.loadConfigFile
|
||||
import java.io.File
|
||||
|
||||
//private val uncaughtExceptionsBC = BroadcastChannel<DefaultErrorHandler.ErrorEvent>(Channel.CONFLATED)
|
||||
@ -48,7 +47,9 @@ fun main(args: Array<String>) = application {
|
||||
.fillMaxSize()
|
||||
.verticalScroll(stateVertical)
|
||||
) {
|
||||
builder.init()
|
||||
Column {
|
||||
builder.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.exportGradle
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.loadConfig
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.saveAs
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.saveConfig
|
||||
|
||||
actual object BuilderViewDrawer : Drawer<BuilderView> {
|
||||
override fun BuilderView.draw() {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Column() {
|
||||
TopAppBar(
|
||||
@Composable {
|
||||
Text("Kotlin publication scripts builder", Modifier.clickable { println(config) })
|
||||
},
|
||||
actions = {
|
||||
createIcon("Open file", "images/open_file.svg") {
|
||||
loadConfig()?.also {
|
||||
config = it
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAvailableState) {
|
||||
createIcon("Save", "images/save_file.svg") {
|
||||
saveConfig(config)
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAvailableState) {
|
||||
createIcon("Export Gradle script", "images/export_gradle.svg") {
|
||||
exportGradle(config)
|
||||
}
|
||||
}
|
||||
|
||||
createIcon("Save as", "images/save_as.svg") {
|
||||
if (saveAs(config)) {
|
||||
saveAvailableState = true
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
projectTypeView.init()
|
||||
Divider()
|
||||
licensesView.init()
|
||||
Divider()
|
||||
mavenInfoView.init()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel
|
||||
|
||||
actual class GpgSigningOptionDrawer(
|
||||
private val mavenInfoView: MavenInfoView
|
||||
) : Drawer<GpgSigning> {
|
||||
@Composable
|
||||
override fun GpgSigning.draw() {
|
||||
if (mavenInfoView.gpgSignProperty == this) {
|
||||
Button({}, Modifier.padding(8.dp)) {
|
||||
Text(name)
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(
|
||||
{
|
||||
mavenInfoView.gpgSignProperty = this
|
||||
},
|
||||
Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view)
|
@ -4,6 +4,9 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
|
||||
@ -11,44 +14,39 @@ import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual object LicensesDrawer : Drawer<LicensesView> {
|
||||
@Composable
|
||||
override fun LicensesView.draw() {
|
||||
CommonTextField(licenseSearchFilter, "Search filter") { filterText ->
|
||||
licenseSearchFilter = filterText
|
||||
licensesOffersToShow.clear()
|
||||
if (licenseSearchFilter.isNotEmpty()) {
|
||||
licensesOffersToShow.addAll(
|
||||
availableLicensesState.filter { filterText.all { symbol -> symbol.lowercaseChar() in it.title } }
|
||||
)
|
||||
}
|
||||
}
|
||||
if (searchFieldFocused.value) {
|
||||
Column {
|
||||
licensesOffersToShow.forEach {
|
||||
licensesOffersToShow.value.forEach {
|
||||
Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
|
||||
CommonText(it.title) {
|
||||
licensesListState.add(it.toLicenseState())
|
||||
licenseSearchFilter = ""
|
||||
licensesOffersToShow.clear()
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
Button({ licensesListState.add(LicenseState()) }, Modifier.padding(8.dp)) {
|
||||
CommonText("Add empty license",)
|
||||
}
|
||||
|
||||
Button({ licensesListState.add(LicenseState()) }, Modifier.padding(8.dp)) {
|
||||
CommonText("Add empty license")
|
||||
}
|
||||
|
||||
licensesListState.forEach { license ->
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
CommonTextField(
|
||||
license.id,
|
||||
"License ID"
|
||||
"License ID",
|
||||
) { license.id = it }
|
||||
CommonTextField(
|
||||
license.title,
|
||||
"License title"
|
||||
"License title",
|
||||
) { license.title = it }
|
||||
CommonTextField(
|
||||
license.url ?: "",
|
||||
"License URL"
|
||||
"License URL",
|
||||
) { license.url = it }
|
||||
Button({ licensesListState.remove(license) }, Modifier.padding(8.dp)) {
|
||||
CommonText("Remove",)
|
||||
|
@ -3,12 +3,14 @@ package dev.inmo.kmppscriptbuilder.core.ui
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual class ListViewDrawer<T> : Drawer<ListView<T>> {
|
||||
@Composable
|
||||
override fun ListView<T>.draw() {
|
||||
Button({ itemsList.add(createItem()) }) {
|
||||
CommonText(addItemText,)
|
||||
|
@ -1,68 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel
|
||||
|
||||
actual object MavenInfoDrawer : Drawer<MavenInfoView> {
|
||||
@Composable
|
||||
private fun MavenInfoView.addGpgSigningButton(gpgSigning: GpgSigning) {
|
||||
if (gpgSignProperty == gpgSigning) {
|
||||
Button({}, Modifier.padding(8.dp)) {
|
||||
Text(gpgSigning.name)
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(
|
||||
{
|
||||
gpgSignProperty = gpgSigning
|
||||
},
|
||||
Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(gpgSigning.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun MavenInfoView.draw() {
|
||||
CommonTextField(
|
||||
projectNameProperty,
|
||||
"Public project name"
|
||||
) { projectNameProperty = it }
|
||||
CommonTextField(
|
||||
projectDescriptionProperty,
|
||||
"Public project description"
|
||||
) { projectDescriptionProperty = it }
|
||||
CommonTextField(
|
||||
projectUrlProperty,
|
||||
"Public project URL"
|
||||
) { projectUrlProperty = it }
|
||||
CommonTextField(
|
||||
projectVcsUrlProperty,
|
||||
"Public project VCS URL (with .git)"
|
||||
) { projectVcsUrlProperty = it }
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Gpg Signing: ")
|
||||
addGpgSigningButton(GpgSigning.Disabled)
|
||||
addGpgSigningButton(GpgSigning.Optional)
|
||||
addGpgSigningButton(GpgSigning.Enabled)
|
||||
}
|
||||
|
||||
SwitchWithLabel(
|
||||
"Include publication to MavenCentral",
|
||||
publishToMavenCentralProperty,
|
||||
placeSwitchAtTheStart = true
|
||||
) { publishToMavenCentralProperty = it }
|
||||
developersView.init()
|
||||
repositoriesView.init()
|
||||
}
|
||||
}
|
@ -15,30 +15,26 @@ import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual object ProjectTypeDrawer : Drawer<ProjectTypeView> {
|
||||
actual class ProjectTypeDrawer(
|
||||
private val projectTypeView: ProjectTypeView
|
||||
) : Drawer<ProjectType> {
|
||||
@Composable
|
||||
private fun ProjectTypeView.addProjectTypeButton(newProjectType: ProjectType) {
|
||||
if (projectType == newProjectType) {
|
||||
override fun ProjectType.draw() {
|
||||
if (projectTypeView.projectType == this) {
|
||||
Button({}, Modifier.padding(8.dp)) {
|
||||
Text(newProjectType.name)
|
||||
Text(name)
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(
|
||||
{
|
||||
projectType = newProjectType
|
||||
projectTypeView.projectType = this
|
||||
},
|
||||
Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(newProjectType.name)
|
||||
Text(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ProjectTypeView.draw() {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
addProjectTypeButton(MultiplatformProjectType)
|
||||
addProjectTypeButton(JVMProjectType)
|
||||
addProjectTypeButton(JSProjectType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view)
|
||||
|
@ -1,18 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
|
||||
|
||||
actual object RepositoryStateDrawer : Drawer<RepositoriesView> {
|
||||
override fun RepositoriesView.draw() {
|
||||
CommonTextField(
|
||||
item.name,
|
||||
"Repository name"
|
||||
) { item.name = it }
|
||||
CommonTextField(
|
||||
item.url,
|
||||
"Repository url"
|
||||
) { item.url = it }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package dev.inmo.kmppscriptbuilder.core.ui
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.TooltipArea
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.primarySurface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.exportGradle
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.saveAs
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.saveConfig
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun createIcon(
|
||||
tooltip: String,
|
||||
resource: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
TooltipArea(
|
||||
tooltip = {
|
||||
Surface(
|
||||
modifier = Modifier.shadow(4.dp),
|
||||
color = MaterialTheme.colors.primarySurface,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
) {
|
||||
Text(tooltip, modifier = Modifier.padding(10.dp), color = MaterialTheme.colors.onPrimary)
|
||||
}
|
||||
}
|
||||
) {
|
||||
IconButton(onClick) {
|
||||
Image(
|
||||
painter = painterResource(resource),
|
||||
contentDescription = tooltip
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun TopAppBar(
|
||||
config: Config,
|
||||
saveAvailable: Boolean,
|
||||
onSaveAvailable: (Boolean) -> Unit,
|
||||
onNewConfig: (Config) -> Unit
|
||||
) {
|
||||
TopAppBar(
|
||||
@Composable {
|
||||
Text("Kotlin publication scripts builder", Modifier.clickable { println(config) })
|
||||
},
|
||||
actions = {
|
||||
createIcon("Open file", "images/open_file.svg") {
|
||||
openNewConfig(onNewConfig)
|
||||
}
|
||||
|
||||
if (saveAvailable) {
|
||||
createIcon("Save", "images/save_file.svg") {
|
||||
saveConfig(config)
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAvailable) {
|
||||
createIcon("Export Gradle script", "images/export_gradle.svg") {
|
||||
exportGradle(config)
|
||||
}
|
||||
}
|
||||
|
||||
createIcon("Save as", "images/save_as.svg") {
|
||||
if (saveAs(config)) {
|
||||
onSaveAvailable(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -6,12 +6,14 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@ -29,15 +31,15 @@ actual fun SwitchWithLabel(
|
||||
switchEnabled: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit
|
||||
) {
|
||||
Row(Modifier.padding(0.dp, 8.dp), Arrangement.Start, Alignment.Top) {
|
||||
Row(Modifier.padding(0.dp, 8.dp).clickable { onCheckedChange(!checked) }, Arrangement.Start, Alignment.Top) {
|
||||
val switchCreator = @Composable {
|
||||
Switch(checked, onCheckedChange, Modifier.padding(8.dp, 0.dp), enabled = switchEnabled)
|
||||
Switch(checked, null, Modifier.padding(8.dp, 0.dp), enabled = switchEnabled)
|
||||
}
|
||||
if (placeSwitchAtTheStart) {
|
||||
switchCreator()
|
||||
}
|
||||
Box(Modifier.fillMaxWidth().align(Alignment.CenterVertically).clickable { }) {
|
||||
CommonText(label,)
|
||||
Box(Modifier.fillMaxWidth().align(Alignment.CenterVertically)) {
|
||||
CommonText(label)
|
||||
}
|
||||
if (!placeSwitchAtTheStart) {
|
||||
switchCreator()
|
||||
@ -46,11 +48,18 @@ actual fun SwitchWithLabel(
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun CommonTextField(presetText: String, hint: String, onChange: (String) -> Unit) {
|
||||
actual fun CommonTextField(
|
||||
presetText: String,
|
||||
hint: String,
|
||||
onFocusChanged: (Boolean) -> Unit,
|
||||
onChange: (String) -> Unit
|
||||
) {
|
||||
OutlinedTextField(
|
||||
presetText,
|
||||
onChange,
|
||||
Modifier.fillMaxWidth(),
|
||||
Modifier.fillMaxWidth().onFocusChanged {
|
||||
onFocusChanged(it.isFocused)
|
||||
},
|
||||
singleLine = true,
|
||||
label = {
|
||||
CommonText(hint,)
|
||||
@ -69,3 +78,15 @@ actual fun TitleText(text: String) {
|
||||
text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun <T> ButtonsPanel(data: Iterable<T>, itemDrawer: @Composable (T) -> Unit) {
|
||||
Row {
|
||||
data.forEach { itemDrawer(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun DefaultDivider() {
|
||||
Divider()
|
||||
}
|
||||
|
@ -2,33 +2,29 @@ package dev.inmo.kmppscriptbuilder.core.utils
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.FileFilter
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.serialFormat
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import java.io.File
|
||||
import javax.swing.JFileChooser
|
||||
|
||||
private const val appExtension = "kpsb"
|
||||
fun MPPFile.text() = readText()
|
||||
|
||||
private var lastFile: File? = null
|
||||
internal var lastFile: MPPFile? = null
|
||||
|
||||
fun loadConfigFile(file: File): Config {
|
||||
fun loadConfigFile(file: MPPFile): Config {
|
||||
lastFile = file
|
||||
return serialFormat.decodeFromString(Config.serializer(), file.readText())
|
||||
return serialFormat.decodeFromString(Config.serializer(), file.text())
|
||||
}
|
||||
|
||||
actual fun MPPFile.text() = readText()
|
||||
|
||||
actual fun loadConfig(): Config? {
|
||||
actual fun openNewConfig(onParsed: (Config) -> Unit) {
|
||||
val fc = JFileChooser(lastFile ?.parent)
|
||||
fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension")))
|
||||
fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json")))
|
||||
return when (fc.showOpenDialog(null)) {
|
||||
when (fc.showOpenDialog(null)) {
|
||||
JFileChooser.APPROVE_OPTION -> {
|
||||
val file = fc.selectedFile
|
||||
lastFile = file
|
||||
return serialFormat.decodeFromString(Config.serializer(), fc.selectedFile.readText())
|
||||
onParsed(serialFormat.decodeFromString(Config.serializer(), fc.selectedFile.readText()))
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
alias(libs.plugins.jb.compose)
|
||||
}
|
||||
|
||||
apply from: "$mppJavaProjectPresetPath"
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation project(":kmppscriptbuilder.core")
|
||||
}
|
||||
}
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation libs.ktor.client.cio
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "dev.inmo.kmppscriptbuilder.desktop.BuilderKt"
|
||||
}
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.utils
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.FileFilter
|
||||
import dev.inmo.kmppscriptbuilder.core.utils.serialFormat
|
||||
import java.io.File
|
||||
import javax.swing.JFileChooser
|
||||
|
||||
private const val appExtension = "kpsb"
|
||||
|
||||
private var lastFile: File? = null
|
||||
|
||||
fun loadConfigFile(file: File): Config {
|
||||
lastFile = file
|
||||
return serialFormat.decodeFromString(Config.serializer(), file.readText())
|
||||
}
|
||||
|
||||
fun loadConfig(): Config? {
|
||||
val fc = JFileChooser(lastFile ?.parent)
|
||||
fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension")))
|
||||
fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json")))
|
||||
return when (fc.showOpenDialog(null)) {
|
||||
JFileChooser.APPROVE_OPTION -> {
|
||||
val file = fc.selectedFile
|
||||
lastFile = file
|
||||
return serialFormat.decodeFromString(Config.serializer(), fc.selectedFile.readText())
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun saveConfig(config: Config): Boolean {
|
||||
return lastFile ?.also {
|
||||
it.writeText(serialFormat.encodeToString(Config.serializer(), config))
|
||||
} != null
|
||||
}
|
||||
|
||||
fun exportGradle(config: Config): Boolean {
|
||||
val fc = JFileChooser(lastFile ?.parent)
|
||||
fc.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
|
||||
return when (fc.showSaveDialog(null)) {
|
||||
JFileChooser.APPROVE_OPTION -> {
|
||||
val file = fc.selectedFile
|
||||
val mavenConfigContent = config.type.buildMavenGradleConfig(
|
||||
config.mavenConfig,
|
||||
config.licenses
|
||||
)
|
||||
File(file, "publish.gradle").apply {
|
||||
delete()
|
||||
createNewFile()
|
||||
writeText(mavenConfigContent)
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun saveAs(config: Config): Boolean {
|
||||
val fc = JFileChooser(lastFile ?.parent)
|
||||
fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension")))
|
||||
fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json")))
|
||||
return when (fc.showSaveDialog(null)) {
|
||||
JFileChooser.APPROVE_OPTION -> {
|
||||
val file = fc.selectedFile
|
||||
val resultFile = if (file.extension == "") {
|
||||
File(file.parentFile, "${file.name}.$appExtension")
|
||||
} else {
|
||||
file
|
||||
}
|
||||
resultFile.writeText(serialFormat.encodeToString(Config.serializer(), config))
|
||||
lastFile = resultFile
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.utils
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
val commonTextFieldTextStyle = TextStyle(
|
||||
fontSize = 12.sp
|
||||
)
|
||||
|
||||
@Composable
|
||||
inline fun TitleText(text: String) = Text(
|
||||
text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp
|
||||
)
|
||||
|
||||
@Composable
|
||||
inline fun CommonText(text: String, modifier: Modifier = Modifier) = Text(
|
||||
text, modifier = modifier
|
||||
)
|
||||
|
||||
@Composable
|
||||
inline fun CommonTextField(presetText: String, hint: String, noinline onChange: (String) -> Unit) = OutlinedTextField(
|
||||
presetText,
|
||||
onChange,
|
||||
Modifier.fillMaxWidth(),
|
||||
singleLine = true,
|
||||
label = {
|
||||
CommonText(hint)
|
||||
}
|
||||
)
|
||||
|
||||
@Composable
|
||||
inline fun SwitchWithLabel(
|
||||
label: String,
|
||||
checked: Boolean,
|
||||
placeSwitchAtTheStart: Boolean = false,
|
||||
switchEnabled: Boolean = true,
|
||||
modifier: Modifier = Modifier.padding(0.dp, 8.dp),
|
||||
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
|
||||
verticalAlignment: Alignment.Vertical = Alignment.Top,
|
||||
switchModifier: Modifier = Modifier.padding(8.dp, 0.dp),
|
||||
noinline onCheckedChange: (Boolean) -> Unit
|
||||
) = Row(modifier, horizontalArrangement, verticalAlignment) {
|
||||
val switchCreator = @Composable {
|
||||
Switch(checked, onCheckedChange, switchModifier, enabled = switchEnabled)
|
||||
}
|
||||
if (placeSwitchAtTheStart) {
|
||||
switchCreator()
|
||||
}
|
||||
CommonText(label, Modifier.align(Alignment.CenterVertically).clickable { })
|
||||
if (!placeSwitchAtTheStart) {
|
||||
switchCreator()
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.utils
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
abstract class View {
|
||||
protected open val defaultModifier = Modifier.fillMaxWidth().padding(8.dp)
|
||||
|
||||
@Composable
|
||||
abstract fun build()
|
||||
}
|
||||
|
||||
abstract class VerticalView(val title: String) : View() {
|
||||
abstract val content: @Composable ColumnScope.() -> Unit
|
||||
@Composable
|
||||
override fun build() {
|
||||
TitleText(title)
|
||||
|
||||
Column(
|
||||
defaultModifier
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
||||
Spacer(Modifier.fillMaxWidth().height(8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T : View> T.init(): T = apply {
|
||||
build()
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Config
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.*
|
||||
|
||||
class BuilderView : View() {
|
||||
private val projectTypeView = ProjectTypeView()
|
||||
private val mavenInfoView = MavenInfoView()
|
||||
private val licensesView = LicensesView()
|
||||
private var saveAvailableState by mutableStateOf(false)
|
||||
|
||||
override val defaultModifier: Modifier = Modifier.fillMaxSize()
|
||||
|
||||
var config: Config
|
||||
get() = Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType)
|
||||
set(value) {
|
||||
licensesView.licenses = value.licenses
|
||||
mavenInfoView.mavenConfig = value.mavenConfig
|
||||
projectTypeView.projectType = value.type
|
||||
saveAvailableState = true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun createIcon(
|
||||
tooltip: String,
|
||||
resource: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
TooltipArea(
|
||||
tooltip = {
|
||||
Surface(
|
||||
modifier = Modifier.shadow(4.dp),
|
||||
color = MaterialTheme.colors.primarySurface,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
) {
|
||||
Text(tooltip, modifier = Modifier.padding(10.dp), color = MaterialTheme.colors.onPrimary)
|
||||
}
|
||||
}
|
||||
) {
|
||||
IconButton(onClick) {
|
||||
Image(
|
||||
painter = painterResource(resource),
|
||||
contentDescription = tooltip
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
override fun build() {
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
Column() {
|
||||
TopAppBar(
|
||||
@Composable {
|
||||
CommonText("Kotlin publication scripts builder", Modifier.clickable { println(config) })
|
||||
},
|
||||
actions = {
|
||||
createIcon("Open file", "images/open_file.svg") {
|
||||
loadConfig()?.also {
|
||||
config = it
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAvailableState) {
|
||||
createIcon("Save", "images/save_file.svg") {
|
||||
saveConfig(config)
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAvailableState) {
|
||||
createIcon("Export Gradle script", "images/export_gradle.svg") {
|
||||
exportGradle(config)
|
||||
}
|
||||
}
|
||||
|
||||
createIcon("Save as", "images/save_as.svg") {
|
||||
if (saveAs(config)) {
|
||||
saveAvailableState = true
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
projectTypeView.init()
|
||||
Divider()
|
||||
licensesView.init()
|
||||
Divider()
|
||||
mavenInfoView.init()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.CommonTextField
|
||||
|
||||
class DeveloperState(
|
||||
id: String = "",
|
||||
name: String = "",
|
||||
eMail: String = ""
|
||||
) {
|
||||
var id: String by mutableStateOf(id)
|
||||
var name: String by mutableStateOf(name)
|
||||
var eMail: String by mutableStateOf(eMail)
|
||||
|
||||
fun toDeveloper() = Developer(id, name, eMail)
|
||||
}
|
||||
|
||||
private fun Developer.toDeveloperState() = DeveloperState(id, name, eMail)
|
||||
|
||||
class DevelopersView : ListView<DeveloperState>("Developers info") {
|
||||
var developers: List<Developer>
|
||||
get() = itemsList.map { it.toDeveloper() }
|
||||
set(value) {
|
||||
itemsList.clear()
|
||||
itemsList.addAll(
|
||||
value.map { it.toDeveloperState() }
|
||||
)
|
||||
}
|
||||
|
||||
override val addItemText: String = "Add developer"
|
||||
override val removeItemText: String = "Remove developer"
|
||||
|
||||
override fun createItem(): DeveloperState = DeveloperState()
|
||||
@Composable
|
||||
override fun buildView(item: DeveloperState) {
|
||||
CommonTextField(
|
||||
item.id,
|
||||
"Developer username"
|
||||
) { item.id = it }
|
||||
CommonTextField(
|
||||
item.name,
|
||||
"Developer name"
|
||||
) { item.name = it }
|
||||
CommonTextField(
|
||||
item.eMail,
|
||||
"Developer E-Mail"
|
||||
) { item.eMail = it }
|
||||
}
|
||||
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.License
|
||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.*
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
private class LicenseState(
|
||||
id: String = "",
|
||||
title: String = "",
|
||||
url: String? = null
|
||||
) {
|
||||
var id: String by mutableStateOf(id)
|
||||
var title: String by mutableStateOf(title)
|
||||
var url: String? by mutableStateOf(url)
|
||||
|
||||
fun toLicense() = License(id, title, url)
|
||||
}
|
||||
|
||||
private fun License.toLicenseState() = LicenseState(id, title, url)
|
||||
|
||||
class LicensesView: VerticalView("Licenses") {
|
||||
private var licensesListState = mutableStateListOf<LicenseState>()
|
||||
var licenses: List<License>
|
||||
get() = licensesListState.map { it.toLicense() }
|
||||
set(value) {
|
||||
licensesListState.clear()
|
||||
licensesListState.addAll(value.map { it.toLicenseState() })
|
||||
}
|
||||
private val availableLicensesState = mutableStateListOf<License>()
|
||||
private val licensesOffersToShow = mutableStateListOf<License>()
|
||||
private var licenseSearchFilter by mutableStateOf("")
|
||||
|
||||
init {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
val client = HttpClient()
|
||||
availableLicensesState.addAll(client.getLicenses().values)
|
||||
client.close()
|
||||
}
|
||||
}
|
||||
|
||||
override val content: @Composable ColumnScope.() -> Unit = {
|
||||
CommonTextField(licenseSearchFilter, "Search filter") { filterText ->
|
||||
licenseSearchFilter = filterText
|
||||
licensesOffersToShow.clear()
|
||||
if (licenseSearchFilter.isNotEmpty()) {
|
||||
licensesOffersToShow.addAll(
|
||||
availableLicensesState.filter { filterText.all { symbol -> symbol.lowercaseChar() in it.title } }
|
||||
)
|
||||
}
|
||||
}
|
||||
Column {
|
||||
licensesOffersToShow.forEach {
|
||||
Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
|
||||
CommonText(it.title, Modifier.clickable {
|
||||
licensesListState.add(it.toLicenseState())
|
||||
licenseSearchFilter = ""
|
||||
licensesOffersToShow.clear()
|
||||
})
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
Button({ licensesListState.add(LicenseState()) }, Modifier.padding(8.dp)) {
|
||||
CommonText("Add empty license")
|
||||
}
|
||||
licensesListState.forEach { license ->
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
CommonTextField(
|
||||
license.id,
|
||||
"License ID"
|
||||
) { license.id = it }
|
||||
CommonTextField(
|
||||
license.title,
|
||||
"License title"
|
||||
) { license.title = it }
|
||||
CommonTextField(
|
||||
license.url ?: "",
|
||||
"License URL"
|
||||
) { license.url = it }
|
||||
Button({ licensesListState.remove(license) }, Modifier.padding(8.dp)) {
|
||||
CommonText("Remove")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.CommonText
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.VerticalView
|
||||
|
||||
abstract class ListView<T>(title: String) : VerticalView(title) {
|
||||
protected val itemsList = mutableStateListOf<T>()
|
||||
|
||||
protected open val addItemText: String = "Add"
|
||||
protected open val removeItemText: String = "Remove"
|
||||
|
||||
protected abstract fun createItem(): T
|
||||
@Composable
|
||||
protected abstract fun buildView(item: T)
|
||||
|
||||
override val content: @Composable ColumnScope.() -> Unit = {
|
||||
Button({ itemsList.add(createItem()) }) {
|
||||
CommonText(addItemText)
|
||||
}
|
||||
itemsList.forEach { item ->
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
buildView(item)
|
||||
Button({ itemsList.remove(item) }, Modifier.padding(8.dp)) {
|
||||
CommonText(removeItemText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.VerticalAlignmentLine
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.*
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.*
|
||||
|
||||
class MavenInfoView : VerticalView("Project information") {
|
||||
private var projectNameProperty by mutableStateOf("")
|
||||
private var projectDescriptionProperty by mutableStateOf("")
|
||||
private var projectUrlProperty by mutableStateOf("")
|
||||
private var projectVcsUrlProperty by mutableStateOf("")
|
||||
private var gpgSignProperty by mutableStateOf<GpgSigning>(GpgSigning.Disabled)
|
||||
private var publishToMavenCentralProperty by mutableStateOf(false)
|
||||
private val developersView = DevelopersView()
|
||||
private val repositoriesView = RepositoriesView()
|
||||
|
||||
var mavenConfig: MavenConfig
|
||||
get() = MavenConfig(
|
||||
projectNameProperty.ifBlank { defaultProjectName },
|
||||
projectDescriptionProperty.ifBlank { defaultProjectDescription },
|
||||
projectUrlProperty,
|
||||
projectVcsUrlProperty,
|
||||
developersView.developers,
|
||||
repositoriesView.repositories + if (publishToMavenCentralProperty) {
|
||||
listOf(SonatypeRepository)
|
||||
} else {
|
||||
emptyList()
|
||||
},
|
||||
gpgSignProperty
|
||||
)
|
||||
set(value) {
|
||||
projectNameProperty = value.name
|
||||
projectDescriptionProperty = value.description
|
||||
projectUrlProperty = value.url
|
||||
projectVcsUrlProperty = value.vcsUrl
|
||||
gpgSignProperty = if (value.includeGpgSigning) {
|
||||
GpgSigning.Enabled
|
||||
} else {
|
||||
value.gpgSigning
|
||||
}
|
||||
publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository }
|
||||
developersView.developers = value.developers
|
||||
repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository }
|
||||
// developersView.developers = value.developers
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun addGpgSigningButton(gpgSigning: GpgSigning) {
|
||||
if (gpgSignProperty == gpgSigning) {
|
||||
Button({}, Modifier.padding(8.dp)) {
|
||||
Text(gpgSigning.name)
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(
|
||||
{
|
||||
gpgSignProperty = gpgSigning
|
||||
},
|
||||
Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(gpgSigning.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val content: @Composable ColumnScope.() -> Unit = {
|
||||
CommonTextField(
|
||||
projectNameProperty,
|
||||
"Public project name"
|
||||
) { projectNameProperty = it }
|
||||
CommonTextField(
|
||||
projectDescriptionProperty,
|
||||
"Public project description"
|
||||
) { projectDescriptionProperty = it }
|
||||
CommonTextField(
|
||||
projectUrlProperty,
|
||||
"Public project URL"
|
||||
) { projectUrlProperty = it }
|
||||
CommonTextField(
|
||||
projectVcsUrlProperty,
|
||||
"Public project VCS URL (with .git)"
|
||||
) { projectVcsUrlProperty = it }
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Gpg Signing: ")
|
||||
addGpgSigningButton(GpgSigning.Disabled)
|
||||
addGpgSigningButton(GpgSigning.Optional)
|
||||
addGpgSigningButton(GpgSigning.Enabled)
|
||||
}
|
||||
|
||||
SwitchWithLabel(
|
||||
"Include publication to MavenCentral",
|
||||
publishToMavenCentralProperty,
|
||||
placeSwitchAtTheStart = true
|
||||
) { publishToMavenCentralProperty = it }
|
||||
developersView.init()
|
||||
repositoriesView.init()
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.kmppscriptbuilder.core.models.*
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.VerticalView
|
||||
|
||||
class ProjectTypeView : VerticalView("Project type") {
|
||||
var projectType by mutableStateOf<ProjectType>(MultiplatformProjectType)
|
||||
|
||||
@Composable
|
||||
private fun addProjectTypeButton(newProjectType: ProjectType) {
|
||||
if (projectType == newProjectType) {
|
||||
Button({}, Modifier.padding(8.dp)) {
|
||||
Text(newProjectType.name)
|
||||
}
|
||||
} else {
|
||||
OutlinedButton(
|
||||
{
|
||||
projectType = newProjectType
|
||||
},
|
||||
Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(newProjectType.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val content: @Composable ColumnScope.() -> Unit = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
addProjectTypeButton(MultiplatformProjectType)
|
||||
addProjectTypeButton(JVMProjectType)
|
||||
addProjectTypeButton(JSProjectType)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.desktop.views
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
|
||||
import dev.inmo.kmppscriptbuilder.desktop.utils.CommonTextField
|
||||
|
||||
class RepositoryState(
|
||||
name: String = "",
|
||||
url: String = ""
|
||||
) {
|
||||
var name: String by mutableStateOf(name)
|
||||
var url: String by mutableStateOf(url)
|
||||
|
||||
fun toRepository() = MavenPublishingRepository(name, url)
|
||||
}
|
||||
|
||||
private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url)
|
||||
|
||||
class RepositoriesView : ListView<RepositoryState>("Repositories info") {
|
||||
var repositories: List<MavenPublishingRepository>
|
||||
get() = itemsList.map { it.toRepository() }
|
||||
set(value) {
|
||||
itemsList.clear()
|
||||
itemsList.addAll(
|
||||
value.map { it.toRepositoryState() }
|
||||
)
|
||||
}
|
||||
|
||||
override val addItemText: String = "Add repository"
|
||||
override val removeItemText: String = "Remove repository"
|
||||
|
||||
override fun createItem(): RepositoryState = RepositoryState()
|
||||
@Composable
|
||||
override fun buildView(item: RepositoryState) {
|
||||
CommonTextField(
|
||||
item.name,
|
||||
"Repository name"
|
||||
) { item.name = it }
|
||||
CommonTextField(
|
||||
item.url,
|
||||
"Repository url"
|
||||
) { item.url = it }
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ kt-coroutines = "1.6.4"
|
||||
jb-compose = "1.2.1"
|
||||
jb-dokka = "1.7.20"
|
||||
microutils = "0.14.2"
|
||||
kjsuikit = "0.4.1"
|
||||
|
||||
ktor = "2.1.3"
|
||||
|
||||
@ -22,10 +23,13 @@ kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", vers
|
||||
|
||||
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
|
||||
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
|
||||
|
||||
microutils-common = { module = "dev.inmo:micro_utils.common", version.ref = "microutils" }
|
||||
microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", version.ref = "microutils" }
|
||||
|
||||
jsuikit = { module = "dev.inmo:kjsuikit", version.ref = "kjsuikit" }
|
||||
|
||||
|
||||
kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" }
|
||||
kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" }
|
||||
|
@ -9,8 +9,8 @@ rootProject.name = 'kmppscriptbuilder'
|
||||
|
||||
String[] includes = [
|
||||
":core",
|
||||
":desktop",
|
||||
":web"
|
||||
// ":desktop",
|
||||
// ":web"
|
||||
]
|
||||
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
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(
|
||||
"application/*;charset=utf-8"
|
||||
))
|
||||
val url = URL.createObjectURL(blob)
|
||||
a.href = url
|
||||
a.download = filename
|
||||
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
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
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")
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.web.utils
|
||||
|
||||
import kotlinx.browser.document
|
||||
|
||||
inline fun <R> keepScrolling(crossinline block: () -> R): R = document.body ?.let {
|
||||
val (x, y) = (it.scrollLeft to it.scrollTop)
|
||||
return block().also { _ ->
|
||||
it.scrollTo(x, y)
|
||||
}
|
||||
} ?: block()
|
@ -1,23 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.web.views
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
|
||||
import org.w3c.dom.*
|
||||
|
||||
class DevelopersView(rootElement: HTMLElement) : MutableListView<Developer>(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<Developer>
|
||||
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
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
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<License>(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<License>(rootElement, useSimpleDiffStrategy = true) {
|
||||
private var licensesTemplates: List<License> = emptyList()
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
licensesTemplates = client.getLicenses().values.toList()
|
||||
changeActor.send(Unit) // update list of searches
|
||||
}
|
||||
}
|
||||
|
||||
private val changeActor: SendChannel<Unit> = scope.run {
|
||||
val onChangeActor = Channel<Unit>(Channel.CONFLATED)
|
||||
onChangeActor.consumeAsFlow().subscribeSafelyWithoutExceptions(scope) {
|
||||
val lowercased = searchString
|
||||
data = if (lowercased.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
licensesTemplates.filter {
|
||||
val lowercasedTitle = it.title.lowercase()
|
||||
lowercased.all { it in lowercasedTitle }
|
||||
}
|
||||
}
|
||||
}
|
||||
onChangeActor
|
||||
}
|
||||
private val searchElement = rootElement.createTextField("Quick add", "Type some license name part to find it").apply {
|
||||
oninput = {
|
||||
changeActor.trySend(Unit)
|
||||
false
|
||||
}
|
||||
}
|
||||
private var searchString: String
|
||||
get() = searchElement.value.lowercase()
|
||||
set(value) {
|
||||
searchElement.value = value
|
||||
}
|
||||
|
||||
override fun HTMLElement.placeElement(value: License) {
|
||||
createCommonButton(value.title).onclick = {
|
||||
searchString = ""
|
||||
licensesView.licenses += value
|
||||
changeActor.trySend(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<License>
|
||||
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 ?: ""
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
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<T>(
|
||||
protected val rootElement: HTMLElement,
|
||||
useSimpleDiffStrategy: Boolean = false
|
||||
) : View {
|
||||
protected val elements = mutableListOf<HTMLElement>()
|
||||
private val diffHandling: (old: List<T>, new: List<T>) -> 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<T> = 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
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
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
|
||||
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 disableGpgSigningElement = document.getElementById("disableGpgSigning") as HTMLElement
|
||||
private val optionalGpgSigningElement = document.getElementById("optionalGpgSigning") as HTMLElement
|
||||
private val enableGpgSigningElement = document.getElementById("enableGpgSigning") as HTMLElement
|
||||
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)
|
||||
|
||||
private var gpgSignMode: GpgSigning = GpgSigning.Disabled
|
||||
set(value) {
|
||||
field = value
|
||||
when (value) {
|
||||
GpgSigning.Enabled -> {
|
||||
enableGpgSigningElement.ukActive = true
|
||||
disableGpgSigningElement.ukActive = false
|
||||
optionalGpgSigningElement.ukActive = false
|
||||
}
|
||||
GpgSigning.Optional -> {
|
||||
enableGpgSigningElement.ukActive = false
|
||||
disableGpgSigningElement.ukActive = false
|
||||
optionalGpgSigningElement.ukActive = true
|
||||
}
|
||||
GpgSigning.Disabled -> {
|
||||
enableGpgSigningElement.ukActive = false
|
||||
disableGpgSigningElement.ukActive = true
|
||||
optionalGpgSigningElement.ukActive = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mavenConfig: MavenConfig
|
||||
get() = MavenConfig(
|
||||
nameElement.value.ifBlank { defaultProjectName },
|
||||
descriptionElement.value.ifBlank { defaultProjectDescription },
|
||||
urlElement.value,
|
||||
vcsUrlElement.value,
|
||||
developersView.developers,
|
||||
repositoriesView.repositories + if (includeMavenCentralElement.checked) {
|
||||
listOf(SonatypeRepository)
|
||||
} else {
|
||||
emptyList()
|
||||
},
|
||||
when {
|
||||
optionalGpgSigningElement.ukActive -> GpgSigning.Optional
|
||||
enableGpgSigningElement.ukActive -> GpgSigning.Enabled
|
||||
else -> GpgSigning.Disabled
|
||||
}
|
||||
)
|
||||
set(value) {
|
||||
nameElement.value = value.name
|
||||
descriptionElement.value = value.description
|
||||
urlElement.value = value.url
|
||||
vcsUrlElement.value = value.vcsUrl
|
||||
gpgSignMode = if (value.includeGpgSigning) {
|
||||
GpgSigning.Enabled
|
||||
} else {
|
||||
value.gpgSigning
|
||||
}
|
||||
developersView.developers = value.developers
|
||||
val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository }
|
||||
includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size
|
||||
repositoriesView.repositories = reposWithoutSonatype
|
||||
}
|
||||
|
||||
init {
|
||||
enableGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Enabled; Unit }
|
||||
disableGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Disabled; Unit }
|
||||
optionalGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Optional; Unit }
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.web.views
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.web.utils.keepScrolling
|
||||
import org.w3c.dom.HTMLElement
|
||||
|
||||
abstract class MutableListView<T>(
|
||||
rootElement: HTMLElement,
|
||||
addButtonText: String = "Add",
|
||||
private val removeButtonText: String = "Remove"
|
||||
) : ListView<T>(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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
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
|
||||
private val jsProjectTypeElement = document.getElementById("jsProjectType") as HTMLElement
|
||||
|
||||
var projectType: ProjectType
|
||||
get() = when {
|
||||
jvmProjectTypeElement.ukActive -> JVMProjectType
|
||||
jsProjectTypeElement.ukActive -> JSProjectType
|
||||
else -> MultiplatformProjectType
|
||||
}
|
||||
set(value) {
|
||||
mppProjectTypeElement.ukActive = value == MultiplatformProjectType
|
||||
jvmProjectTypeElement.ukActive = value == JVMProjectType
|
||||
jsProjectTypeElement.ukActive = value == JSProjectType
|
||||
}
|
||||
|
||||
init {
|
||||
mppProjectTypeElement.onclick = {
|
||||
projectType = MultiplatformProjectType
|
||||
Unit
|
||||
}
|
||||
jvmProjectTypeElement.onclick = {
|
||||
projectType = JVMProjectType
|
||||
Unit
|
||||
}
|
||||
jsProjectTypeElement.onclick = {
|
||||
projectType = JSProjectType
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.web.views
|
||||
|
||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
|
||||
import org.w3c.dom.*
|
||||
|
||||
class RepositoriesView(rootElement: HTMLElement) : MutableListView<MavenPublishingRepository>(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<MavenPublishingRepository>
|
||||
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.url
|
||||
}
|
||||
|
||||
override fun HTMLElement.updateElement(from: MavenPublishingRepository, to: MavenPublishingRepository) {
|
||||
nameElement.value = to.name
|
||||
urlElement.value = to.url
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package dev.inmo.kmppscriptbuilder.web.views
|
||||
|
||||
interface View
|
@ -1,35 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kotlin Publication Scripts Builder</title>
|
||||
<!-- UIkit CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/css/uikit.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="uk-navbar-container" uk-navbar>
|
||||
<div class="uk-navbar-left">
|
||||
<div class="uk-padding-small uk-text-lead">Kotlin Publication Scripts Builder</div>
|
||||
<div class="uk-padding-small"><a href="https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder"><img src="https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic"/></a></div>
|
||||
</div>
|
||||
<div class="uk-navbar-right">
|
||||
<ul class="uk-navbar-nav">
|
||||
<li uk-tooltip="title: Open config" id="openConfig"><a href="#"><span uk-icon="icon: pull"></span></a></li><!--Open file-->
|
||||
<li uk-tooltip="title: Save config" id="saveConfig"><a href="#"><span uk-icon="icon: push"></span></a></li><!--Save file-->
|
||||
<li uk-tooltip="title: Export script" id="exportScript"><a href="#"><span uk-icon="icon: upload"></span></a></li><!--Save file-->
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<form class="uk-padding-small">
|
||||
<fieldset class="uk-fieldset">
|
||||
<legend class="uk-legend">Project type</legend>
|
||||
<div class="uk-padding-small">
|
||||
<ul class="uk-subnav uk-subnav-pill">
|
||||
<li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>
|
||||
<li id="jvmProjectType"><a href="#">JVM</a></li>
|
||||
<li id="jsProjectType"><a href="#">JS</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<legend class="uk-legend">Licenses</legend>
|
||||
<div id="licensesListDiv" class="uk-padding-small"></div>
|
||||
|
||||
<legend class="uk-legend">Project information</legend>
|
||||
|
||||
<div class="uk-padding-small">
|
||||
<div class="uk-margin uk-width-1-1">
|
||||
<label class="uk-form-label" for="projectNameInput">Public project name</label>
|
||||
<input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">
|
||||
</div>
|
||||
<div class="uk-margin uk-width-1-1">
|
||||
<label class="uk-form-label" for="projectDescriptionInput">Public project description</label>
|
||||
<input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">
|
||||
</div>
|
||||
<div class="uk-margin uk-width-1-1">
|
||||
<label class="uk-form-label" for="projectUrlInput">Public project URL</label>
|
||||
<input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme">
|
||||
</div>
|
||||
<div class="uk-margin uk-width-1-1">
|
||||
<label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label>
|
||||
<input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file">
|
||||
</div>
|
||||
|
||||
<div class="uk-margin">
|
||||
<label>GPG Signing</label>
|
||||
|
||||
<div class="uk-padding-small">
|
||||
<ul class="uk-subnav uk-subnav-pill">
|
||||
<li id="disableGpgSigning" class="uk-active" uk-tooltip="title: Signing will not be added"><a href="#">Disabled</a></li>
|
||||
<li id="optionalGpgSigning" uk-tooltip="title: Signing will be added, but disabled in case of absence 'signatory.keyId'"><a href="#">Optional</a></li>
|
||||
<li id="enableGpgSigning" uk-tooltip="title: Signing will be always enabled"><a href="#">Enabled</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-margin">
|
||||
<label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<legend class="uk-legend">Developers info</legend>
|
||||
<div id="developersListDiv" class="uk-padding-small"></div>
|
||||
|
||||
<legend class="uk-legend">Repositories info</legend>
|
||||
<div id="repositoriesListDiv" class="uk-padding-small"></div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<!-- UIkit JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit-icons.min.js"></script>
|
||||
<!-- Internal JS -->
|
||||
<script src="kmppscriptbuilder.web.js"></script>
|
||||
</body>
|
||||
</html>
|