modulearn 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,170 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>ModuLearn — visual training editor</title>
7
+ <style>
8
+ /* ---- shell: full-viewport three-pane (palette | canvas | output) ---- */
9
+ :root { --bg:#14181f; --panel:#1b212b; --edge:#2a323f; --ink:#e6edf3;
10
+ --muted:#8b98a9; --accent:#a8542f; --ok:#3fb950; --err:#f85149;
11
+ --palette-w:220px; }
12
+ * { box-sizing: border-box; }
13
+ html, body { margin:0; height:100%; background:var(--bg); color:var(--ink);
14
+ font:13px/1.4 ui-sans-serif, system-ui, sans-serif; overflow:hidden; }
15
+ #app { display:grid; grid-template-columns:var(--palette-w) 6px 1fr;
16
+ grid-template-rows:44px 1fr;
17
+ grid-template-areas:"bar bar bar" "palette resizer canvas"; height:100%; }
18
+ #app.palette-hidden { grid-template-columns:0 0 1fr; }
19
+ #app.palette-hidden #palette, #app.palette-hidden #resizer { display:none; }
20
+
21
+ /* ---- palette resize handle ---- */
22
+ #resizer { grid-area:resizer; cursor:col-resize; background:transparent;
23
+ transition:background .12s ease; }
24
+ #resizer:hover, #resizer.dragging { background:var(--accent); }
25
+
26
+ /* ---- top toolbar ---- */
27
+ #bar { grid-area:bar; display:flex; align-items:center; gap:10px; padding:0 14px;
28
+ background:var(--panel); border-bottom:1px solid var(--edge); }
29
+ #bar h1 { font-size:14px; margin:0; font-weight:600; letter-spacing:.2px; }
30
+ #bar .dot { width:10px; height:10px; border-radius:50%; background:var(--accent);
31
+ transition:box-shadow .3s; }
32
+ #bar .dot.live { animation:dotpulse 1.2s ease-in-out infinite; }
33
+ @keyframes dotpulse {
34
+ 0%,100% { box-shadow:0 0 0 0 rgba(63,185,80,.55); background:var(--ok); }
35
+ 50% { box-shadow:0 0 0 7px rgba(63,185,80,0); background:var(--ok); }
36
+ }
37
+ #bar .spacer { flex:1; }
38
+ button { background:#232b37; color:var(--ink); border:1px solid var(--edge);
39
+ border-radius:6px; padding:6px 12px; font-size:12px; cursor:pointer; }
40
+ button:hover { border-color:var(--muted); }
41
+ button:disabled { opacity:.45; cursor:not-allowed; }
42
+ button:disabled:hover { border-color:var(--edge); }
43
+ button.primary { background:var(--accent); border-color:var(--accent); color:#fff; }
44
+ button.primary:disabled { background:#232b37; border-color:var(--edge); color:var(--muted); }
45
+ button.primary.running { background:#2d3a2e; border-color:var(--ok); color:var(--ok); }
46
+ button.icon { padding:6px 9px; font-size:14px; line-height:1; }
47
+ button.primary.running .spin { display:inline-block; animation:spin 1s linear infinite; }
48
+ @keyframes spin { to { transform:rotate(360deg); } }
49
+ #runs { background:#232b37; color:var(--ink); border:1px solid var(--edge);
50
+ border-radius:6px; padding:6px; font-size:12px; }
51
+
52
+ /* ---- left palette: search box + catalog nodes grouped by category ---- */
53
+ #palette { grid-area:palette; background:var(--panel); border-right:1px solid var(--edge);
54
+ display:flex; flex-direction:column; overflow:hidden; }
55
+ #paletteSearch { padding:8px; border-bottom:1px solid var(--edge); }
56
+ #paletteQuery { width:100%; background:#14181f; color:var(--ink);
57
+ border:1px solid var(--edge); border-radius:6px; padding:6px 9px; font-size:12px;
58
+ outline:none; transition:border-color .12s ease; }
59
+ #paletteQuery::placeholder { color:var(--muted); }
60
+ #paletteQuery:focus { border-color:var(--accent); }
61
+ #paletteList { flex:1; overflow-y:auto; padding:8px; }
62
+ #paletteEmpty { color:var(--muted); font-size:12px; padding:10px 4px; display:none; }
63
+ #palette .catblock { margin-bottom:2px; }
64
+ #palette .cat { color:var(--ink); text-transform:uppercase; font-size:10.5px;
65
+ letter-spacing:.8px; padding:7px 8px; border-radius:6px; cursor:pointer;
66
+ user-select:none; display:flex; align-items:center; gap:8px;
67
+ transition:background .12s ease; }
68
+ #palette .cat:hover { background:#232b37; }
69
+ #palette .cat .caret { color:var(--accent); font-size:9px; width:9px; text-align:center;
70
+ display:inline-block; transition:transform .15s ease; }
71
+ #palette .catblock:not(.collapsed) .cat .caret { transform:rotate(90deg); }
72
+ #palette .cat .catcount { margin-left:auto; color:var(--faint); font-size:9px;
73
+ background:#14181f; border:1px solid var(--edge); border-radius:8px; padding:0 6px; }
74
+ #palette .item { margin:1px 4px 1px 10px; padding:6px 8px; border-radius:6px;
75
+ cursor:pointer; user-select:none; display:flex; align-items:center; gap:6px;
76
+ transition:transform .12s ease, background .12s ease, box-shadow .12s ease; }
77
+ #palette .item:hover { background:#232b37; transform:translateX(4px);
78
+ box-shadow:-3px 0 0 var(--accent); }
79
+ #palette .item.exp { opacity:.55; }
80
+ #palette .item .tag { font-size:9px; color:var(--accent); border:1px solid var(--edge);
81
+ border-radius:4px; padding:0 3px; margin-left:auto; }
82
+
83
+ /* ---- canvas + floating validation panel ---- */
84
+ #canvasWrap { grid-area:canvas; position:relative; }
85
+ #graphcanvas { width:100%; height:100%; display:block; }
86
+ /* position:fixed so drag/resize math (viewport-based) matches its coords */
87
+ #out { position:fixed; right:12px; bottom:12px; z-index:5; width:360px; max-height:88vh;
88
+ overflow:auto; background:rgba(20,24,31,.94); border:1px solid var(--edge);
89
+ border-radius:8px; padding:10px 12px; font:11px/1.5 ui-monospace, monospace;
90
+ transition:border-color .3s ease;
91
+ resize:both; min-width:240px; min-height:110px; max-width:90vw; }
92
+ /* the title bar doubles as the drag handle */
93
+ #outTitle { cursor:move; user-select:none; display:flex; align-items:center; gap:6px; }
94
+ #outTitle::before { content:"⠿"; color:var(--muted); font-size:12px;
95
+ letter-spacing:-1px; }
96
+ #chart { display:none; width:100%; height:120px; margin:2px 0 8px;
97
+ border-bottom:1px solid var(--edge); padding-bottom:6px; }
98
+ #outBody { transition:color .3s ease; }
99
+ #outBody.flash { animation:panelflash .35s ease; }
100
+ @keyframes panelflash { from { opacity:.35; transform:translateY(2px); } to { opacity:1; transform:none; } }
101
+ @media (prefers-reduced-motion: reduce) {
102
+ #bar .dot.live { animation:none; }
103
+ #outBody.flash { animation:none; }
104
+ #palette .item:hover { transform:none; }
105
+ }
106
+ #out .ok { color:var(--ok); } #out .err { color:var(--err); }
107
+ #out .k { color:var(--muted); }
108
+ #out h4 { margin:0 0 6px; font:600 11px/1 ui-sans-serif; letter-spacing:.4px; }
109
+ /* clickable error lines: click to select + centre the offending node */
110
+ #out .errline { cursor:pointer; border-radius:3px; padding:0 2px;
111
+ text-decoration:underline dotted rgba(248,81,73,.5); text-underline-offset:2px; }
112
+ #out .errline:hover { background:rgba(248,81,73,.14); color:#ffb3ae; }
113
+
114
+ /* ---- narrow screens: palette becomes an overlay drawer ---- */
115
+ @media (max-width:720px) {
116
+ #app { grid-template-columns:0 0 1fr; }
117
+ #resizer { display:none; }
118
+ #palette { position:absolute; top:44px; left:0; z-index:30;
119
+ width:min(280px,82vw); height:calc(100% - 44px);
120
+ transform:translateX(-100%); transition:transform .2s ease;
121
+ box-shadow:2px 0 14px rgba(0,0,0,.45); }
122
+ #app:not(.palette-hidden) #palette { transform:none; }
123
+ #app.palette-hidden #palette { display:flex; } /* keep the drawer mounted */
124
+ #out { width:min(340px,88vw); }
125
+ }
126
+ </style>
127
+ </head>
128
+ <body>
129
+ <div id="app">
130
+ <div id="bar">
131
+ <button id="paletteToggle" class="icon" title="Show / hide the node palette"
132
+ aria-label="Toggle palette">☰</button>
133
+ <span class="dot"></span>
134
+ <h1 id="brand">ModuLearn <span id="brandSub" style="color:var(--muted);font-weight:400"></span></h1>
135
+ <div class="spacer"></div>
136
+ <button id="fitBtn" title="Zoom to fit / reset view">⤢ Fit</button>
137
+ <select id="runs" title="Load a saved run's blueprint"></select>
138
+ <button id="loadBtn">Load</button>
139
+ <button id="exportBtn" title="Download this blueprint as JSON">⭳ Export</button>
140
+ <button id="importBtn" title="Load a blueprint file">⭱ Import</button>
141
+ <input id="importFile" type="file" accept="application/json,.json" hidden>
142
+ <button id="undoBtn" class="icon" title="Undo (⌘Z)" disabled>↶</button>
143
+ <button id="redoBtn" class="icon" title="Redo (⌘⇧Z)" disabled>↷</button>
144
+ <button id="clearBtn">Clear</button>
145
+ <button id="trainBtn" class="primary"><span class="spin">▶</span> Train</button>
146
+ </div>
147
+ <div id="palette">
148
+ <div id="paletteSearch">
149
+ <input id="paletteQuery" type="search" autocomplete="off" spellcheck="false"
150
+ placeholder="Search nodes… (⌘K / )" aria-label="Search nodes">
151
+ </div>
152
+ <div id="paletteList">
153
+ <div id="paletteEmpty">No nodes match.</div>
154
+ </div>
155
+ </div>
156
+ <div id="resizer" title="Drag to resize palette"></div>
157
+ <div id="canvasWrap">
158
+ <canvas id="graphcanvas"></canvas>
159
+ <div id="out">
160
+ <h4 id="outTitle">VALIDATION</h4>
161
+ <canvas id="chart"></canvas>
162
+ <div id="outBody" class="k">Add nodes and wire a Train sink.</div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+
167
+ <script src="/static/graph-engine.js"></script>
168
+ <script src="/static/graph.js"></script>
169
+ </body>
170
+ </html>