More or less working muon monitor
This commit is contained in:
parent
72ead21ef0
commit
659b9c3525
@ -1,50 +0,0 @@
|
|||||||
@file:JsModule("react-file-drop")
|
|
||||||
@file:JsNonModule
|
|
||||||
|
|
||||||
package drop
|
|
||||||
|
|
||||||
import org.w3c.dom.DragEvent
|
|
||||||
import org.w3c.files.FileList
|
|
||||||
import react.Component
|
|
||||||
import react.Props
|
|
||||||
import react.State
|
|
||||||
|
|
||||||
sealed external class DropEffects {
|
|
||||||
@JsName("copy")
|
|
||||||
object Copy : DropEffects
|
|
||||||
|
|
||||||
@JsName("move")
|
|
||||||
object Move : DropEffects
|
|
||||||
|
|
||||||
@JsName("link")
|
|
||||||
object Link : DropEffects
|
|
||||||
|
|
||||||
@JsName("none")
|
|
||||||
object None : DropEffects
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface FileDropProps : Props {
|
|
||||||
var className: String?
|
|
||||||
var targetClassName: String?
|
|
||||||
var draggingOverFrameClassName: String?
|
|
||||||
var draggingOverTargetClassName: String?
|
|
||||||
|
|
||||||
// var frame?: Exclude<HTMLElementTagNameMap[keyof HTMLElementTagNameMap], HTMLElement> | HTMLDocument;
|
|
||||||
var onFrameDragEnter: ((event: DragEvent) -> Unit)?
|
|
||||||
var onFrameDragLeave: ((event: DragEvent) -> Unit)?
|
|
||||||
var onFrameDrop: ((event: DragEvent) -> Unit)?
|
|
||||||
|
|
||||||
// var onDragOver: ReactDragEventHandler<HTMLDivElement>?
|
|
||||||
// var onDragLeave: ReactDragEventHandler<HTMLDivElement>?
|
|
||||||
var onDrop: ((files: FileList?, event: dynamic) -> Unit)?//event:DragEvent<HTMLDivElement>)
|
|
||||||
var dropEffect: DropEffects?
|
|
||||||
}
|
|
||||||
|
|
||||||
external interface FileDropState : State {
|
|
||||||
var draggingOverFrame: Boolean
|
|
||||||
var draggingOverTarget: Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
external class FileDrop : Component<FileDropProps, FileDropState> {
|
|
||||||
override fun render(): dynamic
|
|
||||||
}
|
|
@ -0,0 +1,87 @@
|
|||||||
|
@file:OptIn(ExperimentalComposeWebApi::class)
|
||||||
|
|
||||||
|
package space.kscience.visionforge.gdml.demo
|
||||||
|
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||||
|
import org.jetbrains.compose.web.attributes.InputType
|
||||||
|
import org.jetbrains.compose.web.attributes.name
|
||||||
|
import org.jetbrains.compose.web.css.*
|
||||||
|
import org.jetbrains.compose.web.dom.Div
|
||||||
|
import org.jetbrains.compose.web.dom.I
|
||||||
|
import org.jetbrains.compose.web.dom.Input
|
||||||
|
import org.jetbrains.compose.web.dom.Text
|
||||||
|
import org.w3c.files.FileList
|
||||||
|
|
||||||
|
|
||||||
|
//https://codepen.io/zahedkamal87/pen/PobNNwE
|
||||||
|
@Composable
|
||||||
|
fun FileDrop(
|
||||||
|
title: String = "Drop files or Click here to select files to upload.",
|
||||||
|
onFileDrop: (FileList) -> Unit,
|
||||||
|
) {
|
||||||
|
var dragOver by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Div({
|
||||||
|
id("dropzone")
|
||||||
|
style {
|
||||||
|
border(
|
||||||
|
width = 0.2.cssRem,
|
||||||
|
style = LineStyle.Dashed,
|
||||||
|
color = Color("#6583fe")
|
||||||
|
)
|
||||||
|
padding(2.cssRem)
|
||||||
|
borderRadius(0.25.cssRem)
|
||||||
|
backgroundColor(Color("#fff"))
|
||||||
|
textAlign("center")
|
||||||
|
fontSize(1.5.cssRem)
|
||||||
|
transitions {
|
||||||
|
all {
|
||||||
|
delay(0.25.s)
|
||||||
|
timingFunction(AnimationTimingFunction.EaseInOut)
|
||||||
|
properties("background-color")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor("pointer")
|
||||||
|
}
|
||||||
|
listOf("drag", "dragstart", "dragend", "dragenter").forEach {
|
||||||
|
addEventListener(it) { event ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onDragOver { event ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
dragOver = true
|
||||||
|
}
|
||||||
|
onDragLeave { event ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
dragOver = false
|
||||||
|
}
|
||||||
|
onDrop { event ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
dragOver = false
|
||||||
|
event.dataTransfer?.files?.let {
|
||||||
|
onFileDrop(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
|
||||||
|
I({ classes("bi", "bi-cloud-upload", "dropzone-icon") })
|
||||||
|
Text(title)
|
||||||
|
Input(type = InputType.File, attrs = {
|
||||||
|
style {
|
||||||
|
display(DisplayStyle.None)
|
||||||
|
}
|
||||||
|
classes("dropzone-input")
|
||||||
|
name("files")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//dropzone.addEventListener("click", function(e) {
|
||||||
|
// dropzone_input.click();
|
||||||
|
//});
|
@ -69,8 +69,8 @@ fun GDMLApp(solids: Solids, initialVision: Solid?, selected: Name? = null) {
|
|||||||
H2 {
|
H2 {
|
||||||
Text("Drag and drop .gdml or .json VisionForge files here")
|
Text("Drag and drop .gdml or .json VisionForge files here")
|
||||||
}
|
}
|
||||||
fileDrop("(drag file here)") { files ->
|
FileDrop("(drag file here)") { files ->
|
||||||
val file = files?.get(0)
|
val file = files[0]
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
readFileAsync(file)
|
readFileAsync(file)
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package space.kscience.visionforge.gdml.demo
|
|
||||||
|
|
||||||
import drop.FileDrop
|
|
||||||
import kotlinx.css.*
|
|
||||||
import org.w3c.files.FileList
|
|
||||||
import react.RBuilder
|
|
||||||
import styled.css
|
|
||||||
import styled.styledDiv
|
|
||||||
|
|
||||||
//TODO move styles to inline
|
|
||||||
|
|
||||||
fun RBuilder.fileDrop(title: String, action: (files: FileList?) -> Unit) {
|
|
||||||
styledDiv {
|
|
||||||
css {
|
|
||||||
border = Border(style = BorderStyle.dashed, width = 1.px, color = Color.orange)
|
|
||||||
flexGrow = 0.0
|
|
||||||
alignContent = Align.center
|
|
||||||
}
|
|
||||||
|
|
||||||
child(FileDrop::class) {
|
|
||||||
attrs {
|
|
||||||
onDrop = { files, _ ->
|
|
||||||
console.info("loaded $files")
|
|
||||||
action(files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3
demo/gdml/webpack.config.d/01.ring.js
vendored
3
demo/gdml/webpack.config.d/01.ring.js
vendored
@ -1,3 +0,0 @@
|
|||||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
|
||||||
|
|
||||||
config.module.rules.push(...ringConfig.module.rules)
|
|
@ -1,3 +0,0 @@
|
|||||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
|
||||||
|
|
||||||
config.module.rules.push(...ringConfig.module.rules)
|
|
@ -1,5 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
|
alias(spclibs.plugins.compose)
|
||||||
application
|
application
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,11 +15,22 @@ kscience {
|
|||||||
fullStack(
|
fullStack(
|
||||||
"muon-monitor.js",
|
"muon-monitor.js",
|
||||||
jvmConfig = { withJava() },
|
jvmConfig = { withJava() },
|
||||||
jsConfig = { useCommonJs() }
|
// jsConfig = { useCommonJs() },
|
||||||
|
browserConfig = {
|
||||||
|
webpackTask{
|
||||||
|
cssSupport{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
scssSupport{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
implementation(projects.visionforgeSolid)
|
implementation(projects.visionforgeSolid)
|
||||||
|
implementation(projects.visionforgeComposeHtml)
|
||||||
}
|
}
|
||||||
jvmMain {
|
jvmMain {
|
||||||
implementation("org.apache.commons:commons-math3:3.6.1")
|
implementation("org.apache.commons:commons-math3:3.6.1")
|
||||||
|
@ -4,12 +4,13 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import app.softwork.bootstrapcompose.Button
|
import app.softwork.bootstrapcompose.Button
|
||||||
|
import app.softwork.bootstrapcompose.ButtonGroup
|
||||||
|
import app.softwork.bootstrapcompose.Container
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
import kotlinx.coroutines.await
|
import kotlinx.coroutines.await
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.jetbrains.compose.web.css.*
|
import org.jetbrains.compose.web.css.*
|
||||||
import org.jetbrains.compose.web.dom.Div
|
|
||||||
import org.jetbrains.compose.web.dom.P
|
import org.jetbrains.compose.web.dom.P
|
||||||
import org.jetbrains.compose.web.dom.Span
|
import org.jetbrains.compose.web.dom.Span
|
||||||
import org.jetbrains.compose.web.dom.Text
|
import org.jetbrains.compose.web.dom.Text
|
||||||
@ -17,8 +18,6 @@ import org.w3c.fetch.RequestInit
|
|||||||
import space.kscience.dataforge.meta.invoke
|
import space.kscience.dataforge.meta.invoke
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.Colors
|
import space.kscience.visionforge.Colors
|
||||||
import space.kscience.visionforge.compose.FlexColumn
|
|
||||||
import space.kscience.visionforge.compose.FlexRow
|
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.solid.ambientLight
|
import space.kscience.visionforge.solid.ambientLight
|
||||||
import space.kscience.visionforge.solid.edges
|
import space.kscience.visionforge.solid.edges
|
||||||
@ -51,16 +50,21 @@ fun MMApp(solids: Solids, model: Model, selected: Name? = null) {
|
|||||||
|
|
||||||
val events = remember { mutableStateListOf<Event>() }
|
val events = remember { mutableStateListOf<Event>() }
|
||||||
|
|
||||||
Div({
|
Container(fluid = true,
|
||||||
|
attrs = {
|
||||||
style {
|
style {
|
||||||
height(100.vh - 12.pt)
|
height(100.vh - 12.pt)
|
||||||
}
|
}
|
||||||
}) {
|
}
|
||||||
ThreeView(solids, root, selected, mmOptions) {
|
) {
|
||||||
|
ThreeView(
|
||||||
|
solids = solids,
|
||||||
|
solid = root,
|
||||||
|
initialSelected = selected,
|
||||||
|
options = mmOptions,
|
||||||
|
sidebarTabs = {
|
||||||
Tab("Events") {
|
Tab("Events") {
|
||||||
|
ButtonGroup {
|
||||||
FlexColumn {
|
|
||||||
FlexRow {
|
|
||||||
Button("Next") {
|
Button("Next") {
|
||||||
solids.context.launch {
|
solids.context.launch {
|
||||||
val event = window.fetch(
|
val event = window.fetch(
|
||||||
@ -84,7 +88,7 @@ fun MMApp(solids: Solids, model: Model, selected: Name? = null) {
|
|||||||
model.reset()
|
model.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
events.forEach { event ->
|
events.forEach { event ->
|
||||||
P {
|
P {
|
||||||
Span {
|
Span {
|
||||||
@ -102,5 +106,6 @@ fun MMApp(solids: Solids, model: Model, selected: Name? = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,13 @@
|
|||||||
package ru.mipt.npm.muon.monitor
|
package ru.mipt.npm.muon.monitor
|
||||||
|
|
||||||
|
import org.jetbrains.compose.web.css.Style
|
||||||
import org.jetbrains.compose.web.renderComposable
|
import org.jetbrains.compose.web.renderComposable
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
import space.kscience.visionforge.Application
|
import space.kscience.visionforge.Application
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
|
import space.kscience.visionforge.compose.VisionForgeStyles
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||||
import space.kscience.visionforge.startApplication
|
import space.kscience.visionforge.startApplication
|
||||||
@ -22,8 +24,8 @@ private class MMDemoApp : Application {
|
|||||||
|
|
||||||
val model = Model(visionManager)
|
val model = Model(visionManager)
|
||||||
|
|
||||||
val element = document.getElementById("app") ?: error("Element with id 'app' not found on page")
|
renderComposable("app") {
|
||||||
renderComposable(element) {
|
Style(VisionForgeStyles)
|
||||||
MMApp(context.request(Solids), model)
|
MMApp(context.request(Solids), model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
|
||||||
|
|
||||||
config.module.rules.push(...ringConfig.module.rules)
|
|
@ -16,6 +16,12 @@ kotlin {
|
|||||||
js(IR) {
|
js(IR) {
|
||||||
browser {
|
browser {
|
||||||
webpackTask {
|
webpackTask {
|
||||||
|
cssSupport{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
scssSupport{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
mainOutputFileName.set("js/visionforge-playground.js")
|
mainOutputFileName.set("js/visionforge-playground.js")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
demo/playground/webpack.config.d/01.ring.js
vendored
23
demo/playground/webpack.config.d/01.ring.js
vendored
@ -1,23 +0,0 @@
|
|||||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
config.module.rules.push(...ringConfig.module.rules)
|
|
||||||
|
|
||||||
config.module.rules.push(
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: [
|
|
||||||
path.resolve(__dirname, "../../node_modules/@jetbrains/ring-ui")
|
|
||||||
],
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader',
|
|
||||||
options: {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
@ -41,11 +41,11 @@ dependencyResolutionManagement {
|
|||||||
|
|
||||||
include(
|
include(
|
||||||
// ":ui",
|
// ":ui",
|
||||||
":ui:react",
|
// ":ui:react",
|
||||||
":ui:ring",
|
// ":ui:ring",
|
||||||
// ":ui:material",
|
// ":ui:material",
|
||||||
":ui:bootstrap",
|
// ":ui:bootstrap",
|
||||||
":visionforge-compose",
|
":visionforge-compose-html",
|
||||||
":visionforge-core",
|
":visionforge-core",
|
||||||
":visionforge-solid",
|
":visionforge-solid",
|
||||||
// ":visionforge-fx",
|
// ":visionforge-fx",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose)
|
||||||
@ -16,12 +15,12 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.visionforgeCore)
|
api(projects.visionforgeCore)
|
||||||
|
api(compose.runtime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val jvmMain by getting {
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(compose.runtime)
|
|
||||||
api(compose.foundation)
|
api(compose.foundation)
|
||||||
api(compose.material)
|
api(compose.material)
|
||||||
api(compose.preview)
|
api(compose.preview)
|
@ -0,0 +1,88 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import app.softwork.bootstrapcompose.Card
|
||||||
|
import app.softwork.bootstrapcompose.NavbarLink
|
||||||
|
import app.softwork.bootstrapcompose.Styling
|
||||||
|
import org.jetbrains.compose.web.dom.*
|
||||||
|
import org.w3c.dom.HTMLAnchorElement
|
||||||
|
import org.w3c.dom.HTMLDivElement
|
||||||
|
|
||||||
|
|
||||||
|
public class ComposeTab(
|
||||||
|
public val key: String,
|
||||||
|
public val title: ContentBuilder<HTMLAnchorElement>,
|
||||||
|
public val disabled: Boolean,
|
||||||
|
public val content: ContentBuilder<HTMLDivElement>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
public fun Tabs(
|
||||||
|
tabs: List<ComposeTab>,
|
||||||
|
activeKey: String,
|
||||||
|
styling: (Styling.() -> Unit)? = null,
|
||||||
|
attrs: AttrBuilderContext<HTMLDivElement>? = null,
|
||||||
|
) {
|
||||||
|
var active by remember(activeKey) { mutableStateOf(activeKey) }
|
||||||
|
|
||||||
|
val activeTab by derivedStateOf { tabs.find { it.key == active } }
|
||||||
|
|
||||||
|
Card(
|
||||||
|
styling,
|
||||||
|
attrs,
|
||||||
|
header = {
|
||||||
|
Ul({ classes("nav", "nav-tabs", "card-header-tabs") }) {
|
||||||
|
tabs.forEach { tab ->
|
||||||
|
Li({
|
||||||
|
classes("nav-item")
|
||||||
|
}) {
|
||||||
|
NavbarLink(
|
||||||
|
active = active == tab.key,
|
||||||
|
disabled = tab.disabled,
|
||||||
|
attrs = {
|
||||||
|
onClick { event ->
|
||||||
|
event.preventDefault()
|
||||||
|
active = tab.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
tab.title.invoke(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
activeTab?.content?.invoke(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TabsBuilder {
|
||||||
|
internal val tabs: MutableList<ComposeTab> = mutableListOf()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
public fun Tab(
|
||||||
|
key: String,
|
||||||
|
label: ContentBuilder<HTMLAnchorElement> = { Text(key) },
|
||||||
|
disabled: Boolean = false,
|
||||||
|
content: ContentBuilder<HTMLDivElement>,
|
||||||
|
) {
|
||||||
|
tabs.add(ComposeTab(key, label, disabled, content))
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun addTab(tab: ComposeTab) {
|
||||||
|
tabs.add(tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
public fun Tabs(
|
||||||
|
activeKey: String? = null,
|
||||||
|
styling: (Styling.() -> Unit)? = null,
|
||||||
|
attrs: AttrBuilderContext<HTMLDivElement>? = null,
|
||||||
|
builder: @Composable TabsBuilder.() -> Unit,
|
||||||
|
) {
|
||||||
|
val result = TabsBuilder().apply { builder() }
|
||||||
|
|
||||||
|
Tabs(result.tabs, activeKey ?: result.tabs.firstOrNull()?.key ?: "", styling, attrs)
|
||||||
|
}
|
@ -5,7 +5,7 @@ import org.jetbrains.compose.web.css.*
|
|||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeWebApi::class)
|
@OptIn(ExperimentalComposeWebApi::class)
|
||||||
public object TreeStyles : StyleSheet() {
|
public object TreeStyles : StyleSheet(VisionForgeStyles) {
|
||||||
/**
|
/**
|
||||||
* Remove default bullets
|
* Remove default bullets
|
||||||
*/
|
*/
|
||||||
@ -46,13 +46,11 @@ public object TreeStyles : StyleSheet() {
|
|||||||
public val treeItem: String by style {
|
public val treeItem: String by style {
|
||||||
alignItems(AlignItems.Center)
|
alignItems(AlignItems.Center)
|
||||||
paddingLeft(10.px)
|
paddingLeft(10.px)
|
||||||
border {
|
property("border-left", CSSBorder().apply{
|
||||||
left {
|
|
||||||
width(1.px)
|
width(1.px)
|
||||||
color(Color.lightgray)
|
color(Color.lightgray)
|
||||||
style = LineStyle.Dashed
|
style = LineStyle.Dashed
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public val treeLabel: String by style {
|
public val treeLabel: String by style {
|
@ -0,0 +1,7 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import org.jetbrains.compose.web.css.StyleSheet
|
||||||
|
|
||||||
|
public object VisionForgeStyles: StyleSheet() {
|
||||||
|
|
||||||
|
}
|
@ -1,102 +0,0 @@
|
|||||||
package space.kscience.visionforge.compose
|
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
import org.jetbrains.compose.web.dom.*
|
|
||||||
import org.w3c.dom.HTMLDivElement
|
|
||||||
import org.w3c.dom.HTMLLIElement
|
|
||||||
|
|
||||||
|
|
||||||
public class ComposeTab(
|
|
||||||
public val key: String,
|
|
||||||
public val title: String,
|
|
||||||
public val content: ContentBuilder<HTMLDivElement>,
|
|
||||||
public val disabled: Boolean,
|
|
||||||
public val titleExt: ContentBuilder<HTMLLIElement>,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Tabs(tabs: List<ComposeTab>, activeKey: String) {
|
|
||||||
var active by remember(activeKey) { mutableStateOf(activeKey) }
|
|
||||||
|
|
||||||
Div({ classes("card", "text-center") }) {
|
|
||||||
Div({ classes("card-header") }) {
|
|
||||||
|
|
||||||
Ul({ classes("nav", "nav-tabs", "card-header-tabs") }) {
|
|
||||||
tabs.forEach { tab ->
|
|
||||||
Li({
|
|
||||||
classes("nav-item")
|
|
||||||
}) {
|
|
||||||
A(attrs = {
|
|
||||||
classes("nav-link")
|
|
||||||
if (active == tab.key) {
|
|
||||||
classes("active")
|
|
||||||
}
|
|
||||||
if (tab.disabled) {
|
|
||||||
classes("disabled")
|
|
||||||
}
|
|
||||||
onClick {
|
|
||||||
active = tab.key
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
Text(tab.title)
|
|
||||||
}
|
|
||||||
tab.titleExt.invoke(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tabs.find { it.key == active }?.let { tab ->
|
|
||||||
Div({ classes("card-body") }) {
|
|
||||||
tab.content.invoke(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TabBuilder internal constructor(public val key: String) {
|
|
||||||
private var title: String = key
|
|
||||||
public var disabled: Boolean = false
|
|
||||||
private var content: ContentBuilder<HTMLDivElement> = {}
|
|
||||||
private var titleExt: ContentBuilder<HTMLLIElement> = {}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Content(content: ContentBuilder<HTMLDivElement>) {
|
|
||||||
this.content = content
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Title(title: String, titleExt: ContentBuilder<HTMLLIElement> = {}) {
|
|
||||||
this.title = title
|
|
||||||
this.titleExt = titleExt
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun build(): ComposeTab = ComposeTab(
|
|
||||||
key,
|
|
||||||
title,
|
|
||||||
content,
|
|
||||||
disabled,
|
|
||||||
titleExt
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TabsBuilder {
|
|
||||||
public var active: String = ""
|
|
||||||
internal val tabs: MutableList<ComposeTab> = mutableListOf()
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Tab(key: String, builder: @Composable TabBuilder.() -> Unit) {
|
|
||||||
tabs.add(TabBuilder(key).apply { builder() }.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun addTab(tab: ComposeTab) {
|
|
||||||
tabs.add(tab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
public fun Tabs(builder: @Composable TabsBuilder.() -> Unit) {
|
|
||||||
val result = TabsBuilder().apply { builder() }
|
|
||||||
Tabs(result.tabs, result.active)
|
|
||||||
}
|
|
@ -7,6 +7,16 @@ description = "Jupyter api artifact including all common modules"
|
|||||||
kscience {
|
kscience {
|
||||||
fullStack(
|
fullStack(
|
||||||
"js/visionforge-jupyter-common.js",
|
"js/visionforge-jupyter-common.js",
|
||||||
|
browserConfig = {
|
||||||
|
webpackTask {
|
||||||
|
cssSupport{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
scssSupport {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
config.module.rules.push(...ringConfig.module.rules)
|
|
||||||
|
|
||||||
config.module.rules.push(
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: [
|
|
||||||
path.resolve(__dirname, "../../node_modules/@jetbrains/ring-ui")
|
|
||||||
],
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'style-loader',
|
|
||||||
options: {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
@ -7,8 +7,14 @@ val tablesVersion = "0.3.0"
|
|||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
js {
|
js {
|
||||||
useCommonJs()
|
|
||||||
binaries.library()
|
binaries.library()
|
||||||
|
browser {
|
||||||
|
webpackTask{
|
||||||
|
scssSupport {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useSerialization()
|
useSerialization()
|
||||||
@ -17,8 +23,8 @@ kscience {
|
|||||||
api("space.kscience:tables-kt:${tablesVersion}")
|
api("space.kscience:tables-kt:${tablesVersion}")
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
implementation(npm("tabulator-tables", "5.5.2"))
|
api(npm("tabulator-tables", "5.5.2"))
|
||||||
implementation(npm("@types/tabulator-tables", "5.5.3"))
|
api(npm("@types/tabulator-tables", "5.5.3"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING")
|
"NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING")
|
||||||
|
|
||||||
@file:JsModule("tabulator-tables")
|
@file:JsModule("tabulator-tables")
|
||||||
|
@file:JsNonModule
|
||||||
|
|
||||||
package tabulator
|
package tabulator
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ kscience {
|
|||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
api(projects.visionforgeCompose)
|
api(projects.visionforgeComposeHtml)
|
||||||
}
|
}
|
||||||
|
|
||||||
jsMain {
|
jsMain {
|
||||||
|
@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.jetbrains.compose.web.renderComposable
|
import org.jetbrains.compose.web.renderComposable
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.HTMLElement
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package space.kscience.visionforge.solid.three.compose
|
package space.kscience.visionforge.solid.three.compose
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import app.softwork.bootstrapcompose.Column
|
||||||
|
import app.softwork.bootstrapcompose.Layout.Height
|
||||||
|
import app.softwork.bootstrapcompose.Row
|
||||||
import org.jetbrains.compose.web.css.*
|
import org.jetbrains.compose.web.css.*
|
||||||
import org.jetbrains.compose.web.dom.Button
|
import org.jetbrains.compose.web.dom.Button
|
||||||
import org.jetbrains.compose.web.dom.Text
|
import org.jetbrains.compose.web.dom.Text
|
||||||
@ -18,8 +21,8 @@ internal fun CanvasControls(
|
|||||||
vision: Vision?,
|
vision: Vision?,
|
||||||
options: Canvas3DOptions,
|
options: Canvas3DOptions,
|
||||||
) {
|
) {
|
||||||
FlexColumn {
|
Column {
|
||||||
FlexRow({
|
Row(attrs = {
|
||||||
style {
|
style {
|
||||||
border {
|
border {
|
||||||
width(1.px)
|
width(1.px)
|
||||||
@ -64,8 +67,11 @@ public fun ThreeControls(
|
|||||||
onSelect: (Name?) -> Unit,
|
onSelect: (Name?) -> Unit,
|
||||||
tabBuilder: @Composable TabsBuilder.() -> Unit = {},
|
tabBuilder: @Composable TabsBuilder.() -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Tabs {
|
Tabs(
|
||||||
active = "Tree"
|
styling = {
|
||||||
|
Layout.height = Height.Full
|
||||||
|
}
|
||||||
|
) {
|
||||||
vision?.let { vision ->
|
vision?.let { vision ->
|
||||||
Tab("Tree") {
|
Tab("Tree") {
|
||||||
CardTitle("Vision tree")
|
CardTitle("Vision tree")
|
||||||
|
@ -2,6 +2,10 @@ package space.kscience.visionforge.solid.three.compose
|
|||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import app.softwork.bootstrapcompose.Card
|
import app.softwork.bootstrapcompose.Card
|
||||||
|
import app.softwork.bootstrapcompose.Column
|
||||||
|
import app.softwork.bootstrapcompose.Layout.Height
|
||||||
|
import app.softwork.bootstrapcompose.Layout.Width
|
||||||
|
import app.softwork.bootstrapcompose.Row
|
||||||
import kotlinx.dom.clear
|
import kotlinx.dom.clear
|
||||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
import org.jetbrains.compose.web.ExperimentalComposeWebApi
|
||||||
import org.jetbrains.compose.web.css.*
|
import org.jetbrains.compose.web.css.*
|
||||||
@ -90,24 +94,27 @@ public fun ThreeView(
|
|||||||
|
|
||||||
if (optionsSnapshot.controls.enabled) {
|
if (optionsSnapshot.controls.enabled) {
|
||||||
|
|
||||||
|
Row(
|
||||||
FlexRow({
|
styling = {
|
||||||
style {
|
Layout {
|
||||||
height(100.percent)
|
width = Width.Full
|
||||||
width(100.percent)
|
height = Height.Full
|
||||||
flexWrap(FlexWrap.Wrap)
|
|
||||||
alignItems(AlignItems.Stretch)
|
|
||||||
alignContent(AlignContent.Stretch)
|
|
||||||
}
|
}
|
||||||
}) {
|
}
|
||||||
FlexColumn({
|
) {
|
||||||
|
Column(
|
||||||
|
styling = {
|
||||||
|
Layout {
|
||||||
|
height = Height.Full
|
||||||
|
}
|
||||||
|
},
|
||||||
|
attrs = {
|
||||||
style {
|
style {
|
||||||
height(100.percent)
|
|
||||||
minWidth(600.px)
|
|
||||||
flex(10, 1, 600.px)
|
|
||||||
position(Position.Relative)
|
position(Position.Relative)
|
||||||
|
minWidth(600.px)
|
||||||
}
|
}
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
if (solid == null) {
|
if (solid == null) {
|
||||||
Div({
|
Div({
|
||||||
style {
|
style {
|
||||||
@ -143,20 +150,28 @@ public fun ThreeView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectedVision?.let { vision ->
|
selectedVision?.let { vision ->
|
||||||
Div({
|
Card(
|
||||||
|
attrs = {
|
||||||
style {
|
style {
|
||||||
position(Position.Absolute)
|
position(Position.Absolute)
|
||||||
top(5.px)
|
top(5.px)
|
||||||
right(5.px)
|
right(5.px)
|
||||||
width(450.px)
|
width(450.px)
|
||||||
}
|
}
|
||||||
}) {
|
},
|
||||||
Card(
|
|
||||||
headerAttrs = {
|
headerAttrs = {
|
||||||
// border = true
|
// border = true
|
||||||
},
|
},
|
||||||
header = {
|
header = {
|
||||||
NameCrumbs(selected) { selected = it }
|
NameCrumbs(selected) { selected = it }
|
||||||
|
},
|
||||||
|
footer = {
|
||||||
|
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
|
||||||
|
P {
|
||||||
|
B { Text("Styles: ") }
|
||||||
|
Text(styles.joinToString(separator = ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
PropertyEditor(
|
PropertyEditor(
|
||||||
@ -175,30 +190,29 @@ public fun ThreeView(
|
|||||||
updates = vision.properties.changes,
|
updates = vision.properties.changes,
|
||||||
rootDescriptor = vision.descriptor
|
rootDescriptor = vision.descriptor
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vision.styles.takeIf { it.isNotEmpty() }?.let { styles ->
|
Column(
|
||||||
P {
|
auto = true,
|
||||||
B { Text("Styles: ") }
|
styling = {
|
||||||
Text(styles.joinToString(separator = ", "))
|
Layout {
|
||||||
|
height = Height.Full
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
attrs = {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FlexColumn({
|
|
||||||
style {
|
style {
|
||||||
paddingAll(4.px)
|
paddingAll(4.px)
|
||||||
minWidth(400.px)
|
minWidth(400.px)
|
||||||
height(100.percent)
|
height(100.percent)
|
||||||
overflowY("auto")
|
overflowY("auto")
|
||||||
flex(1, 10, 300.px)
|
|
||||||
}
|
}
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
ThreeControls(solid, optionsSnapshot, selected, onSelect = { selected = it }, tabBuilder = sidebarTabs)
|
ThreeControls(solid, optionsSnapshot, selected, onSelect = { selected = it }, tabBuilder = sidebarTabs)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SimpleThreeView(solids.context, optionsSnapshot, solid, selected)
|
SimpleThreeView(solids.context, optionsSnapshot, solid, selected)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ kscience {
|
|||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
api(projects.visionforgeCompose)
|
api(projects.visionforgeComposeHtml)
|
||||||
}
|
}
|
||||||
|
|
||||||
jvmMain{
|
jvmMain{
|
||||||
@ -19,6 +19,8 @@ kscience {
|
|||||||
|
|
||||||
jsMain{
|
jsMain{
|
||||||
api(projects.visionforgeThreejs)
|
api(projects.visionforgeThreejs)
|
||||||
|
implementation(npm("file-saver","2.0.5"))
|
||||||
|
implementation(npm("@types/file-saver", "2.0.7"))
|
||||||
compileOnly(npm("webpack-bundle-analyzer","4.5.0"))
|
compileOnly(npm("webpack-bundle-analyzer","4.5.0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user