lexgui 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/demo.js CHANGED
@@ -5,21 +5,21 @@ import 'lexgui/components/audio.js';
5
5
 
6
6
  window.LX = LX;
7
7
 
8
- let area = LX.init( { strictViewport: false } );
8
+ const area = LX.init( { strictViewport: false, rootClass: "wrapper" } );
9
9
 
10
10
  // Menubar
11
11
  {
12
12
  area.addMenubar( m => {
13
-
13
+
14
14
  m.setButtonImage("lexgui.js", "images/icon.png", () => {window.open("https://jxarco.github.io/lexgui.js/")}, {float: "left"})
15
-
15
+
16
16
  m.add( "Docs", { icon: "fa-solid fa-magnifying-glass", short: "F1", callback: () => { window.open("./docs/") }});
17
-
17
+
18
18
  const commandButton = new LX.Button(null, "Search command...", () => { LX.setCommandbarState( true ) }, {
19
19
  width: "256px", className: "right", buttonClass: "outline left fg-tertiary bg-secondary" }
20
20
  );
21
21
  m.root.appendChild( commandButton.root );
22
-
22
+
23
23
  m.addButtons( [
24
24
  {
25
25
  title: "Github",
@@ -40,40 +40,379 @@ let area = LX.init( { strictViewport: false } );
40
40
 
41
41
  // Header
42
42
  {
43
- const header = LX.makeContainer( [ null, "auto" ], "col border gap-2 p-8" );
44
-
45
- header.innerHTML = `
43
+ const header = LX.makeContainer( [ null, "auto" ], "flex flex-col border-top border-bottom gap-2 px-6 py-12", `
46
44
  <a>Get started with LexGUI.js</a>
47
45
  <h1>Build your application interface</h1>
48
- <p style="max-width:32rem">A set of beautifully-designed, accessible widgets and components.
46
+ <p class="font-light" style="max-width:32rem">A set of beautifully-designed, accessible widgets and components.
49
47
  No complex frameworks. Pure JavaScript and CSS. Open Source.</p>
50
- `;
51
-
52
- area.attach( header );
48
+ `, area );
53
49
  }
54
50
 
55
51
  // Content
56
52
  {
57
- const tabs = area.addTabs( { sizes: [ "auto", "auto" ], contentClass: "p-6 pt-0" } );
58
- tabs.root.parentElement.classList.add( "p-4" );
53
+ const tabs = area.addTabs( { parentClass: "p-4", sizes: [ "auto", "auto" ], contentClass: "p-6 pt-0" } );
54
+
55
+ // Editor
56
+ {
57
+ const editorContainer = LX.makeContainer( [ null, "800px" ], "flex flex-col bg-primary border rounded-lg overflow-hidden" );
58
+ tabs.add( "Editor", editorContainer, { selected: true } );
59
+
60
+ const editorArea = new LX.Area({ className: "rounded-lg" });
61
+ editorContainer.appendChild( editorArea.root );
62
+
63
+ editorArea.addMenubar( m => {
64
+ m.add( "Scene/New Scene", () => { console.log("New scene created!") });
65
+ m.add( "Scene/Open Scene", { icon: "fa-solid fa-folder-open", short: "S" } );
66
+ m.add( "Scene/Open Recent/hello.scene" );
67
+ m.add( "Scene/Open Recent/Old/goodbye.scene" );
68
+ m.add( "Scene/Open Recent/Old/salute.scene" );
69
+ m.add( "Project/Project Settings", { disabled: true } );
70
+ m.add( "Project/" );
71
+ m.add( "Project/Export", { icon: "fa-solid fa-download" });
72
+ m.add( "Project/Export/DAE", { icon: "fa-solid fa-cube", short: "D" } );
73
+ m.add( "Project/Export/GLTF", { short: "G" } );
74
+ m.add( "Account/Login", { icon: "fa-solid fa-user" } );
75
+ m.add( "Help/Search Help", { icon: "fa-solid fa-magnifying-glass", short: "F1" } );
76
+ m.add( "Help/Support LexGUI/Please", { icon: "fa-solid fa-heart" } );
77
+ m.add( "Help/Support LexGUI/Do it" );
78
+ m.addButtons( [
79
+ {
80
+ title: "Play",
81
+ icon: "fa-solid fa-play",
82
+ swap: "fa-solid fa-stop"
83
+ },
84
+ {
85
+ title: "Pause",
86
+ icon: "fa-solid fa-pause",
87
+ disabled: true
88
+ }
89
+ ]);
90
+ }, { sticky: false });
91
+
92
+ // split main area
93
+ const [ left, right ] = editorArea.split({ sizes:["70%","30%"], minimizable: true });
94
+
95
+ // add canvas to left upper part
96
+ const canvas = document.createElement('canvas');
97
+ canvas.style.width = "100%";
98
+ canvas.style.height = "100%";
99
+ canvas.width = left.root.offsetWidth;
100
+ canvas.height = left.root.offsetHeight
101
+
102
+ const resizeCanvas = ( bounding ) => {
103
+ canvas.width = bounding.width;
104
+ canvas.height = bounding.height;
105
+ };
106
+
107
+ left.attach( canvas );
108
+ left.onresize = resizeCanvas;
109
+ left.addOverlayButtons( [
110
+ [
111
+ { name: "Select", icon: "fa fa-arrow-pointer", selectable: true },
112
+ { name: "Move", icon: "fa-solid fa-arrows-up-down-left-right", selectable: true },
113
+ { name: "Rotate", icon: "fa-solid fa-rotate-right", selectable: true }
114
+ ],
115
+ { name: "Lit", options: ["Lit", "Unlit", "Wireframe"] },
116
+ [
117
+ { name: "Enable Snap", icon: "fa fa-table-cells", selectable: true },
118
+ { name: 10, options: [10, 100, 1000] }
119
+ ]
120
+ ], { float: "htc" } );
121
+
122
+ // add panels
123
+ var sidePanel = right.addPanel();
124
+ fillPanel( sidePanel );
125
+
126
+ function loop(dt) {
127
+
128
+ var ctx = canvas.getContext("2d");
129
+ ctx.fillStyle = sidePanel.getValue('Background');
130
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
131
+ ctx.font = `${ sidePanel.getValue('Font Size') }px ${ sidePanel.getValue('Font Family') }`;
132
+ ctx.fillStyle = sidePanel.getValue('Font Color');
133
+ const pos2D = sidePanel.getValue('2D Position');
134
+ ctx.fillText( sidePanel.getValue('Text'), pos2D[0], pos2D[1]);
135
+ requestAnimationFrame(loop);
136
+ }
137
+
138
+ requestAnimationFrame(loop);
139
+
140
+ // **** **** **** **** **** **** **** **** **** **** **** ****
141
+
142
+ function fillPanel( panel ) {
143
+
144
+ // Add data tree
145
+
146
+ let sceneData = {
147
+ 'id': 'root',
148
+ 'children': [
149
+ {
150
+ 'id': 'node_1',
151
+ 'children': [
152
+ {
153
+ 'id': 'node_1_1',
154
+ 'icon': 'fa-solid fa-cube',
155
+ 'children': [],
156
+ 'actions': [
157
+ {
158
+ 'name': 'Open script',
159
+ 'icon': 'fa-solid fa-scroll'
160
+ }
161
+ ]
162
+ }
163
+ ]
164
+ },
165
+ {
166
+ 'id': 'node_2',
167
+ 'icon': 'fa-solid fa-circle-play',
168
+ 'children': []
169
+ }
170
+ ]
171
+ };
172
+
173
+ // This is optional!
174
+ const treeIcons = [
175
+ {
176
+ 'name':'Add node',
177
+ 'icon': 'fa-solid fa-plus'
178
+ },
179
+ {
180
+ 'name':'Instantiate scene',
181
+ 'icon': 'fa-solid fa-link'
182
+ }
183
+ ];
184
+
185
+ window.tree = panel.addTree("Scene Tree", sceneData, {
186
+ icons: treeIcons,
187
+ addDefault: true,
188
+ onevent: (event) => {
189
+ switch(event.type) {
190
+ case LX.TreeEvent.NODE_CONTEXTMENU:
191
+ const m = event.panel;
192
+ m.add( "Components/Transform");
193
+ m.add( "Components/MeshRenderer");
194
+ break;
195
+ }
196
+ }
197
+ });
198
+
199
+ // add widgets to panel branch
200
+ panel.branch("Canvas", {icon: "fa-solid fa-palette", filter: true});
201
+ panel.addColor("Background", "#b7a9b1", null);
202
+ panel.addText("Text", "LexGUI.js @jxarco", null, {placeholder: "e.g. ColorPicker", icon: "fa fa-font"});
203
+ panel.addColor("Font Color", "#303b8d", null);
204
+ panel.addNumber("Font Size", 36, null, { min: 1, max: 48, step: 1, units: "px"});
205
+ panel.addSelect("Font Family", ["Arial", "GeistSans", "Monospace"], "GeistSans");
206
+ panel.addVector2("2D Position", [300, 350], null, { min: 0, max: 1024 });
207
+ const opacityValues = [
208
+ [0.2, 0.3146875],
209
+ [0.417313915857606, 0.8946875000000003],
210
+ [0.5495145631067961, 0.6746875],
211
+ [1, 1]
212
+ ];
213
+ panel.addCurve("Opacity", opacityValues);
214
+ panel.addSize("Resolution", [1280, 720], null, { units: "p", precision: 0 });
215
+ panel.merge();
216
+
217
+ panel.branch("Node", { icon: "fa-solid fa-cube" });
218
+ panel.addText("Name", "node_1");
219
+ panel.addCheckbox("Visibility", true, null, { className: "accent" });
220
+ panel.addLayers("Layers", 10, null);
221
+
222
+ panel.addTitle( "Transform" );
223
+ panel.addVector3( "Position", [0.0, 0.0, 0.0] );
224
+ panel.addVector4( "Rotation", [0.0, 0.0, 0.0, 1.0] );
225
+ panel.addVector3( "Scale", [1.0, 1.0, 1.0] );
226
+ panel.addButton(null, "Export", null, { buttonClass: "contrast" });
227
+ panel.merge();
228
+ }
229
+ }
59
230
 
60
231
  // Mail
61
232
  {
62
- const mailContainer = LX.makeContainer( [ null, "auto" ], "col bg-primary border rounded-lg p-6" );
63
- tabs.add( "Mail", mailContainer, { selected: true } );
233
+ const mailContainer = LX.makeContainer( [ null, "800px" ], "flex flex-col bg-primary border rounded-lg overflow-hidden" );
234
+ tabs.add( "Mail", mailContainer, { xselected: true } );
235
+
236
+ const mailArea = new LX.Area();
237
+ mailContainer.appendChild( mailArea.root );
238
+ const badgeClass = "ml-auto no-bg font-medium";
239
+
240
+ const sidebar = mailArea.addSidebar( m => {
241
+ m.add( "Inbox", { selected: true, icon: "inbox", content: LX.badge("128", badgeClass, { asElement: true }) } );
242
+ m.add( "Drafts", { icon: "file", content: LX.badge("9", badgeClass, { asElement: true }) } );
243
+ m.add( "Sent", { icon: "paper-plane" } );
244
+ m.add( "Junk", { icon: "box-archive-x", content: LX.badge("23", badgeClass, { asElement: true }) } );
245
+ m.add( "Trash", { icon: "trash-can" } );
246
+ m.add( "Archive", { icon: "box-archive" } );
247
+ m.separator();
248
+ m.add( "Social", { icon: "user", content: LX.badge("972", badgeClass, { asElement: true }) } );
249
+ m.add( "Updates", { icon: "circle-info", content: LX.badge("342", badgeClass, { asElement: true }) } );
250
+ m.add( "Forums", { icon: "comments", content: LX.badge("96", badgeClass, { asElement: true }) } );
251
+ m.add( "Shopping ", { icon: "shopping-cart" } );
252
+ m.add( "Promotions", { icon: "flag", content: LX.badge("21", badgeClass, { asElement: true }) } );
253
+ }, {
254
+ className: "border-right",
255
+ headerTitle: "jxarco",
256
+ headerSubtitle: "alexroco.30@gmail.com",
257
+ headerImage: "https://raw.githubusercontent.com/jxarco/lexgui.js/refs/heads/master/images/icon.png",
258
+ skipFooter: true,
259
+ displaySelected: true,
260
+ onHeaderPressed: (e, element) => { }
261
+ });
262
+
263
+ const inboxArea = sidebar.siblingArea;
264
+
265
+ var [ left, right ] = inboxArea.split({ sizes:["40%","60%"] });
266
+ left.setLimitBox( 350, null, 650, null );
267
+
268
+ // Manage Inbox
269
+ {
270
+ const inboxTabs = left.addTabs({ parentClass: "flex p-3 items-end border-bottom", sizes: [ "auto", "auto" ], float: "end" });
271
+ const tabsRowContainer = inboxTabs.root.parentElement;
272
+
273
+ const mailSectionTitle = LX.makeContainer( [ "auto", "auto" ], "mr-auto ml-2 self-center text-xxl font-semibold", "Inbox" );
274
+ tabsRowContainer.prepend( mailSectionTitle );
275
+
276
+ window.__showMailList = ( container, unreadOnly = false ) => {
277
+
278
+ // Filter
279
+ {
280
+ const allMailFilter = LX.makeContainer( [ "100%", "50px" ], "flex p-2", "", container );
281
+ const filterInput = new LX.TextInput(null, "", null,
282
+ { inputClass: "outline", width: "100%", icon: "fa fa-magnifying-glass", placeholder: "Search..." }
283
+ );
284
+ allMailFilter.appendChild( filterInput.root );
285
+ }
286
+
287
+ // Content
288
+ {
289
+ const allMailContent = LX.makeContainer( [ "100%", "calc(100% - 50px)" ], "flex flex-col p-4 pt-0 gap-2 overflow-scroll", "", container );
290
+
291
+ window.__addMail = ( mail, mailContainer ) => {
292
+
293
+ const msgContent = LX.makeContainer( [ "100%", "auto" ],
294
+ "flex flex-col border p-3 rounded-lg gap-2 select-none hover:bg-secondary cursor-pointer", "", mailContainer );
295
+
296
+ // Name, subject, date
297
+ {
298
+ const msgInfo = LX.makeContainer( [ "100%", "auto" ], "flex flex-col gap-0.5", "", msgContent );
299
+ const msgNameDate = LX.makeContainer( [ "100%", "auto" ], "flex flex-row", "", msgInfo );
300
+
301
+ // Name + Date
302
+ {
303
+ const msgName = LX.makeContainer( [ "auto", "auto" ], "flex font-semibold text-md gap-2", "", msgNameDate );
304
+ msgName.innerHTML = mail.name;
305
+ msgName.innerHTML += ( mail.read ? "" : `<span class="rounded-full self-center bg-accent" style="width: 8px; height: 8px"></span>` );
306
+ const msgDate = LX.makeContainer( [ "auto", "auto" ], "fg-tertiary text-sm ml-auto self-center", mail.date, msgNameDate );
307
+ }
308
+
309
+ const msgSubject = LX.makeContainer( [ "100%", "auto" ], "font-semibold text-sm", mail.subject, msgInfo );
310
+ }
311
+
312
+ const msgText = LX.makeContainer( [ "100%", "auto" ], "text-sm line-clamp-2 fg-tertiary", mail.content, msgContent );
313
+ const msgTags = LX.makeContainer( [ "100%", "auto" ], "flex flex-row gap-0.5 font-semibold", "", msgContent );
314
+ for( const tag of mail.tags )
315
+ {
316
+ msgTags.appendChild( LX.badge( tag, "sm", { asElement: true } ) );
317
+ }
318
+
319
+ msgContent.listen( "click", () => {
320
+ window.__openMail( mail );
321
+ } );
322
+ };
323
+
324
+ LX.requestJSON( "data/example_mail_data.json", data => {
325
+ data.forEach( e => { if( !unreadOnly || ( unreadOnly && !e.read ) ) window.__addMail( e, allMailContent ) } );
326
+ window.__openMail( data[ 0 ] );
327
+ } )
328
+ }
329
+ }
330
+
331
+ const allMailContainer = LX.makeContainer( [ "100%", "100%" ], "flex flex-col" );
332
+ inboxTabs.add( "All mail", allMailContainer, { selected: true } );
333
+ window.__showMailList( allMailContainer );
334
+
335
+ const unreadMailContainer = LX.makeContainer( [ "100%", "100%" ], "flex flex-col" );
336
+ inboxTabs.add( "Unread", unreadMailContainer );
337
+ window.__showMailList( unreadMailContainer, true );
338
+ }
339
+
340
+ // Manage Message Preview
341
+ {
342
+ // Buttons
343
+ {
344
+ const mailPreviewHeader = LX.makeContainer( [ "100%", "59.59px" ], "flex flex-row border-bottom p-1", "", right );
345
+
346
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Archive", tooltip: true, buttonClass: "bg-none", icon: "box-archive" } ).root );
347
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Move to junk", tooltip: true, buttonClass: "bg-none", icon: "box-archive-x" } ).root );
348
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Move to trash", tooltip: true, buttonClass: "bg-none", icon: "trash-can" } ).root );
349
+ mailPreviewHeader.appendChild( LX.makeContainer( [ "1px", "35%" ], "border-right self-center ml-2 mr-2" ) );
350
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Snooze", tooltip: true, buttonClass: "bg-none", icon: "clock" } ).root );
351
+
352
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Reply", tooltip: true, buttonClass: "bg-none", className: "ml-auto", icon: "reply" } ).root );
353
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Reply all", tooltip: true, buttonClass: "bg-none", icon: "reply-all" } ).root );
354
+ mailPreviewHeader.appendChild( new LX.Button( null, "", null, { title: "Forward", tooltip: true, buttonClass: "bg-none", icon: "forward" } ).root );
355
+ mailPreviewHeader.appendChild( LX.makeContainer( [ "1px", "35%" ], "border-right self-center ml-2 mr-2" ) );
356
+ mailPreviewHeader.appendChild( new LX.Button( null, "", (value, event) => {
357
+ new LX.DropdownMenu( event.target, [
358
+ { name: "Mark as unread" },
359
+ { name: "Star thread" },
360
+ { name: "Add label" },
361
+ { name: "Mute thread" }
362
+ ], { side: "bottom", align: "end" });
363
+ }, { buttonClass: "bg-none", icon: "more" } ).root );
364
+ }
365
+
366
+ // Prewiew Info
367
+ {
368
+ const previewDataContent = LX.makeContainer( [ "100%", "100%" ], "", "", right );
369
+
370
+ window.__openMail = ( mail ) => {
371
+
372
+ previewDataContent.innerHTML = "";
373
+
374
+ const mailPreviewInfo = LX.makeContainer( [ "100%", "auto" ], "flex flex-row border-bottom p-6", "", previewDataContent );
375
+
376
+ const senderData = LX.makeContainer( [ "100%", "auto" ], "flex flex-col gap-0.5", `
377
+ <div class="text-md font-semibold">${ mail.name }</div>
378
+ <div class="text-sm">${ mail.subject }</div>
379
+ <div class="text-sm">Reply-To: ${ mail.email }</div>
380
+ `, mailPreviewInfo );
381
+
382
+ const exactDate = LX.makeContainer( [ "100%", "auto" ], "flex flex-row text-sm fg-tertiary justify-end", mail.exactDate, mailPreviewInfo );
383
+ const mailPreviewContent = LX.makeContainer( [ "100%", "505px" ], "flex flex-row border-bottom text-md whitespace-pre-wrap p-4", mail.content, previewDataContent );
384
+ const previewFooter = LX.makeContainer( [ "100%", "auto" ], "flex flex-col p-2", "", previewDataContent );
385
+
386
+ const msgReplyTextArea = new LX.TextArea(null, "", null,
387
+ { className: "mt-1", inputClass: "outline", width: "100%", resize: false, placeholder: `Reply ${ mail.name }` }
388
+ );
389
+ previewFooter.appendChild( msgReplyTextArea.root );
390
+
391
+ const previewButtons = LX.makeContainer( [ "100%", "auto" ], "flex flex-row p-1", "", previewFooter );
392
+
393
+ const muteToggle = new LX.Toggle( null, false, null, { label: "Mute this thread", className: "contrast" } );
394
+ previewButtons.appendChild( muteToggle.root );
395
+
396
+ const sendButton = new LX.Button( null, "Send", () => {
397
+ LX.toast( "Message sent!", "To:" + mail.email, { timeout: 5000, action: { name: "Undo", callback: ( toast, actionName, event ) => {
398
+ toast.close();
399
+ } } } );
400
+ }, { className: "ml-auto", buttonClass: "contrast" } );
401
+ previewButtons.appendChild( sendButton.root );
402
+ };
403
+ }
404
+ }
64
405
  }
65
406
 
66
407
  // Tasks
67
408
  {
68
- const tasksContainer = LX.makeContainer( [ null, "auto" ], "col bg-primary border rounded-lg p-6" );
409
+ const tasksContainer = LX.makeContainer( [ null, "auto" ], "col bg-primary border rounded-lg p-6 overflow-hidden" );
69
410
  tabs.add( "Tasks", tasksContainer, { xselected: true } );
70
411
 
71
- const header = LX.makeContainer( [ null, "auto" ], "col rounded-lg p-6" );
72
- header.innerHTML = `
412
+ const header = LX.makeContainer( [ null, "auto" ], "col p-4", `
73
413
  <h2>Welcome back!</h2>
74
414
  <p class="fg-tertiary">Here's a list of your tasks for this month!</p>
75
- `;
76
- tasksContainer.appendChild( header );
415
+ `, tasksContainer );
77
416
 
78
417
  const tableWidget = new LX.Table(null, {
79
418
  head: ["Name", "Status", "Priority"],
@@ -115,35 +454,34 @@ let area = LX.init( { strictViewport: false } );
115
454
 
116
455
  // Code
117
456
  {
118
- const codeContainer = LX.makeContainer( [ "auto", "850px" ], "", {
119
- backgroundColor: "red"
120
- } );
121
-
457
+ const codeContainer = LX.makeContainer( [ "auto", "800px" ], "flex flex-col border rounded-lg overflow-hidden" );
122
458
  tabs.add( "Code", codeContainer );
123
- }
124
459
 
125
- // Audio
126
- {
127
- const audioContainer = LX.makeContainer( [ "auto", "850px" ], "", {
128
- backgroundColor: "red"
129
- } );
460
+ const codeArea = new LX.Area();
461
+ codeContainer.appendChild( codeArea.root );
130
462
 
131
- tabs.add( "Audio", audioContainer );
463
+ let editor = new LX.CodeEditor(codeArea, {
464
+ // allowAddScripts: false,
465
+ // autocomplete: false,
466
+ // disableEdition: true,
467
+ // fileExplorer: false
468
+ });
132
469
  }
133
470
 
134
- // Examples
135
- {
136
- const examplesContainer = LX.makeContainer( [ "auto", "850px" ], "", {
137
- backgroundColor: "red"
138
- } );
471
+ // Audio
472
+ // {
473
+ // const audioContainer = LX.makeContainer( [ "auto", "850px" ], "", {
474
+ // backgroundColor: "red"
475
+ // } );
139
476
 
140
- tabs.add( "Examples", examplesContainer );
141
- }
477
+ // tabs.add( "Audio", audioContainer );
478
+ // }
142
479
  }
143
480
 
144
481
  // Footer
145
482
  {
146
483
  const footer = new LX.Footer( {
484
+ className: "border-top",
147
485
  parent: LX.root,
148
486
  columns: [
149
487
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lexgui",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "JS library to create web graphical user interfaces",
5
5
  "type": "module",
6
6
  "main": "./build/lexgui.js",