summaryrefslogtreecommitdiffstats
path: root/ui-desktop/src/main/resources
diff options
context:
space:
mode:
authorKostya <mail@sartin.in>2026-09-09 10:05:12 +0300
committerKostya <mail@sartin.in>2026-09-09 10:05:12 +0300
commitf23c20c1c66b39fb1f49307e08e8593fa708e026 (patch)
tree35cf625f5bbb1acf079b6abd2e239fcd446cd2a5 /ui-desktop/src/main/resources
parent8d7cecd9cf9fb2b0b45607b8efd7ca8f19a89fc6 (diff)
downloadguess-market-f23c20c1c66b39fb1f49307e08e8593fa708e026.tar.gz
guess-market-f23c20c1c66b39fb1f49307e08e8593fa708e026.tar.xz
guess-market-f23c20c1c66b39fb1f49307e08e8593fa708e026.zip
ui-desktop: build the JavaFX market UI on top of the service
Replace the placeholder hello-world window with a working desktop client for the guess market. ServiceEngine wires the in-memory repositories, XML loader, risk, matching, fulfillment and settlement contexts together, and AppState exposes their results as observable JavaFX state for the views to bind to. The FXML views have an events tab and a users tab. The events tab lists events with mechanism and commission filters, and shows each event's price chart, order book ladder, trade history and participants. The users tab shows each user's ledger and positions, and lets them place buy and sell orders. Dialogs cover loading an XML file (in a background task), creating an event and resolving one. Bundle a CSS theme and Nerd Font faces so the UI looks the same on every machine. Teach build.sh to copy each module's src/main/resources into its class output, since FXML, CSS and fonts are loaded from the classpath at runtime.
Diffstat (limited to 'ui-desktop/src/main/resources')
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/app_view.fxml158
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_create_event.fxml137
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_load.fxml32
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_resolve.fxml54
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/empty_state.fxml19
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/events_tab.fxml448
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/users_tab.fxml240
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/event_list_item.fxml30
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Bold.ttfbin0 -> 2959748 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Regular.ttfbin0 -> 2959676 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Bold.ttfbin0 -> 2782540 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Regular.ttfbin0 -> 2752724 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Bold.ttfbin0 -> 2472872 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Regular.ttfbin0 -> 2469104 bytes
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/ladder_item.fxml18
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/participant_item.fxml19
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/theme.css926
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/trade_history_item.fxml19
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/user_event_item.fxml21
-rw-r--r--ui-desktop/src/main/resources/market/guess/ui/desktop/user_list_item.fxml22
20 files changed, 2143 insertions, 0 deletions
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/app_view.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/app_view.fxml
new file mode 100644
index 0000000..855b787
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/app_view.fxml
@@ -0,0 +1,158 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Button?>
5<?import javafx.scene.control.ComboBox?>
6<?import javafx.scene.control.Label?>
7<?import javafx.scene.control.ScrollPane?>
8<?import javafx.scene.control.Tab?>
9<?import javafx.scene.control.TabPane?>
10<?import javafx.scene.control.Tooltip?>
11<?import javafx.scene.layout.BorderPane?>
12<?import javafx.scene.layout.HBox?>
13<?import javafx.scene.layout.Region?>
14<?import javafx.scene.layout.StackPane?>
15<?import javafx.scene.layout.VBox?>
16<?import javafx.scene.shape.SVGPath?>
17
18<StackPane fx:id="rootStack" styleClass="gm-root" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.AppController">
19 <children>
20 <!-- Safety net: scrolls only if the viewport gets smaller than AppView.MIN_WIDTH x MIN_HEIGHT. -->
21 <ScrollPane fitToHeight="true" fitToWidth="true" styleClass="gm-app-scroll">
22 <content>
23 <BorderPane fx:id="chrome" styleClass="gm-chrome">
24 <top>
25 <VBox>
26 <children>
27 <!-- Window Bar -->
28 <HBox fx:id="windowBar" alignment="CENTER_LEFT" prefHeight="32.0" spacing="10.0" styleClass="gm-bg-panel2, gm-divider-bottom">
29 <padding>
30 <Insets left="14.0" right="14.0" />
31 </padding>
32 <children>
33 <HBox alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-traffic-lights">
34 <children>
35 <StackPane maxHeight="12.0" maxWidth="12.0" minHeight="12.0" minWidth="12.0" onMouseClicked="#handleClose" prefHeight="12.0" prefWidth="12.0" styleClass="gm-traffic-dot, gm-traffic-dot-no">
36 <children>
37 <SVGPath content="M 0 0 L 5 5 M 5 0 L 0 5" styleClass="gm-traffic-icon" />
38 </children>
39 </StackPane>
40 <StackPane maxHeight="12.0" maxWidth="12.0" minHeight="12.0" minWidth="12.0" onMouseClicked="#handleMinimize" prefHeight="12.0" prefWidth="12.0" styleClass="gm-traffic-dot, gm-traffic-dot-accent">
41 <children>
42 <SVGPath content="M 0 2.5 L 6 2.5" styleClass="gm-traffic-icon" />
43 </children>
44 </StackPane>
45 <StackPane maxHeight="12.0" maxWidth="12.0" minHeight="12.0" minWidth="12.0" onMouseClicked="#handleMaximize" prefHeight="12.0" prefWidth="12.0" styleClass="gm-traffic-dot, gm-traffic-dot-yes">
46 <children>
47 <SVGPath content="M 0 2.5 L 5 2.5 M 2.5 0 L 2.5 5" styleClass="gm-traffic-icon" />
48 </children>
49 </StackPane>
50 </children>
51 </HBox>
52 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink2" text="Guess Market" />
53 </children>
54 </HBox>
55 <!-- Toolbar -->
56 <HBox alignment="CENTER_LEFT" spacing="12.0" styleClass="gm-bg-panel, gm-divider-bottom">
57 <padding>
58 <Insets bottom="12.0" left="16.0" right="16.0" top="12.0" />
59 </padding>
60 <children>
61 <Button minWidth="-Infinity" onAction="#handleLoadFile" styleClass="gm-btn, gm-btn-primary" text="Load File…" />
62 <HBox alignment="CENTER_LEFT" spacing="10.0" styleClass="gm-card-panel2" HBox.hgrow="ALWAYS">
63 <padding>
64 <Insets bottom="8.0" left="12.0" right="12.0" top="8.0" />
65 </padding>
66 <children>
67 <Label minWidth="-Infinity" styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="" />
68 <Label fx:id="loadedFilePathLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-base, gm-font-mono, gm-font-medium, gm-text-ink" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
69 </children>
70 </HBox>
71 <HBox alignment="CENTER_RIGHT" minWidth="-Infinity" spacing="12.0">
72 <children>
73 <Button fx:id="animationsButton" onAction="#handleAnimationsToggled" styleClass="gm-btn, gm-btn-secondary, gm-btn-icon">
74 <tooltip>
75 <Tooltip text="Toggle animations" />
76 </tooltip>
77 </Button>
78 <HBox alignment="CENTER_LEFT" spacing="8.0">
79 <children>
80 <ComboBox fx:id="skinComboBox" onAction="#handleSkinChanged" styleClass="gm-select-base, gm-select-btn-bg" />
81 </children>
82 </HBox>
83 </children>
84 </HBox>
85 </children>
86 </HBox>
87 </children>
88 </VBox>
89 </top>
90 <center>
91 <StackPane fx:id="centerContainer">
92 <children>
93 <fx:include fx:id="emptyState" source="controllers/empty_state.fxml" />
94 <TabPane fx:id="tabPane" managed="false" styleClass="gm-tabs" tabClosingPolicy="UNAVAILABLE" visible="false">
95 <tabs>
96 <Tab text="Events">
97 <content>
98 <fx:include fx:id="eventsTab" source="controllers/events_tab.fxml" />
99 </content>
100 </Tab>
101 <Tab text="Users">
102 <content>
103 <fx:include fx:id="usersTab" source="controllers/users_tab.fxml" />
104 </content>
105 </Tab>
106 </tabs>
107 </TabPane>
108 <!-- Overlaid on the right of the tab header; height is bound to the header in AppController -->
109 <HBox fx:id="tabInfo" alignment="CENTER_RIGHT" maxHeight="-Infinity" pickOnBounds="false" spacing="8.0" visible="false" StackPane.alignment="TOP_RIGHT">
110 <padding>
111 <Insets left="4.0" right="20.0" />
112 </padding>
113 <children>
114 <Label fx:id="actingAsLabel" styleClass="gm-text-base, gm-font-medium, gm-text-ink2">
115 <padding>
116 <Insets right="12.0" />
117 </padding>
118 </Label>
119 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="ACCOUNT BALANCE" />
120 <Label fx:id="balanceValueLabel" styleClass="gm-font-mono, gm-text-lg, gm-font-semibold, gm-text-accent" />
121 </children>
122 </HBox>
123 </children>
124 </StackPane>
125 </center>
126 <bottom>
127 <HBox alignment="CENTER_LEFT" prefHeight="30.0" spacing="12.0" styleClass="gm-bg-panel2, gm-divider-top">
128 <padding>
129 <Insets left="14.0" right="14.0" />
130 </padding>
131 <children>
132 <Label fx:id="statusBarLabel" styleClass="gm-text-sm, gm-font-mono, gm-text-ink2" />
133 <Region HBox.hgrow="ALWAYS" />
134 <Button fx:id="ejectButton" onAction="#handleEjectFile" styleClass="gm-link-button" text="󰮑" visible="false" />
135 </children>
136 </HBox>
137 </bottom>
138 </BorderPane>
139 </content>
140 </ScrollPane>
141 <StackPane fx:id="dialogContainer" mouseTransparent="true" visible="false">
142 <children>
143 <fx:include fx:id="loadDialog" managed="false" source="controllers/dialog_load.fxml" visible="false" />
144 <fx:include fx:id="createEventDialog" managed="false" source="controllers/dialog_create_event.fxml" visible="false" />
145 <fx:include fx:id="resolveDialog" managed="false" source="controllers/dialog_resolve.fxml" visible="false" />
146 </children>
147 </StackPane>
148 <StackPane fx:id="toastContainer" mouseTransparent="true" pickOnBounds="false">
149 <children>
150 <Label fx:id="toastLabel" styleClass="gm-toast" visible="false" StackPane.alignment="BOTTOM_CENTER">
151 <StackPane.margin>
152 <Insets bottom="44.0" />
153 </StackPane.margin>
154 </Label>
155 </children>
156 </StackPane>
157 </children>
158</StackPane>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_create_event.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_create_event.fxml
new file mode 100644
index 0000000..c8f092f
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_create_event.fxml
@@ -0,0 +1,137 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Button?>
5<?import javafx.scene.control.CheckBox?>
6<?import javafx.scene.control.ComboBox?>
7<?import javafx.scene.control.Label?>
8<?import javafx.scene.control.ScrollPane?>
9<?import javafx.scene.control.TextArea?>
10<?import javafx.scene.control.TextField?>
11<?import javafx.scene.layout.HBox?>
12<?import javafx.scene.layout.Region?>
13<?import javafx.scene.layout.StackPane?>
14<?import javafx.scene.layout.VBox?>
15
16<StackPane styleClass="gm-modal-scrim" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.CreateEventDialogController">
17 <children>
18 <ScrollPane fitToWidth="true" maxHeight="640.0" maxWidth="620.0" prefWidth="620.0" styleClass="gm-modal-card" StackPane.alignment="CENTER">
19 <content>
20 <VBox>
21 <children>
22 <!-- Header -->
23 <HBox alignment="BASELINE_LEFT" styleClass="gm-divider-bottom">
24 <padding>
25 <Insets bottom="16.0" left="20.0" right="20.0" top="16.0" />
26 </padding>
27 <children>
28 <Label styleClass="gm-text-xl, gm-font-bold, gm-text-ink" text="Create new event" />
29 <Region HBox.hgrow="ALWAYS" />
30 </children>
31 </HBox>
32 <!-- Body Form -->
33 <VBox spacing="14.0">
34 <padding>
35 <Insets bottom="18.0" left="20.0" right="20.0" top="18.0" />
36 </padding>
37 <children>
38 <!-- Name Field -->
39 <VBox spacing="5.0">
40 <children>
41 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Event name" />
42 <TextField fx:id="nameField" maxWidth="1.7976931348623157E308" promptText="Will the summit happen before Q4?" styleClass="gm-textfield" />
43 </children>
44 </VBox>
45 <!-- Description Field -->
46 <VBox spacing="5.0">
47 <children>
48 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Description &amp; termination condition" />
49 <TextArea fx:id="descArea" prefRowCount="2" promptText="Resolves YES if a joint summit is publicly confirmed and held before October 1st." styleClass="gm-textarea" wrapText="true" />
50 </children>
51 </VBox>
52 <!-- Row 1: Trading Method & Fee Collection -->
53 <HBox spacing="12.0">
54 <children>
55 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
56 <children>
57 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Trading method" />
58 <HBox>
59 <children>
60 <Button fx:id="lmsrBtn" maxWidth="1.7976931348623157E308" onAction="#handleSelectLmsr" styleClass="gm-seg, gm-seg-left, gm-seg-pad-tight" text="LMSR" HBox.hgrow="ALWAYS" />
61 <Button fx:id="orderBookBtn" maxWidth="1.7976931348623157E308" onAction="#handleSelectOrderBook" styleClass="gm-seg, gm-seg-right, gm-seg-pad-tight" text="Order Book" HBox.hgrow="ALWAYS" />
62 </children>
63 </HBox>
64 </children>
65 </VBox>
66 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
67 <children>
68 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Fee collection" />
69 <ComboBox fx:id="feeCollectionCombo" maxWidth="1.7976931348623157E308" styleClass="gm-select-base, gm-select-panel2-bg" />
70 </children>
71 </VBox>
72 </children>
73 </HBox>
74 <!-- Row 2: Fee Percent & Parameter -->
75 <HBox spacing="12.0">
76 <children>
77 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
78 <children>
79 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Fee percent (0–90)" />
80 <TextField fx:id="feePercentField" maxWidth="1.7976931348623157E308" promptText="5" styleClass="gm-textfield, gm-textfield-mono" />
81 </children>
82 </VBox>
83 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
84 <children>
85 <Label fx:id="paramLabel" styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Liquidity b (integer)" />
86 <TextField fx:id="paramField" maxWidth="1.7976931348623157E308" promptText="100" styleClass="gm-textfield, gm-textfield-mono" />
87 </children>
88 </VBox>
89 </children>
90 </HBox>
91 <!-- Option Names -->
92 <HBox spacing="12.0">
93 <children>
94 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
95 <children>
96 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Option 1" />
97 <TextField fx:id="opt1Field" maxWidth="1.7976931348623157E308" promptText="YES" styleClass="gm-textfield" />
98 </children>
99 </VBox>
100 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
101 <children>
102 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Option 2" />
103 <TextField fx:id="opt2Field" maxWidth="1.7976931348623157E308" promptText="NO" styleClass="gm-textfield" />
104 </children>
105 </VBox>
106 </children>
107 </HBox>
108 <!-- Minting CheckBox (Order Book only) -->
109 <CheckBox fx:id="mintingCheckBox" selected="true" styleClass="gm-checkbox-strong" text="Allow minting new share pairs when bid + ask exceeds d" visible="false" />
110 <!-- Info Box -->
111 <HBox styleClass="gm-card-panel2">
112 <padding>
113 <Insets bottom="11.0" left="13.0" right="13.0" top="11.0" />
114 </padding>
115 <children>
116 <Label fx:id="infoNoteLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" wrapText="true" />
117 </children>
118 </HBox>
119 </children>
120 </VBox>
121 <!-- Footer -->
122 <HBox alignment="CENTER_LEFT" spacing="9.0" styleClass="gm-divider-top">
123 <padding>
124 <Insets bottom="14.0" left="20.0" right="20.0" top="14.0" />
125 </padding>
126 <children>
127 <Region HBox.hgrow="ALWAYS" />
128 <Button onAction="#handleCancel" styleClass="gm-btn, gm-btn-secondary" text="Cancel" />
129 <Button onAction="#handleCreate" styleClass="gm-btn, gm-btn-primary" text="Create event" />
130 </children>
131 </HBox>
132 </children>
133 </VBox>
134 </content>
135 </ScrollPane>
136 </children>
137</StackPane>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_load.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_load.fxml
new file mode 100644
index 0000000..d93ac9e
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_load.fxml
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Button?>
5<?import javafx.scene.control.Label?>
6<?import javafx.scene.control.ProgressBar?>
7<?import javafx.scene.layout.HBox?>
8<?import javafx.scene.layout.Region?>
9<?import javafx.scene.layout.StackPane?>
10<?import javafx.scene.layout.VBox?>
11
12<StackPane styleClass="gm-modal-scrim" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.LoadDialogController">
13 <children>
14 <VBox maxHeight="-Infinity" maxWidth="-Infinity" prefWidth="430.0" spacing="12.0" styleClass="gm-card" StackPane.alignment="CENTER">
15 <padding>
16 <Insets bottom="20.0" left="22.0" right="22.0" top="20.0" />
17 </padding>
18 <children>
19 <Label styleClass="gm-text-lg, gm-font-bold, gm-text-ink" text="Loading events file…" />
20 <Label fx:id="pathLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-sm, gm-font-mono, gm-font-medium, gm-text-ink2" textOverrun="ELLIPSIS" />
21 <ProgressBar fx:id="progressBar" maxWidth="1.7976931348623157E308" prefHeight="9.0" progress="0.06" styleClass="gm-progress, gm-progress-accent" />
22 <HBox alignment="CENTER_LEFT">
23 <children>
24 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Validating users, market makers and fees…" />
25 <Region HBox.hgrow="ALWAYS" />
26 <Button onAction="#handleCancel" styleClass="gm-btn, gm-btn-secondary" text="Cancel" />
27 </children>
28 </HBox>
29 </children>
30 </VBox>
31 </children>
32</StackPane>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_resolve.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_resolve.fxml
new file mode 100644
index 0000000..b5a9634
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/dialog_resolve.fxml
@@ -0,0 +1,54 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Button?>
5<?import javafx.scene.control.Label?>
6<?import javafx.scene.layout.HBox?>
7<?import javafx.scene.layout.Priority?>
8<?import javafx.scene.layout.Region?>
9<?import javafx.scene.layout.StackPane?>
10<?import javafx.scene.layout.VBox?>
11
12<StackPane styleClass="gm-modal-scrim" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.ResolveDialogController">
13 <children>
14 <VBox maxHeight="-Infinity" maxWidth="-Infinity" prefWidth="470.0" styleClass="gm-card" StackPane.alignment="CENTER">
15 <children>
16 <!-- Title -->
17 <HBox alignment="CENTER_LEFT" styleClass="gm-divider-bottom">
18 <padding>
19 <Insets bottom="16.0" left="20.0" right="20.0" top="16.0" />
20 </padding>
21 <children>
22 <Label styleClass="gm-text-lg, gm-font-bold, gm-text-ink" text="Close &amp; resolve event" />
23 </children>
24 </HBox>
25 <!-- Body -->
26 <VBox spacing="13.0">
27 <padding>
28 <Insets bottom="18.0" left="20.0" right="20.0" top="18.0" />
29 </padding>
30 <children>
31 <Label styleClass="gm-text-base, gm-font-regular, gm-text-ink2" text="Pick the option the event ended with. The contract account is emptied to holders of the winning option; a close-time fee is moved to the market maker. This cannot be undone." wrapText="true" />
32 <HBox spacing="10.0">
33 <children>
34 <Button fx:id="resolveYesBtn" maxWidth="1.7976931348623157E308" onAction="#handleSelectYes" styleClass="gm-resolve-option, gm-resolve-option-yes" text="YES" HBox.hgrow="ALWAYS" />
35 <Button fx:id="resolveNoBtn" maxWidth="1.7976931348623157E308" onAction="#handleSelectNo" styleClass="gm-resolve-option, gm-resolve-option-no" text="NO" HBox.hgrow="ALWAYS" />
36 </children>
37 </HBox>
38 </children>
39 </VBox>
40 <!-- Footer -->
41 <HBox alignment="CENTER_LEFT" spacing="9.0" styleClass="gm-divider-top">
42 <padding>
43 <Insets bottom="14.0" left="20.0" right="20.0" top="14.0" />
44 </padding>
45 <children>
46 <Region HBox.hgrow="ALWAYS" />
47 <Button onAction="#handleCancel" styleClass="gm-btn, gm-btn-secondary" text="Cancel" />
48 <Button fx:id="confirmBtn" disable="true" onAction="#handleConfirm" styleClass="gm-btn, gm-btn-destructive" text="Resolve as …" />
49 </children>
50 </HBox>
51 </children>
52 </VBox>
53 </children>
54</StackPane>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/empty_state.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/empty_state.fxml
new file mode 100644
index 0000000..0385759
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/empty_state.fxml
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.scene.control.Button?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.StackPane?>
6<?import javafx.scene.layout.VBox?>
7<?import market.guess.ui.desktop.components.graphic.MarketChart?>
8
9<StackPane styleClass="gm-chrome" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.EmptyStateController">
10 <children>
11 <VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" spacing="14.0">
12 <children>
13 <MarketChart fx:id="marketChart" />
14 <Label styleClass="gm-text-xl, gm-font-semibold, gm-text-ink" text="No file loaded" />
15 <Label alignment="CENTER" maxWidth="420.0" styleClass="gm-text-md, gm-font-regular, gm-text-ink2" text="Load an XML file to populate events and users" textAlignment="CENTER" wrapText="true" />
16 </children>
17 </VBox>
18 </children>
19</StackPane>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/events_tab.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/events_tab.fxml
new file mode 100644
index 0000000..4e2c1d4
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/events_tab.fxml
@@ -0,0 +1,448 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.layout.FlowPane?>
5<?import javafx.scene.chart.LineChart?>
6<?import javafx.scene.chart.NumberAxis?>
7<?import javafx.scene.control.Button?>
8<?import javafx.scene.control.Label?>
9<?import javafx.scene.control.ListView?>
10<?import javafx.scene.control.ProgressBar?>
11<?import javafx.scene.control.ScrollPane?>
12<?import javafx.scene.layout.HBox?>
13<?import javafx.scene.layout.Priority?>
14<?import javafx.scene.layout.Region?>
15<?import javafx.scene.layout.StackPane?>
16<?import javafx.scene.layout.VBox?>
17
18<HBox spacing="12.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.EventsTabController">
19 <padding>
20 <Insets bottom="12.0" left="16.0" right="16.0" top="12.0" />
21 </padding>
22 <children>
23 <!-- Left Card: Filters + List -->
24 <VBox maxWidth="498.0" minWidth="498.0" prefWidth="498.0" spacing="10.0" styleClass="gm-card">
25 <padding>
26 <Insets bottom="12.0" left="12.0" right="12.0" top="12.0" />
27 </padding>
28 <children>
29 <!-- Method Filter -->
30 <HBox alignment="CENTER_LEFT" spacing="8.0">
31 <children>
32 <Label minWidth="74.0" prefWidth="74.0" styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Method" />
33 <Button fx:id="methodFilterAllBtn" onAction="#handleMethodAll" styleClass="gm-toggle" text="All" />
34 <Button fx:id="methodFilterLmsrBtn" onAction="#handleMethodLmsr" styleClass="gm-toggle" text="LMSR" />
35 <Button fx:id="methodFilterObBtn" onAction="#handleMethodOb" styleClass="gm-toggle" text="Order Book" />
36 </children>
37 </HBox>
38 <!-- Status Filter -->
39 <HBox alignment="CENTER_LEFT" spacing="8.0">
40 <children>
41 <Label minWidth="74.0" prefWidth="74.0" styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Status" />
42 <Button fx:id="statusFilterAllBtn" onAction="#handleStatusAll" styleClass="gm-toggle" text="All" />
43 <Button fx:id="statusFilterNotStartedBtn" onAction="#handleStatusNotStarted" styleClass="gm-toggle" text="Not started" />
44 <Button fx:id="statusFilterActiveBtn" onAction="#handleStatusActive" styleClass="gm-toggle" text="Active" />
45 <Button fx:id="statusFilterClosedBtn" onAction="#handleStatusClosed" styleClass="gm-toggle" text="Closed" />
46 </children>
47 </HBox>
48 <!-- Fee Filter -->
49 <HBox alignment="CENTER_LEFT" spacing="8.0">
50 <children>
51 <Label minWidth="74.0" prefWidth="74.0" styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Fee" />
52 <Button fx:id="feeFilterAllBtn" onAction="#handleFeeAll" styleClass="gm-toggle" text="All" />
53 <Button fx:id="feeFilterPurchaseBtn" onAction="#handleFeePurchase" styleClass="gm-toggle" text="On purchase" />
54 <Button fx:id="feeFilterCloseBtn" onAction="#handleFeeClose" styleClass="gm-toggle" text="On close" />
55 </children>
56 </HBox>
57 <!-- Virtualized Event List -->
58 <ListView fx:id="eventListContainer" styleClass="gm-scroll-transparent, gm-list-view" VBox.vgrow="ALWAYS" />
59 <!-- Footer -->
60 <HBox alignment="CENTER_LEFT">
61 <children>
62 <Label fx:id="eventCountLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="0 of 0 events shown" />
63 <Region HBox.hgrow="ALWAYS" />
64 <Button onAction="#handleNewEvent" styleClass="gm-btn, gm-btn-secondary" text="+ New Event" />
65 </children>
66 </HBox>
67 </children>
68 </VBox>
69 <!-- Right Card: Event Details -->
70 <VBox fx:id="eventDetailCard" styleClass="gm-card" HBox.hgrow="ALWAYS">
71 <children>
72 <!-- Detail Header -->
73 <VBox fx:id="detailHeaderBox" spacing="9.0" styleClass="gm-divider-bottom">
74 <padding>
75 <Insets bottom="14.0" left="16.0" right="16.0" top="14.0" />
76 </padding>
77 <children>
78 <HBox alignment="TOP_LEFT" spacing="12.0">
79 <children>
80 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
81 <children>
82 <Label fx:id="eventNameLabel" styleClass="gm-text-xl, gm-font-bold, gm-text-ink" />
83 <Label fx:id="eventDescLabel" styleClass="gm-text-base, gm-font-regular, gm-text-ink2" wrapText="true" />
84 </children>
85 </VBox>
86 <HBox spacing="7.0">
87 <children>
88 <Button fx:id="openEventBtn" onAction="#handleOpenEvent" styleClass="gm-btn, gm-btn-primary" text="Open Event" />
89 <Button fx:id="closeEventBtn" onAction="#handleCloseEvent" styleClass="gm-btn, gm-btn-secondary" text="Close &amp; Resolve…" />
90 </children>
91 </HBox>
92 </children>
93 </HBox>
94 <HBox fx:id="metaFieldsBox" alignment="CENTER_LEFT" spacing="16.0">
95 <children>
96 <HBox fx:id="livePill" alignment="CENTER_LEFT" spacing="7.0" styleClass="gm-pill, gm-live-pill">
97 <children>
98 <StackPane fx:id="liveBarsBox" />
99 <Label fx:id="liveLabel" styleClass="gm-live-label" />
100 </children>
101 </HBox>
102 <HBox alignment="CENTER_LEFT" spacing="4.0">
103 <children>
104 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Method" />
105 <Label fx:id="metaMethodLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
106 </children>
107 </HBox>
108 <HBox alignment="CENTER_LEFT" spacing="4.0">
109 <children>
110 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Status" />
111 <Label fx:id="metaStatusLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
112 </children>
113 </HBox>
114 <HBox alignment="CENTER_LEFT" spacing="4.0">
115 <children>
116 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Market Maker" />
117 <Label fx:id="metaMmLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
118 </children>
119 </HBox>
120 <HBox alignment="CENTER_LEFT" spacing="4.0">
121 <children>
122 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Fee" />
123 <Label fx:id="metaFeeLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
124 </children>
125 </HBox>
126 <HBox alignment="CENTER_LEFT" spacing="4.0">
127 <children>
128 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Contract" />
129 <Label fx:id="metaContractLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
130 </children>
131 </HBox>
132 </children>
133 </HBox>
134 </children>
135 </VBox>
136 <!-- Detail Scrollable Body -->
137 <ScrollPane fitToWidth="true" styleClass="gm-scroll-transparent" VBox.vgrow="ALWAYS">
138 <content>
139 <VBox spacing="14.0">
140 <padding>
141 <Insets bottom="14.0" left="16.0" right="16.0" top="14.0" />
142 </padding>
143 <children>
144 <!-- LMSR Section -->
145 <VBox fx:id="lmsrSection" spacing="14.0">
146 <children>
147 <!-- YES / NO Option Cards -->
148 <HBox spacing="10.0">
149 <children>
150 <VBox spacing="9.0" styleClass="gm-card-soft-yes" HBox.hgrow="ALWAYS">
151 <padding>
152 <Insets bottom="12.0" left="13.0" right="13.0" top="12.0" />
153 </padding>
154 <children>
155 <HBox alignment="BASELINE_LEFT">
156 <children>
157 <Label styleClass="gm-text-lg, gm-font-bold, gm-text-yes" text="YES" />
158 <Region HBox.hgrow="ALWAYS" />
159 <Label fx:id="lmsrYesPriceLabel" styleClass="gm-text-2xl, gm-font-semibold, gm-font-mono, gm-text-yes" />
160 </children>
161 </HBox>
162 <ProgressBar fx:id="lmsrYesProgressBar" maxHeight="6.0" maxWidth="1.7976931348623157E308" minHeight="6.0" prefHeight="6.0" styleClass="gm-progress, gm-progress-yes" />
163 <Label fx:id="lmsrYesSharesLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
164 </children>
165 </VBox>
166 <VBox spacing="9.0" styleClass="gm-card-soft-no" HBox.hgrow="ALWAYS">
167 <padding>
168 <Insets bottom="12.0" left="13.0" right="13.0" top="12.0" />
169 </padding>
170 <children>
171 <HBox alignment="BASELINE_LEFT">
172 <children>
173 <Label styleClass="gm-text-lg, gm-font-bold, gm-text-no" text="NO" />
174 <Region HBox.hgrow="ALWAYS" />
175 <Label fx:id="lmsrNoPriceLabel" styleClass="gm-text-2xl, gm-font-semibold, gm-font-mono, gm-text-no" />
176 </children>
177 </HBox>
178 <ProgressBar fx:id="lmsrNoProgressBar" maxHeight="6.0" maxWidth="1.7976931348623157E308" minHeight="6.0" prefHeight="6.0" styleClass="gm-progress, gm-progress-no" />
179 <Label fx:id="lmsrNoSharesLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
180 </children>
181 </VBox>
182 </children>
183 </HBox>
184 <!-- LMSR Chart Block -->
185 <VBox spacing="8.0">
186 <children>
187 <HBox alignment="CENTER_LEFT">
188 <children>
189 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Share price over time" />
190 <Region HBox.hgrow="ALWAYS" />
191 <Label fx:id="lmsrChartSubLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
192 </children>
193 </HBox>
194 <VBox styleClass="gm-card-panel2">
195 <padding>
196 <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
197 </padding>
198 <children>
199 <LineChart fx:id="lmsrChart" animated="false" createSymbols="false" horizontalGridLinesVisible="true" legendVisible="false" prefHeight="170.0" styleClass="gm-chart, gm-chart-dual" verticalGridLinesVisible="false">
200 <xAxis>
201 <NumberAxis autoRanging="false" forceZeroInRange="false" minorTickVisible="false" styleClass="gm-chart-axis" tickLabelsVisible="true" tickMarkVisible="true" />
202 </xAxis>
203 <yAxis>
204 <NumberAxis autoRanging="false" lowerBound="0.0" minorTickVisible="false" styleClass="gm-chart-axis" tickUnit="0.25" upperBound="1.0" />
205 </yAxis>
206 </LineChart>
207 </children>
208 </VBox>
209 </children>
210 </VBox>
211 </children>
212 </VBox>
213 <!-- Order Book Section -->
214 <VBox fx:id="orderBookSection" spacing="14.0">
215 <children>
216 <HBox spacing="12.0">
217 <children>
218 <!-- YES Order Book -->
219 <VBox styleClass="gm-card-panel2" HBox.hgrow="ALWAYS">
220 <children>
221 <HBox alignment="CENTER_LEFT" styleClass="gm-card-soft-yes">
222 <padding>
223 <Insets bottom="10.0" left="12.0" right="12.0" top="10.0" />
224 </padding>
225 <children>
226 <Label styleClass="gm-text-base, gm-font-bold, gm-text-yes" text="YES Order Book" />
227 <Region HBox.hgrow="ALWAYS" />
228 <Label fx:id="yesBookCountLabel" styleClass="gm-text-xs, gm-font-regular, gm-text-ink2" />
229 </children>
230 </HBox>
231 <FlowPane hgap="12.0" vgap="4.0" styleClass="gm-divider-bottom">
232 <padding>
233 <Insets bottom="8.0" left="12.0" right="12.0" top="8.0" />
234 </padding>
235 <children>
236 <HBox spacing="4.0">
237 <children>
238 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Last" />
239 <Label fx:id="yesLastLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
240 </children>
241 </HBox>
242 <HBox spacing="4.0">
243 <children>
244 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Best bid" />
245 <Label fx:id="yesBestBidLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
246 </children>
247 </HBox>
248 <HBox spacing="4.0">
249 <children>
250 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Best ask" />
251 <Label fx:id="yesBestAskLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
252 </children>
253 </HBox>
254 <HBox spacing="4.0">
255 <children>
256 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Mid" />
257 <Label fx:id="yesMidLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
258 </children>
259 </HBox>
260 <HBox spacing="4.0">
261 <children>
262 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Spread" />
263 <Label fx:id="yesSpreadLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
264 </children>
265 </HBox>
266 </children>
267 </FlowPane>
268 <HBox spacing="8.0" styleClass="gm-bg-panel3">
269 <padding>
270 <Insets bottom="6.0" left="12.0" right="12.0" top="6.0" />
271 </padding>
272 <children>
273 <Label alignment="CENTER_RIGHT" minWidth="54.0" prefWidth="54.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Price" />
274 <Label alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Side" />
275 <Label alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Qty" />
276 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="User" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
277 </children>
278 </HBox>
279 <VBox fx:id="yesBookLadderList" />
280 </children>
281 </VBox>
282 <!-- NO Order Book -->
283 <VBox styleClass="gm-card-panel2" HBox.hgrow="ALWAYS">
284 <children>
285 <HBox alignment="CENTER_LEFT" styleClass="gm-card-soft-no">
286 <padding>
287 <Insets bottom="10.0" left="12.0" right="12.0" top="10.0" />
288 </padding>
289 <children>
290 <Label styleClass="gm-text-base, gm-font-bold, gm-text-no" text="NO Order Book" />
291 <Region HBox.hgrow="ALWAYS" />
292 <Label fx:id="noBookCountLabel" styleClass="gm-text-xs, gm-font-regular, gm-text-ink2" />
293 </children>
294 </HBox>
295 <FlowPane hgap="12.0" vgap="4.0" styleClass="gm-divider-bottom">
296 <padding>
297 <Insets bottom="8.0" left="12.0" right="12.0" top="8.0" />
298 </padding>
299 <children>
300 <HBox spacing="4.0">
301 <children>
302 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Last" />
303 <Label fx:id="noLastLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
304 </children>
305 </HBox>
306 <HBox spacing="4.0">
307 <children>
308 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Best bid" />
309 <Label fx:id="noBestBidLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
310 </children>
311 </HBox>
312 <HBox spacing="4.0">
313 <children>
314 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Best ask" />
315 <Label fx:id="noBestAskLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
316 </children>
317 </HBox>
318 <HBox spacing="4.0">
319 <children>
320 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Mid" />
321 <Label fx:id="noMidLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
322 </children>
323 </HBox>
324 <HBox spacing="4.0">
325 <children>
326 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="Spread" />
327 <Label fx:id="noSpreadLabel" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink" />
328 </children>
329 </HBox>
330 </children>
331 </FlowPane>
332 <HBox spacing="8.0" styleClass="gm-bg-panel3">
333 <padding>
334 <Insets bottom="6.0" left="12.0" right="12.0" top="6.0" />
335 </padding>
336 <children>
337 <Label alignment="CENTER_RIGHT" minWidth="54.0" prefWidth="54.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Price" />
338 <Label alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Side" />
339 <Label alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Qty" />
340 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="User" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
341 </children>
342 </HBox>
343 <VBox fx:id="noBookLadderList" />
344 </children>
345 </VBox>
346 </children>
347 </HBox>
348 <VBox spacing="8.0">
349 <children>
350 <HBox alignment="CENTER_LEFT">
351 <children>
352 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Last trade price over time" />
353 <Region HBox.hgrow="ALWAYS" />
354 <Label fx:id="obChartSubLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
355 </children>
356 </HBox>
357 <VBox styleClass="gm-card-panel2">
358 <padding>
359 <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
360 </padding>
361 <children>
362 <LineChart fx:id="obChart" animated="false" createSymbols="false" horizontalGridLinesVisible="true" legendVisible="false" prefHeight="160.0" styleClass="gm-chart, gm-chart-single" verticalGridLinesVisible="false">
363 <xAxis>
364 <NumberAxis autoRanging="false" forceZeroInRange="false" minorTickVisible="false" styleClass="gm-chart-axis" tickLabelsVisible="true" tickMarkVisible="true" />
365 </xAxis>
366 <yAxis>
367 <NumberAxis autoRanging="false" lowerBound="0.0" minorTickVisible="false" styleClass="gm-chart-axis" tickUnit="0.25" upperBound="1.0" />
368 </yAxis>
369 </LineChart>
370 </children>
371 </VBox>
372 </children>
373 </VBox>
374 </children>
375 </VBox>
376 <!-- Trade History Block -->
377 <VBox spacing="7.0">
378 <children>
379 <HBox alignment="CENTER_LEFT" spacing="6.0">
380 <children>
381 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Trade history" />
382 <Label styleClass="gm-text-base, gm-font-regular, gm-text-ink2" text="newest first" />
383 </children>
384 </HBox>
385 <VBox styleClass="gm-card-panel">
386 <children>
387 <HBox alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-bg-panel3">
388 <padding>
389 <Insets bottom="8.0" left="11.0" right="11.0" top="8.0" />
390 </padding>
391 <children>
392 <Label minWidth="66.0" prefWidth="66.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="#" />
393 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="User" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
394 <Label minWidth="76.0" prefWidth="76.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Option" />
395 <Label minWidth="92.0" prefWidth="92.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Shares" />
396 <Label minWidth="88.0" prefWidth="88.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Paid" />
397 </children>
398 </HBox>
399 <VBox fx:id="tradeHistoryRowsContainer" />
400 </children>
401 </VBox>
402 </children>
403 </VBox>
404 <!-- Participants Section -->
405 <VBox spacing="7.0">
406 <children>
407 <VBox styleClass="gm-card-panel">
408 <children>
409 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Participants">
410 <padding>
411 <Insets bottom="4.0" />
412 </padding>
413 </Label>
414 <HBox alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-bg-panel3">
415 <padding>
416 <Insets bottom="8.0" left="11.0" right="11.0" top="8.0" />
417 </padding>
418 <children>
419 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="User" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
420 <Label alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="YES" />
421 <Label alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="NO" />
422 <Label alignment="CENTER_RIGHT" minWidth="96.0" prefWidth="96.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Value" />
423 <Label alignment="CENTER_RIGHT" minWidth="96.0" prefWidth="96.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Fees paid" />
424 </children>
425 </HBox>
426 <VBox fx:id="participantsRowsContainer" />
427 </children>
428 </VBox>
429 </children>
430 </VBox>
431 <!-- Resolved Banner Section -->
432 <HBox fx:id="resolvedBanner" alignment="CENTER_LEFT" spacing="12.0" styleClass="gm-banner-resolved">
433 <padding>
434 <Insets bottom="12.0" left="14.0" right="14.0" top="12.0" />
435 </padding>
436 <children>
437 <Label styleClass="gm-pill, gm-pill-resolved" text="RESOLVED" />
438 <Label fx:id="resolvedBannerText" maxWidth="1.7976931348623157E308" styleClass="gm-text-md, gm-font-medium, gm-text-ink" wrapText="true" HBox.hgrow="ALWAYS" />
439 </children>
440 </HBox>
441 </children>
442 </VBox>
443 </content>
444 </ScrollPane>
445 </children>
446 </VBox>
447 </children>
448</HBox>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/users_tab.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/users_tab.fxml
new file mode 100644
index 0000000..0a8ee3b
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/controllers/users_tab.fxml
@@ -0,0 +1,240 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.chart.LineChart?>
5<?import javafx.scene.chart.NumberAxis?>
6<?import javafx.scene.control.Button?>
7<?import javafx.scene.control.Label?>
8<?import javafx.scene.control.ListView?>
9<?import javafx.scene.control.ScrollPane?>
10<?import javafx.scene.control.TextField?>
11<?import javafx.scene.layout.FlowPane?>
12<?import javafx.scene.layout.HBox?>
13<?import javafx.scene.layout.Priority?>
14<?import javafx.scene.layout.Region?>
15<?import javafx.scene.layout.StackPane?>
16<?import javafx.scene.layout.VBox?>
17
18<HBox spacing="12.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="market.guess.ui.desktop.controllers.UsersTabController">
19 <padding>
20 <Insets bottom="12.0" left="16.0" right="16.0" top="12.0" />
21 </padding>
22 <children>
23 <!-- Left Card: Users List -->
24 <VBox maxWidth="274.0" minWidth="274.0" prefWidth="274.0" spacing="6.0" styleClass="gm-card">
25 <padding>
26 <Insets bottom="12.0" left="12.0" right="12.0" top="12.0" />
27 </padding>
28 <children>
29 <!-- Header -->
30 <HBox alignment="CENTER_LEFT" spacing="8.0">
31 <children>
32 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="User" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
33 <Label alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Balance" />
34 </children>
35 </HBox>
36 <!-- Virtualized Users List -->
37 <ListView fx:id="userListContainer" styleClass="gm-scroll-transparent, gm-list-view" VBox.vgrow="ALWAYS" />
38 <!-- Create Event Button -->
39 <Button maxWidth="1.7976931348623157E308" onAction="#handleCreateNewEvent" styleClass="gm-btn, gm-btn-primary" text="+ Create New Event" />
40 </children>
41 </VBox>
42 <!-- Right Card: User Details -->
43 <VBox fx:id="userDetailCard" styleClass="gm-card" HBox.hgrow="ALWAYS">
44 <children>
45 <!-- Header Section -->
46 <HBox alignment="CENTER_LEFT" spacing="14.0" styleClass="gm-divider-bottom">
47 <padding>
48 <Insets bottom="14.0" left="16.0" right="16.0" top="14.0" />
49 </padding>
50 <children>
51 <VBox spacing="5.0" HBox.hgrow="ALWAYS">
52 <children>
53 <HBox alignment="CENTER_LEFT" spacing="9.0">
54 <children>
55 <Label fx:id="userNameLabel" styleClass="gm-text-xl, gm-font-bold, gm-text-ink" />
56 <Label fx:id="userRolePill" styleClass="gm-pill" />
57 </children>
58 </HBox>
59 <Label fx:id="userSubLabel" styleClass="gm-text-base, gm-font-regular, gm-text-ink2" />
60 </children>
61 </VBox>
62 <HBox alignment="CENTER_RIGHT" spacing="12.0">
63 <children>
64 <StackPane fx:id="sparklineBox" />
65 <VBox alignment="CENTER_RIGHT" spacing="4.0">
66 <children>
67 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Balance" />
68 <Label fx:id="userBalanceLabel" styleClass="gm-user-balance" />
69 </children>
70 </VBox>
71 </children>
72 </HBox>
73 </children>
74 </HBox>
75 <!-- Body Content (Scrollable) -->
76 <ScrollPane fitToWidth="true" styleClass="gm-scroll-transparent" VBox.vgrow="ALWAYS">
77 <content>
78 <VBox spacing="14.0">
79 <padding>
80 <Insets bottom="14.0" left="16.0" right="16.0" top="14.0" />
81 </padding>
82 <children>
83 <!-- Blocked Banner -->
84 <HBox fx:id="blockedBanner" alignment="CENTER_LEFT" spacing="11.0" styleClass="gm-banner-blocked">
85 <padding>
86 <Insets bottom="11.0" left="13.0" right="13.0" top="11.0" />
87 </padding>
88 <children>
89 <Label styleClass="gm-pill, gm-pill-blocked" text="BLOCKED" />
90 <Label maxWidth="1.7976931348623157E308" styleClass="gm-text-base, gm-font-medium, gm-text-ink" text="This account reached a negative balance. All trading actions are disabled and cannot be re-enabled — accounts cannot be topped up in Ex 2." wrapText="true" HBox.hgrow="ALWAYS" />
91 </children>
92 </HBox>
93 <!-- Balance Chart Block -->
94 <VBox spacing="8.0">
95 <children>
96 <HBox alignment="CENTER_LEFT">
97 <children>
98 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Account balance over time" />
99 <Region HBox.hgrow="ALWAYS" />
100 <Label styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" text="every trade, fee and payout" />
101 </children>
102 </HBox>
103 <VBox styleClass="gm-card-panel2">
104 <padding>
105 <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
106 </padding>
107 <children>
108 <LineChart fx:id="balanceChart" animated="false" createSymbols="false" horizontalGridLinesVisible="true" legendVisible="false" prefHeight="170.0" styleClass="gm-chart, gm-chart-single" verticalGridLinesVisible="false">
109 <xAxis>
110 <NumberAxis autoRanging="false" forceZeroInRange="false" minorTickVisible="false" styleClass="gm-chart-axis" tickLabelsVisible="true" tickMarkVisible="true" />
111 </xAxis>
112 <yAxis>
113 <NumberAxis autoRanging="true" minorTickVisible="false" styleClass="gm-chart-axis" />
114 </yAxis>
115 </LineChart>
116 </children>
117 </VBox>
118 </children>
119 </VBox>
120 <!-- Participation Table Block -->
121 <VBox spacing="7.0">
122 <children>
123 <Label styleClass="gm-text-base, gm-font-semibold, gm-text-ink" text="Events participation / owner" />
124 <VBox styleClass="gm-card-panel">
125 <children>
126 <HBox alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-bg-panel3">
127 <padding>
128 <Insets bottom="8.0" left="11.0" right="11.0" top="8.0" />
129 </padding>
130 <children>
131 <Label maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Event" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
132 <Label minWidth="-Infinity" prefWidth="92.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Role" />
133 <Label minWidth="-Infinity" prefWidth="78.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="Type" />
134 <Label alignment="CENTER_RIGHT" minWidth="78.0" prefWidth="78.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="YES" />
135 <Label alignment="CENTER_RIGHT" minWidth="78.0" prefWidth="78.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="NO" />
136 <Label alignment="CENTER_RIGHT" minWidth="90.0" prefWidth="90.0" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" text="P/L" />
137 </children>
138 </HBox>
139 <VBox fx:id="participationRowsContainer" />
140 </children>
141 </VBox>
142 </children>
143 </VBox>
144 <!-- Trade Panel Block -->
145 <VBox fx:id="tradePanel" spacing="9.0" styleClass="gm-card-panel2">
146 <padding>
147 <Insets bottom="13.0" left="14.0" right="14.0" top="13.0" />
148 </padding>
149 <children>
150 <Label fx:id="noTradeEventLabel" styleClass="gm-text-base, gm-font-regular, gm-text-ink2" text="Select an event above to trade." visible="false" />
151 <VBox fx:id="tradeContentBox" spacing="9.0">
152 <children>
153 <HBox alignment="BASELINE_LEFT">
154 <children>
155 <Label fx:id="tradeEventTitle" styleClass="gm-text-lg, gm-font-bold, gm-text-ink" />
156 <Region HBox.hgrow="ALWAYS" />
157 <Label fx:id="tradeEventSub" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
158 </children>
159 </HBox>
160 <HBox spacing="10.0">
161 <children>
162 <VBox fx:id="tradeYesOptCard" onMouseClicked="#handleSelectTradeYes" spacing="6.0" styleClass="gm-option-card, gm-option-card-yes" HBox.hgrow="ALWAYS">
163 <padding>
164 <Insets bottom="10.0" left="12.0" right="12.0" top="10.0" />
165 </padding>
166 <children>
167 <HBox alignment="CENTER_LEFT">
168 <children>
169 <Label styleClass="gm-text-md, gm-font-bold, gm-text-yes" text="YES" />
170 <Region HBox.hgrow="ALWAYS" />
171 <Label fx:id="tradeYesPriceLabel" styleClass="gm-text-xl, gm-font-semibold, gm-font-mono, gm-text-yes" />
172 </children>
173 </HBox>
174 <Label fx:id="tradeYesHeldLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
175 </children>
176 </VBox>
177 <VBox fx:id="tradeNoOptCard" onMouseClicked="#handleSelectTradeNo" spacing="6.0" styleClass="gm-option-card, gm-option-card-no" HBox.hgrow="ALWAYS">
178 <padding>
179 <Insets bottom="10.0" left="12.0" right="12.0" top="10.0" />
180 </padding>
181 <children>
182 <HBox alignment="CENTER_LEFT">
183 <children>
184 <Label styleClass="gm-text-md, gm-font-bold, gm-text-no" text="NO" />
185 <Region HBox.hgrow="ALWAYS" />
186 <Label fx:id="tradeNoPriceLabel" styleClass="gm-text-xl, gm-font-semibold, gm-font-mono, gm-text-no" />
187 </children>
188 </HBox>
189 <Label fx:id="tradeNoHeldLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
190 </children>
191 </VBox>
192 </children>
193 </HBox>
194 <FlowPane alignment="BOTTOM_LEFT" hgap="10.0" vgap="10.0">
195 <children>
196 <VBox spacing="5.0">
197 <children>
198 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Action" />
199 <HBox>
200 <children>
201 <Button fx:id="tradeBuyBtn" onAction="#handleTradeBuy" styleClass="gm-seg, gm-seg-left, gm-seg-pad-wide" text="Buy" />
202 <Button fx:id="tradeSellBtn" onAction="#handleTradeSell" styleClass="gm-seg, gm-seg-right, gm-seg-pad-wide" text="Sell" />
203 </children>
204 </HBox>
205 </children>
206 </VBox>
207 <VBox spacing="5.0">
208 <children>
209 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Shares" />
210 <TextField fx:id="tradeQtyField" prefWidth="96.0" styleClass="gm-textfield, gm-textfield-mono" />
211 </children>
212 </VBox>
213 <VBox spacing="5.0">
214 <children>
215 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Price / share" />
216 <TextField fx:id="tradePriceField" prefWidth="96.0" styleClass="gm-textfield, gm-textfield-mono" />
217 </children>
218 </VBox>
219 <VBox spacing="5.0">
220 <children>
221 <Label styleClass="gm-text-base, gm-font-medium, gm-text-ink2" text="Estimated cost" />
222 <Label fx:id="tradeCostLabel" styleClass="gm-text-lg, gm-font-semibold, gm-font-mono, gm-text-ink" />
223 </children>
224 </VBox>
225 <Button fx:id="tradeSubmitBtn" onAction="#handleTradeSubmit" styleClass="gm-btn, gm-btn-primary" />
226 </children>
227 </FlowPane>
228 <Label fx:id="tradeHintLabel" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" wrapText="true" />
229 </children>
230 </VBox>
231 </children>
232 </VBox>
233 </children>
234 </VBox>
235 </content>
236 </ScrollPane>
237 </children>
238 </VBox>
239 </children>
240</HBox>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/event_list_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/event_list_item.fxml
new file mode 100644
index 0000000..9d82c4a
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/event_list_item.fxml
@@ -0,0 +1,30 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Region?>
7<?import javafx.scene.layout.VBox?>
8
9<fx:root type="javafx.scene.layout.VBox" spacing="5.0" styleClass="gm-list-row" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
10 <padding>
11 <Insets bottom="9.0" left="11.0" right="11.0" top="9.0" />
12 </padding>
13 <children>
14 <HBox alignment="CENTER_LEFT" spacing="6.0">
15 <children>
16 <Label fx:id="numLabel" styleClass="gm-text-xs, gm-font-semibold, gm-text-ink2, gm-font-mono" />
17 <Label fx:id="titleLabel" maxWidth="1.7976931348623157E308" styleClass="gm-text-md, gm-font-semibold, gm-text-ink" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
18 </children>
19 </HBox>
20 <HBox alignment="CENTER_LEFT" spacing="8.0">
21 <children>
22 <Label fx:id="typeLabel" styleClass="gm-text-xs, gm-font-medium, gm-text-ink2" />
23 <Label fx:id="statusLabel" styleClass="gm-pill" />
24 <Label fx:id="feeLabel" minWidth="0.0" styleClass="gm-text-xs, gm-font-medium, gm-text-ink2" textOverrun="ELLIPSIS" />
25 <Region HBox.hgrow="ALWAYS" />
26 <Label fx:id="contractLabel" alignment="CENTER_RIGHT" styleClass="gm-text-xs, gm-font-semibold, gm-font-mono, gm-text-accent" />
27 </children>
28 </HBox>
29 </children>
30</fx:root>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Bold.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Bold.ttf
new file mode 100644
index 0000000..be823bf
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Bold.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Regular.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Regular.ttf
new file mode 100644
index 0000000..013a15b
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/CaskaydiaCoveNerdFont-Regular.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Bold.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Bold.ttf
new file mode 100644
index 0000000..ed37330
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Bold.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Regular.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Regular.ttf
new file mode 100644
index 0000000..3fd04ba
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/FiraCodeNerdFont-Regular.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Bold.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Bold.ttf
new file mode 100644
index 0000000..de2d3b3
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Bold.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Regular.ttf b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Regular.ttf
new file mode 100644
index 0000000..235a07a
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/fonts/JetBrainsMonoNerdFont-Regular.ttf
Binary files differ
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/ladder_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/ladder_item.fxml
new file mode 100644
index 0000000..7516d5b
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/ladder_item.fxml
@@ -0,0 +1,18 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Priority?>
7
8<fx:root type="javafx.scene.layout.HBox" alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-ladder-row" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
9 <padding>
10 <Insets bottom="3.0" left="12.0" right="12.0" top="3.0" />
11 </padding>
12 <children>
13 <Label fx:id="priceLabel" alignment="CENTER_RIGHT" minWidth="54.0" prefWidth="54.0" styleClass="gm-text-xs, gm-font-mono, gm-text-ink2" />
14 <Label fx:id="sideLabel" alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-mono, gm-text-ink2" />
15 <Label fx:id="qtyLabel" alignment="CENTER_RIGHT" minWidth="50.0" prefWidth="50.0" styleClass="gm-text-xs, gm-font-mono, gm-text-ink2" />
16 <Label fx:id="userLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-xs, gm-font-medium, gm-text-ink2" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
17 </children>
18</fx:root>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/participant_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/participant_item.fxml
new file mode 100644
index 0000000..840bacb
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/participant_item.fxml
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Priority?>
7
8<fx:root type="javafx.scene.layout.HBox" alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-divider-top" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
9 <padding>
10 <Insets bottom="7.0" left="11.0" right="11.0" top="7.0" />
11 </padding>
12 <children>
13 <Label fx:id="userLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-sm, gm-font-medium, gm-text-ink" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
14 <Label fx:id="yesLabel" alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-text-sm, gm-font-mono, gm-text-ink2" />
15 <Label fx:id="noLabel" alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-text-sm, gm-font-mono, gm-text-ink2" />
16 <Label fx:id="valueLabel" alignment="CENTER_RIGHT" minWidth="96.0" prefWidth="96.0" styleClass="gm-text-sm, gm-font-mono, gm-text-ink2" />
17 <Label fx:id="feesLabel" alignment="CENTER_RIGHT" minWidth="96.0" prefWidth="96.0" styleClass="gm-text-sm, gm-font-mono, gm-text-ink2" />
18 </children>
19</fx:root>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/theme.css b/ui-desktop/src/main/resources/market/guess/ui/desktop/theme.css
new file mode 100644
index 0000000..f2616a3
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/theme.css
@@ -0,0 +1,926 @@
1/* Guess Market desktop UI stylesheet.
2 *
3 * PALETTES & TYPOGRAPHY:
4 * Each skin class (.gm-skin-*) defines its own looked-up color variables (-gm-*)
5 * and root font-family. AppView puts exactly one skin class on the scene root,
6 * allowing all child rules to automatically cascade and re-resolve without
7 * requiring any inline CSS or manual style-string construction in Java.
8 *
9 * BUNDLED NERD FONTS:
10 * - Rosé Pine Dawn -> CaskaydiaCove Nerd Font (CaskaydiaCove NF)
11 * - Catppuccin -> JetBrainsMono Nerd Font (JetBrainsMono NF)
12 * - Gruvbox -> FiraCode Nerd Font (FiraCode Nerd Font)
13 */
14
15@font-face {
16 font-family: 'CaskaydiaCove NF';
17 src: url('fonts/CaskaydiaCoveNerdFont-Regular.ttf');
18}
19@font-face {
20 font-family: 'CaskaydiaCove NF';
21 font-weight: bold;
22 src: url('fonts/CaskaydiaCoveNerdFont-Bold.ttf');
23}
24
25@font-face {
26 font-family: 'JetBrainsMono NF';
27 src: url('fonts/JetBrainsMonoNerdFont-Regular.ttf');
28}
29@font-face {
30 font-family: 'JetBrainsMono NF';
31 font-weight: bold;
32 src: url('fonts/JetBrainsMonoNerdFont-Bold.ttf');
33}
34
35@font-face {
36 font-family: 'FiraCode Nerd Font';
37 src: url('fonts/FiraCodeNerdFont-Regular.ttf');
38}
39@font-face {
40 font-family: 'FiraCode Nerd Font';
41 font-weight: bold;
42 src: url('fonts/FiraCodeNerdFont-Bold.ttf');
43}
44
45/* rose-pine.dev/palette/#dawn — base/surface/overlay/highlight, iris accent, pine/love for yes/no */
46.gm-root,
47.gm-root:skin-rose-pine-dawn,
48.gm-skin-rose-pine-dawn {
49 -fx-font-family: "CaskaydiaCove NF", "CaskaydiaCove Nerd Font", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
50 -fx-font-size: 13px;
51 -gm-bg: #faf4ed;
52 -gm-panel: #fffaf3;
53 -gm-panel2: #f2e9e1;
54 -gm-panel3: #dfdad9;
55 -gm-line: #cecacd;
56 -gm-ink: #575279;
57 -gm-ink2: #797593;
58 -gm-accent: #907aa9;
59 -gm-accent-fg: #fffaf3;
60 -gm-btn: #f2e9e1;
61 -gm-btn-line: #cecacd;
62 -gm-yes: #286983;
63 -gm-no: #b4637a;
64 -gm-yes-soft: #e3edf0;
65 -gm-no-soft: #f5e6ea;
66}
67
68/* catppuccin.com Mocha — mantle/base/surface, mauve accent, green/red for yes/no */
69.gm-root:skin-catppuccin,
70.gm-skin-catppuccin {
71 -fx-font-family: "JetBrainsMono NF", "JetBrainsMono Nerd Font", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
72 -fx-font-size: 13px;
73 -gm-bg: #181825;
74 -gm-panel: #1e1e2e;
75 -gm-panel2: #313244;
76 -gm-panel3: #45475a;
77 -gm-line: #585b70;
78 -gm-ink: #cdd6f4;
79 -gm-ink2: #a6adc8;
80 -gm-accent: #cba6f7;
81 -gm-accent-fg: #1e1e2e;
82 -gm-btn: #313244;
83 -gm-btn-line: #585b70;
84 -gm-yes: #a6e3a1;
85 -gm-no: #f38ba8;
86 -gm-yes-soft: #23312a;
87 -gm-no-soft: #34232c;
88}
89
90/* gruvbox dark (hard) — bg0_h/bg0/bg1/bg2, bright orange accent, bright green/red */
91.gm-root:skin-gruvbox,
92.gm-skin-gruvbox {
93 -fx-font-family: "FiraCode Nerd Font", "FiraCode NF", Consolas, "Liberation Mono", Menlo, monospace;
94 -fx-font-size: 13.5px;
95 -gm-bg: #1d2021;
96 -gm-panel: #282828;
97 -gm-panel2: #3c3836;
98 -gm-panel3: #504945;
99 -gm-line: #665c54;
100 -gm-ink: #ebdbb2;
101 -gm-ink2: #a89984;
102 -gm-accent: #fe8019;
103 -gm-accent-fg: #1d2021;
104 -gm-btn: #3c3836;
105 -gm-btn-line: #665c54;
106 -gm-yes: #b8bb26;
107 -gm-no: #fb4934;
108 -gm-yes-soft: #2b3021;
109 -gm-no-soft: #3b2320;
110}
111
112/* ---- typography & text fills ------------------------------------------ */
113
114.root {
115 -fx-text-fill: -gm-ink;
116}
117
118.gm-text-ink { -fx-text-fill: -gm-ink; }
119.gm-text-ink2 { -fx-text-fill: -gm-ink2; }
120.gm-text-accent { -fx-text-fill: -gm-accent; }
121.gm-text-accent-fg { -fx-text-fill: -gm-accent-fg; }
122.gm-text-yes { -fx-text-fill: -gm-yes; }
123.gm-text-no { -fx-text-fill: -gm-no; }
124
125.gm-font-mono,
126.gm-textfield-mono,
127.gm-pill,
128.gm-user-balance,
129.gm-balance-cell,
130.gm-pnl-cell,
131.gm-chart-axis,
132.gm-anim-tick {
133 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
134}
135
136.gm-root:skin-rose-pine-dawn .gm-font-mono,
137.gm-skin-rose-pine-dawn .gm-font-mono,
138.gm-root:skin-rose-pine-dawn .gm-textfield-mono,
139.gm-skin-rose-pine-dawn .gm-textfield-mono,
140.gm-root:skin-rose-pine-dawn .gm-pill,
141.gm-skin-rose-pine-dawn .gm-pill,
142.gm-root:skin-rose-pine-dawn .gm-user-balance,
143.gm-skin-rose-pine-dawn .gm-user-balance,
144.gm-root:skin-rose-pine-dawn .gm-balance-cell,
145.gm-skin-rose-pine-dawn .gm-balance-cell,
146.gm-root:skin-rose-pine-dawn .gm-pnl-cell,
147.gm-skin-rose-pine-dawn .gm-pnl-cell,
148.gm-root:skin-rose-pine-dawn .gm-chart-axis,
149.gm-skin-rose-pine-dawn .gm-chart-axis,
150.gm-root:skin-rose-pine-dawn .gm-anim-tick,
151.gm-skin-rose-pine-dawn .gm-anim-tick {
152 -fx-font-family: "CaskaydiaCove NF", "CaskaydiaCove Nerd Font", monospace;
153}
154
155.gm-root:skin-catppuccin .gm-font-mono,
156.gm-skin-catppuccin .gm-font-mono,
157.gm-root:skin-catppuccin .gm-textfield-mono,
158.gm-skin-catppuccin .gm-textfield-mono,
159.gm-root:skin-catppuccin .gm-pill,
160.gm-skin-catppuccin .gm-pill,
161.gm-root:skin-catppuccin .gm-user-balance,
162.gm-skin-catppuccin .gm-user-balance,
163.gm-root:skin-catppuccin .gm-balance-cell,
164.gm-skin-catppuccin .gm-balance-cell,
165.gm-root:skin-catppuccin .gm-pnl-cell,
166.gm-skin-catppuccin .gm-pnl-cell,
167.gm-root:skin-catppuccin .gm-chart-axis,
168.gm-skin-catppuccin .gm-chart-axis,
169.gm-root:skin-catppuccin .gm-anim-tick,
170.gm-skin-catppuccin .gm-anim-tick {
171 -fx-font-family: "JetBrainsMono NF", "JetBrainsMono Nerd Font", monospace;
172}
173
174.gm-root:skin-gruvbox .gm-font-mono,
175.gm-skin-gruvbox .gm-font-mono,
176.gm-root:skin-gruvbox .gm-textfield-mono,
177.gm-skin-gruvbox .gm-textfield-mono,
178.gm-root:skin-gruvbox .gm-pill,
179.gm-skin-gruvbox .gm-pill,
180.gm-root:skin-gruvbox .gm-user-balance,
181.gm-skin-gruvbox .gm-user-balance,
182.gm-root:skin-gruvbox .gm-balance-cell,
183.gm-skin-gruvbox .gm-balance-cell,
184.gm-root:skin-gruvbox .gm-pnl-cell,
185.gm-skin-gruvbox .gm-pnl-cell,
186.gm-root:skin-gruvbox .gm-chart-axis,
187.gm-skin-gruvbox .gm-chart-axis,
188.gm-root:skin-gruvbox .gm-anim-tick,
189.gm-skin-gruvbox .gm-anim-tick {
190 -fx-font-family: "FiraCode Nerd Font", "FiraCode NF", monospace;
191}
192.gm-font-bold { -fx-font-weight: 700; }
193.gm-font-semibold { -fx-font-weight: 600; }
194.gm-font-medium { -fx-font-weight: 500; }
195.gm-font-regular { -fx-font-weight: 400; }
196
197.gm-text-xs { -fx-font-size: 10.5px; }
198.gm-text-sm { -fx-font-size: 11.5px; }
199.gm-text-base { -fx-font-size: 12.5px; }
200.gm-text-md { -fx-font-size: 13px; }
201.gm-text-lg { -fx-font-size: 14px; }
202.gm-text-xl { -fx-font-size: 17px; }
203.gm-text-2xl { -fx-font-size: 22px; }
204
205/* ---- window chrome & containers --------------------------------------- */
206
207.gm-chrome {
208 -fx-background-color: -gm-bg;
209}
210
211.gm-bg-panel {
212 -fx-background-color: -gm-panel;
213}
214
215.gm-bg-panel2 {
216 -fx-background-color: -gm-panel2;
217}
218
219.gm-bg-panel3 {
220 -fx-background-color: -gm-panel3;
221}
222
223.gm-card {
224 -fx-background-color: -gm-panel;
225 -fx-border-color: -gm-line;
226 -fx-border-width: 1;
227 -fx-background-radius: 7;
228 -fx-border-radius: 7;
229}
230
231.gm-card-panel2 {
232 -fx-background-color: -gm-panel2;
233 -fx-border-color: -gm-line;
234 -fx-border-width: 1;
235 -fx-background-radius: 6;
236 -fx-border-radius: 6;
237}
238
239.gm-card-panel {
240 -fx-background-color: -gm-panel;
241 -fx-border-color: -gm-line;
242 -fx-border-width: 1;
243 -fx-background-radius: 6;
244 -fx-border-radius: 6;
245}
246
247.gm-card-soft-yes {
248 -fx-background-color: -gm-yes-soft;
249 -fx-border-color: -gm-line;
250 -fx-border-width: 1;
251 -fx-background-radius: 6;
252 -fx-border-radius: 6;
253}
254
255.gm-card-soft-no {
256 -fx-background-color: -gm-no-soft;
257 -fx-border-color: -gm-line;
258 -fx-border-width: 1;
259 -fx-background-radius: 6;
260 -fx-border-radius: 6;
261}
262
263.gm-banner-blocked {
264 -fx-background-color: -gm-no-soft;
265 -fx-border-color: -gm-no;
266 -fx-border-width: 1;
267 -fx-background-radius: 6;
268 -fx-border-radius: 6;
269}
270
271.gm-banner-resolved {
272 -fx-background-color: -gm-yes-soft;
273 -fx-border-color: -gm-line;
274 -fx-border-width: 1;
275 -fx-background-radius: 6;
276 -fx-border-radius: 6;
277}
278
279.gm-divider-bottom {
280 -fx-border-color: transparent transparent -gm-line transparent;
281 -fx-border-width: 0 0 1 0;
282}
283
284.gm-divider-top {
285 -fx-border-color: -gm-line transparent transparent transparent;
286 -fx-border-width: 1 0 0 0;
287}
288
289.gm-hline {
290 -fx-background-color: -gm-line;
291 -fx-pref-height: 1;
292 -fx-min-height: 1;
293}
294
295/* ---- buttons & interactive controls ----------------------------------- */
296
297.gm-btn {
298 -fx-border-width: 1;
299 -fx-background-radius: 5;
300 -fx-border-radius: 5;
301 -fx-font-size: 13px;
302 -fx-font-weight: 600;
303 -fx-padding: 8 15;
304 -fx-cursor: hand;
305}
306
307.gm-btn:hover {
308 -fx-opacity: 0.92;
309}
310
311.gm-btn:disabled {
312 -fx-opacity: 0.45;
313 -fx-cursor: default;
314}
315
316.gm-btn-primary {
317 -fx-background-color: -gm-accent;
318 -fx-text-fill: -gm-accent-fg;
319 -fx-border-color: -gm-accent;
320}
321
322.gm-btn-secondary {
323 -fx-background-color: -gm-btn;
324 -fx-text-fill: -gm-ink;
325 -fx-border-color: -gm-btn-line;
326}
327
328.gm-btn-destructive {
329 -fx-background-color: -gm-no;
330 -fx-text-fill: -gm-accent-fg;
331 -fx-border-color: -gm-no;
332 -fx-border-width: 1;
333 -fx-background-radius: 5;
334 -fx-border-radius: 5;
335 -fx-font-size: 12.5px;
336 -fx-font-weight: 600;
337 -fx-padding: 9 17;
338 -fx-cursor: hand;
339}
340
341.gm-btn-destructive:disabled {
342 -fx-opacity: 0.5;
343 -fx-cursor: default;
344}
345
346.gm-app-scroll,
347.gm-app-scroll > .viewport {
348 -fx-background-color: transparent;
349 -fx-background-insets: 0;
350 -fx-padding: 0;
351}
352
353.gm-tabs > .tab-header-area {
354 -fx-padding: 6 16 0 16;
355}
356
357.gm-tabs > .tab-header-area > .tab-header-background {
358 -fx-background-color: -gm-line, -gm-panel;
359 -fx-background-insets: 0, 0 0 1 0;
360}
361
362.gm-tabs > .tab-content-area {
363 -fx-background-color: transparent;
364}
365
366.gm-tabs > .tab-header-area > .headers-region > .tab {
367 -fx-background-color: -gm-panel2;
368 -fx-background-insets: 0 1 0 1;
369 -fx-border-color: -gm-line;
370 -fx-border-width: 1 1 0 1;
371 -fx-border-insets: 0 1 0 1;
372 -fx-background-radius: 6 6 0 0;
373 -fx-border-radius: 6 6 0 0;
374 -fx-padding: 9 20;
375 -fx-cursor: hand;
376}
377
378.gm-tabs > .tab-header-area > .headers-region > .tab:selected {
379 -fx-background-color: -gm-bg;
380}
381
382.gm-tabs > .tab-header-area > .headers-region > .tab .tab-label {
383 -fx-text-fill: -gm-ink2;
384 -fx-font-size: 13px;
385 -fx-font-weight: 600;
386}
387
388.gm-tabs > .tab-header-area > .headers-region > .tab:selected .tab-label {
389 -fx-text-fill: -gm-ink;
390}
391
392.gm-tabs > .tab-header-area > .headers-region > .tab:selected .focus-indicator {
393 -fx-border-color: transparent;
394}
395
396.gm-toggle {
397 -fx-background-color: -gm-btn;
398 -fx-text-fill: -gm-ink2;
399 -fx-border-color: -gm-btn-line;
400 -fx-border-width: 1;
401 -fx-background-radius: 4;
402 -fx-border-radius: 4;
403 -fx-font-size: 12px;
404 -fx-font-weight: 500;
405 -fx-padding: 5 11;
406 -fx-cursor: hand;
407}
408
409.gm-toggle:selected {
410 -fx-background-color: -gm-accent;
411 -fx-text-fill: -gm-accent-fg;
412 -fx-border-color: -gm-accent;
413}
414
415.gm-seg {
416 -fx-background-color: -gm-btn;
417 -fx-text-fill: -gm-ink;
418 -fx-border-color: -gm-btn-line;
419 -fx-border-width: 1;
420 -fx-font-size: 12px;
421 -fx-font-weight: 600;
422 -fx-cursor: hand;
423}
424
425.gm-seg:selected {
426 -fx-background-color: -gm-accent;
427 -fx-text-fill: -gm-accent-fg;
428}
429
430.gm-seg:disabled {
431 -fx-opacity: 0.45;
432 -fx-cursor: default;
433}
434
435.gm-seg-left {
436 -fx-background-radius: 5 0 0 5;
437 -fx-border-radius: 5 0 0 5;
438}
439
440.gm-seg-right {
441 -fx-background-radius: 0 5 5 0;
442 -fx-border-radius: 0 5 5 0;
443}
444
445.gm-seg-pad-tight {
446 -fx-padding: 8 0;
447}
448
449.gm-seg-pad-wide {
450 -fx-padding: 8 15;
451}
452
453.gm-textfield {
454 -fx-background-color: -gm-panel2;
455 -fx-border-color: -gm-btn-line;
456 -fx-border-width: 1;
457 -fx-background-radius: 5;
458 -fx-border-radius: 5;
459 -fx-font-size: 13px;
460 -fx-text-fill: -gm-ink;
461 -fx-padding: 8 10;
462}
463
464.gm-textfield:disabled {
465 -fx-opacity: 0.45;
466}
467
468.gm-textfield:error,
469.gm-textfield.error {
470 -fx-border-color: -gm-no;
471 -fx-border-width: 1.5;
472}
473
474.gm-textfield-mono {
475 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
476}
477
478.gm-textarea {
479 -fx-control-inner-background: -gm-panel2;
480 -fx-border-color: -gm-btn-line;
481 -fx-border-radius: 5;
482 -fx-background-radius: 5;
483 -fx-font-size: 13px;
484 -fx-text-fill: -gm-ink;
485}
486
487.gm-select-base {
488 -fx-border-color: -gm-btn-line;
489 -fx-border-radius: 5;
490 -fx-background-radius: 5;
491 -fx-font-size: 12.5px;
492 -fx-text-base-color: -gm-ink;
493}
494
495.gm-select-btn-bg {
496 -fx-background-color: -gm-btn;
497}
498
499.gm-select-panel2-bg {
500 -fx-background-color: -gm-panel2;
501}
502
503.gm-checkbox {
504 -fx-text-fill: -gm-ink2;
505 -fx-font-size: 12.5px;
506}
507
508.gm-checkbox-strong {
509 -fx-text-fill: -gm-ink;
510 -fx-font-size: 12.5px;
511}
512
513.gm-link-button {
514 -fx-background-color: transparent;
515 -fx-text-fill: -gm-ink2;
516 -fx-font-size: 14.5px;
517 -fx-underline: false;
518 -fx-cursor: hand;
519 -fx-border-width: 0;
520}
521
522.gm-toast {
523 -fx-background-color: -gm-ink;
524 -fx-text-fill: -gm-bg;
525 -fx-background-radius: 6;
526 -fx-padding: 10 16;
527 -fx-font-size: 12.5px;
528 -fx-font-weight: 600;
529}
530
531.gm-scroll-transparent {
532 -fx-background-color: transparent;
533 -fx-background: transparent;
534}
535
536.gm-scroll-transparent > .viewport {
537 -fx-background-color: transparent;
538}
539
540/* ---- badges, pills, traffic lights ------------------------------------ */
541
542.gm-pill {
543 -fx-background-radius: 3;
544 -fx-padding: 3 6;
545 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
546 -fx-font-size: 10px;
547 -fx-font-weight: 600;
548 -fx-background-color: -gm-panel3;
549 -fx-text-fill: -gm-ink2;
550}
551
552/* Pseudo-class states for pills */
553.gm-pill:active { -fx-background-color: -gm-yes-soft; -fx-text-fill: -gm-yes; }
554.gm-pill:closed { -fx-background-color: -gm-no-soft; -fx-text-fill: -gm-no; }
555.gm-pill:idle { -fx-background-color: -gm-panel3; -fx-text-fill: -gm-ink2; }
556.gm-pill:blocked { -fx-background-color: -gm-no; -fx-text-fill: -gm-accent-fg; }
557.gm-pill:mm { -fx-background-color: -gm-accent; -fx-text-fill: -gm-accent-fg; }
558.gm-pill:trader { -fx-background-color: -gm-panel3; -fx-text-fill: -gm-ink2; }
559.gm-pill:resolved { -fx-background-color: -gm-yes; -fx-text-fill: -gm-accent-fg; }
560
561.gm-pill-active { -fx-background-color: -gm-yes-soft; -fx-text-fill: -gm-yes; }
562.gm-pill-closed { -fx-background-color: -gm-no-soft; -fx-text-fill: -gm-no; }
563.gm-pill-idle { -fx-background-color: -gm-panel3; -fx-text-fill: -gm-ink2; }
564.gm-pill-blocked { -fx-background-color: -gm-no; -fx-text-fill: -gm-accent-fg; }
565.gm-pill-mm { -fx-background-color: -gm-accent; -fx-text-fill: -gm-accent-fg; }
566.gm-pill-trader { -fx-background-color: -gm-panel3; -fx-text-fill: -gm-ink2; }
567.gm-pill-resolved { -fx-background-color: -gm-yes; -fx-text-fill: -gm-accent-fg; }
568
569/* ---- user balance ---------------------------------------------------- */
570.gm-user-balance {
571 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
572 -fx-font-size: 22px;
573 -fx-font-weight: 600;
574 -fx-text-fill: -gm-accent;
575}
576
577.gm-user-balance:negative {
578 -fx-text-fill: -gm-no;
579}
580
581/* ---- traffic lights with macOS on-hover symbols ---------------------- */
582
583.gm-traffic-lights {
584 -fx-alignment: center-left;
585}
586
587.gm-traffic-dot {
588 -fx-min-width: 12px;
589 -fx-min-height: 12px;
590 -fx-pref-width: 12px;
591 -fx-pref-height: 12px;
592 -fx-max-width: 12px;
593 -fx-max-height: 12px;
594 -fx-background-radius: 999px;
595 -fx-alignment: center;
596 -fx-cursor: hand;
597}
598
599.gm-traffic-icon {
600 -fx-fill: transparent;
601 -fx-stroke: transparent;
602 -fx-stroke-width: 1.1;
603 -fx-stroke-line-cap: round;
604}
605
606/* Reveal glyphs on traffic lights cluster hover */
607.gm-traffic-lights:hover .gm-traffic-icon {
608 -fx-stroke: rgba(0, 0, 0, 0.68);
609}
610
611.gm-traffic-dot:hover { -fx-opacity: 0.85; }
612.gm-traffic-dot:pressed { -fx-opacity: 0.70; }
613
614.gm-traffic-dot-no { -fx-background-color: -gm-no; }
615.gm-traffic-dot-accent { -fx-background-color: -gm-accent; }
616.gm-traffic-dot-yes { -fx-background-color: -gm-yes; }
617
618/* ---- list rows, tables & option cards --------------------------------- */
619
620.gm-balance-cell {
621 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
622 -fx-font-size: 13px;
623 -fx-font-weight: 600;
624 -fx-text-fill: -gm-accent;
625}
626.gm-balance-cell:negative {
627 -fx-text-fill: -gm-no;
628}
629
630.gm-pnl-cell {
631 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
632 -fx-font-size: 12px;
633 -fx-font-weight: 600;
634 -fx-text-fill: -gm-yes;
635}
636.gm-pnl-cell:negative {
637 -fx-text-fill: -gm-no;
638}
639
640.gm-list-view {
641 -fx-background-color: transparent;
642 -fx-background-insets: 0;
643 -fx-padding: 0;
644 -fx-border-color: transparent;
645 -fx-border-width: 0;
646}
647
648.gm-list-view .list-cell {
649 -fx-background-color: transparent;
650 -fx-background-insets: 0;
651 -fx-padding: 1 0;
652}
653
654.gm-list-view .list-cell:empty {
655 -fx-background-color: transparent;
656}
657
658.gm-list-view .list-cell:filled:selected {
659 -fx-background-color: transparent;
660}
661
662.gm-list-view:focused .list-cell:filled:focused:selected {
663 -fx-background-color: transparent;
664}
665
666.gm-list-row {
667 -fx-background-color: transparent;
668 -fx-border-color: transparent;
669 -fx-border-width: 0 0 0 3;
670 -fx-background-radius: 5;
671 -fx-cursor: hand;
672}
673
674.gm-list-row:hover {
675 -fx-background-color: -gm-panel2;
676}
677
678.gm-list-row:selected {
679 -fx-background-color: -gm-panel3;
680 -fx-border-color: -gm-accent;
681}
682
683.gm-ladder-row {
684 -fx-border-color: -gm-line transparent transparent transparent;
685 -fx-border-width: 1 0 0 0;
686}
687
688.gm-ladder-row:bid,
689.gm-ladder-row-bid {
690 -fx-background-color: -gm-yes-soft;
691}
692
693.gm-ladder-row:ask,
694.gm-ladder-row-ask {
695 -fx-background-color: -gm-no-soft;
696}
697
698.gm-participation-row {
699 -fx-border-color: -gm-line transparent transparent transparent;
700 -fx-border-width: 1 0 0 0;
701 -fx-cursor: hand;
702}
703
704.gm-participation-row:hover {
705 -fx-background-color: -gm-panel2;
706}
707
708.gm-participation-row:selected {
709 -fx-background-color: -gm-panel3;
710}
711
712.gm-option-card {
713 -fx-background-radius: 6;
714 -fx-border-radius: 6;
715 -fx-cursor: hand;
716 -fx-background-color: -gm-panel;
717 -fx-border-color: -gm-line;
718 -fx-border-width: 1;
719}
720
721.gm-option-card-yes:selected {
722 -fx-background-color: -gm-yes-soft;
723 -fx-border-color: -gm-yes;
724 -fx-border-width: 1.5;
725}
726
727.gm-option-card-no:selected {
728 -fx-background-color: -gm-no-soft;
729 -fx-border-color: -gm-no;
730 -fx-border-width: 1.5;
731}
732
733/* ---- modals & dialogs ------------------------------------------------- */
734
735.gm-modal-scrim {
736 -fx-background-color: rgba(10, 10, 10, 0.42);
737}
738
739.gm-modal-card {
740 -fx-background-color: -gm-panel;
741 -fx-background: -gm-panel;
742 -fx-background-radius: 8;
743 -fx-border-radius: 8;
744 -fx-border-color: -gm-line;
745}
746
747.gm-resolve-option {
748 -fx-border-width: 1;
749 -fx-background-radius: 6;
750 -fx-border-radius: 6;
751 -fx-font-size: 14px;
752 -fx-font-weight: 700;
753 -fx-padding: 14 0;
754 -fx-cursor: hand;
755 -fx-background-color: -gm-panel2;
756 -fx-border-color: -gm-line;
757}
758
759.gm-resolve-option-yes {
760 -fx-text-fill: -gm-yes;
761}
762
763.gm-resolve-option-yes:selected {
764 -fx-background-color: -gm-yes-soft;
765 -fx-border-color: -gm-yes;
766 -fx-border-width: 1.5;
767}
768
769.gm-resolve-option-no {
770 -fx-text-fill: -gm-no;
771}
772
773.gm-resolve-option-no:selected {
774 -fx-background-color: -gm-no-soft;
775 -fx-border-color: -gm-no;
776 -fx-border-width: 1.5;
777}
778
779/* ---- progress bars ---------------------------------------------------- */
780
781.gm-progress {
782 -fx-control-inner-background: -gm-panel3;
783}
784
785.gm-progress > .track {
786 -fx-background-color: -gm-panel3;
787 -fx-background-insets: 0;
788 -fx-background-radius: 3px;
789 -fx-padding: 0;
790}
791
792.gm-progress > .bar {
793 -fx-background-insets: 0;
794 -fx-background-radius: 3px;
795 -fx-padding: 0;
796}
797
798.gm-progress-accent > .bar {
799 -fx-background-color: -gm-accent;
800}
801
802.gm-progress-yes > .bar {
803 -fx-background-color: -gm-yes;
804}
805
806.gm-progress-no > .bar {
807 -fx-background-color: -gm-no;
808}
809
810/* ---- charts ----------------------------------------------------------- */
811
812.gm-chart {
813 -fx-background-color: transparent;
814}
815
816.gm-chart-axis {
817 -fx-tick-label-fill: -gm-ink2;
818 -fx-tick-mark-stroke: -gm-ink2;
819 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
820 -fx-font-size: 10px;
821}
822
823.gm-chart-axis .axis-tick-mark,
824.gm-chart-axis .axis-minor-tick-mark {
825 -fx-fill: null;
826 -fx-stroke: -gm-ink2;
827}
828
829.gm-chart-axis:bottom {
830 -fx-border-color: -gm-line transparent transparent transparent;
831}
832
833.gm-chart-axis:left {
834 -fx-border-color: transparent -gm-line transparent transparent;
835}
836
837.gm-chart .chart-line-symbol {
838 -fx-background-color: transparent, transparent;
839 -fx-background-radius: 0;
840 -fx-padding: 0;
841}
842
843.gm-chart .chart-series-line {
844 -fx-stroke-width: 2.5px;
845}
846
847.gm-chart-single .series0.chart-series-line {
848 -fx-stroke: -gm-accent;
849}
850
851.gm-chart-dual .series0.chart-series-line {
852 -fx-stroke: -gm-yes;
853}
854
855.gm-chart-dual .series1.chart-series-line {
856 -fx-stroke: -gm-no;
857}
858
859
860/* ---- decorative animations (see Anim.java) ---------------------------- */
861
862.gm-anim-rule { -fx-stroke: -gm-line; }
863
864.gm-anim-tick {
865 -fx-fill: -gm-ink2;
866 -fx-font-family: "CaskaydiaCove NF", "JetBrainsMono NF", "FiraCode Nerd Font", monospace;
867 -fx-font-size: 9px;
868}
869
870.gm-anim-curve-yes { -fx-stroke: -gm-yes; }
871.gm-anim-curve-no { -fx-stroke: -gm-no; }
872.gm-anim-dot-yes { -fx-fill: -gm-yes; }
873.gm-anim-dot-no { -fx-fill: -gm-no; }
874
875/* LIVE pill: bars and label take the pill's status colour */
876.gm-live-pill { -fx-padding: 3 7; }
877
878.gm-anim-bar { -fx-fill: -gm-ink2; }
879.gm-live-label { -fx-text-fill: -gm-ink2; }
880
881.gm-pill:active .gm-anim-bar { -fx-fill: -gm-yes; }
882.gm-pill:active .gm-live-label { -fx-text-fill: -gm-yes; }
883.gm-pill:closed .gm-anim-bar { -fx-fill: -gm-no; }
884.gm-pill:closed .gm-live-label { -fx-text-fill: -gm-no; }
885
886/* Balance sparkline: stroke follows the sign of the balance */
887.gm-anim-spark { -fx-stroke: -gm-accent; }
888.gm-anim-spark-dot { -fx-fill: -gm-accent; }
889
890.gm-anim-sparkline:negative .gm-anim-spark { -fx-stroke: -gm-no; }
891.gm-anim-sparkline:negative .gm-anim-spark-dot { -fx-fill: -gm-no; }
892
893/* Animation toggle button & spinner */
894.gm-btn-icon {
895 -fx-padding: 4 8;
896 -fx-min-width: 34px;
897 -fx-min-height: 30px;
898 -fx-pref-height: 30px;
899 -fx-alignment: center;
900}
901
902.gm-btn-icon:selected {
903 -fx-background-color: -gm-panel3;
904 -fx-border-color: -gm-accent;
905}
906
907.gm-anim-spinner {
908 -fx-fill: -gm-ink2;
909}
910
911.gm-anim-spinner-hub {
912 -fx-fill: -gm-panel;
913 -fx-stroke: -gm-ink2;
914 -fx-stroke-width: 1;
915}
916
917.gm-btn-icon:selected .gm-anim-spinner {
918 -fx-fill: -gm-accent;
919}
920
921.gm-btn-icon:selected .gm-anim-spinner-hub {
922 -fx-fill: -gm-panel;
923 -fx-stroke: -gm-accent;
924 -fx-stroke-width: 1;
925}
926
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/trade_history_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/trade_history_item.fxml
new file mode 100644
index 0000000..2a2bf92
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/trade_history_item.fxml
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Priority?>
7
8<fx:root type="javafx.scene.layout.HBox" alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-divider-top" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
9 <padding>
10 <Insets bottom="7.0" left="11.0" right="11.0" top="7.0" />
11 </padding>
12 <children>
13 <Label fx:id="numLabel" minWidth="66.0" prefWidth="66.0" styleClass="gm-text-sm, gm-font-semibold, gm-text-ink2, gm-font-mono" />
14 <Label fx:id="userLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-sm, gm-font-medium, gm-text-ink" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
15 <Label fx:id="optionLabel" minWidth="76.0" prefWidth="76.0" styleClass="gm-text-sm, gm-font-bold" />
16 <Label fx:id="sharesLabel" alignment="CENTER_RIGHT" minWidth="92.0" prefWidth="92.0" styleClass="gm-text-sm, gm-font-mono" />
17 <Label fx:id="paidLabel" alignment="CENTER_RIGHT" minWidth="88.0" prefWidth="88.0" styleClass="gm-text-sm, gm-font-semibold, gm-font-mono, gm-text-accent" />
18 </children>
19</fx:root>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/user_event_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/user_event_item.fxml
new file mode 100644
index 0000000..93631a1
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/user_event_item.fxml
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Priority?>
7
8<fx:root type="javafx.scene.layout.HBox" alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-participation-row" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
9 <padding>
10 <Insets bottom="8.0" left="11.0" right="11.0" top="8.0" />
11 </padding>
12 <children>
13 <Label fx:id="nameLabel" maxWidth="1.7976931348623157E308" minWidth="0.0" styleClass="gm-text-sm, gm-font-medium, gm-text-ink" textOverrun="ELLIPSIS" HBox.hgrow="ALWAYS" />
14 <!-- Sized for the longest values ("Market Maker", "Order Book") in every skin's mono font; never shrinks. -->
15 <Label fx:id="roleLabel" minWidth="-Infinity" prefWidth="92.0" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
16 <Label fx:id="typeLabel" minWidth="-Infinity" prefWidth="78.0" styleClass="gm-text-sm, gm-font-regular, gm-text-ink2" />
17 <Label fx:id="yesLabel" alignment="CENTER_RIGHT" minWidth="78.0" prefWidth="78.0" styleClass="gm-text-sm, gm-font-mono" />
18 <Label fx:id="noLabel" alignment="CENTER_RIGHT" minWidth="78.0" prefWidth="78.0" styleClass="gm-text-sm, gm-font-mono" />
19 <Label fx:id="plLabel" alignment="CENTER_RIGHT" minWidth="90.0" prefWidth="90.0" styleClass="gm-pnl-cell" />
20 </children>
21</fx:root>
diff --git a/ui-desktop/src/main/resources/market/guess/ui/desktop/user_list_item.fxml b/ui-desktop/src/main/resources/market/guess/ui/desktop/user_list_item.fxml
new file mode 100644
index 0000000..dec7706
--- /dev/null
+++ b/ui-desktop/src/main/resources/market/guess/ui/desktop/user_list_item.fxml
@@ -0,0 +1,22 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<?import javafx.geometry.Insets?>
4<?import javafx.scene.control.Label?>
5<?import javafx.scene.layout.HBox?>
6<?import javafx.scene.layout.Priority?>
7<?import javafx.scene.layout.VBox?>
8
9<fx:root type="javafx.scene.layout.HBox" alignment="CENTER_LEFT" spacing="8.0" styleClass="gm-list-row" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
10 <padding>
11 <Insets bottom="9.0" left="11.0" right="11.0" top="9.0" />
12 </padding>
13 <children>
14 <VBox maxWidth="1.7976931348623157E308" minWidth="0.0" spacing="3.0" HBox.hgrow="ALWAYS">
15 <children>
16 <Label fx:id="nameLabel" styleClass="gm-text-md, gm-font-semibold, gm-text-ink" />
17 <Label fx:id="roleLabel" styleClass="gm-text-xs, gm-font-regular, gm-text-ink2" />
18 </children>
19 </VBox>
20 <Label fx:id="balanceLabel" alignment="CENTER_RIGHT" minWidth="84.0" prefWidth="84.0" styleClass="gm-balance-cell" />
21 </children>
22</fx:root>