jops-core 1.0.0

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,488 @@
1
+ /* ── CSS Variables ───────────────────────────────────────────── */
2
+ :root {
3
+ --color-primary: #4f46e5;
4
+ --color-primary-hover: #4338ca;
5
+ --color-secondary: #06b6d4;
6
+ --color-bg: #f8fafc;
7
+ --color-surface: #ffffff;
8
+ --color-border: #e2e8f0;
9
+ --color-text: #1e293b;
10
+ --color-text-muted: #64748b;
11
+ --color-active: #22c55e;
12
+ --color-inactive: #ef4444;
13
+
14
+ --spacing-xs: 0.25rem;
15
+ --spacing-sm: 0.5rem;
16
+ --spacing-md: 1rem;
17
+ --spacing-lg: 2rem;
18
+ --spacing-xl: 4rem;
19
+
20
+ --radius-sm: 0.25rem;
21
+ --radius-md: 0.5rem;
22
+ --radius-lg: 1rem;
23
+
24
+ --font-sans: system-ui, -apple-system, sans-serif;
25
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
26
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
27
+ }
28
+
29
+ /* ── Reset ───────────────────────────────────────────────────── */
30
+ *,
31
+ *::before,
32
+ *::after {
33
+ box-sizing: border-box;
34
+ margin: 0;
35
+ padding: 0;
36
+ }
37
+
38
+ body {
39
+ font-family: var(--font-sans);
40
+ background: var(--color-bg);
41
+ color: var(--color-text);
42
+ line-height: 1.6;
43
+ }
44
+
45
+ /* ── Root ────────────────────────────────────────────────────── */
46
+ .jops-root {
47
+ display: flex;
48
+ flex-direction: column;
49
+ min-height: 100vh;
50
+ }
51
+
52
+ /* ── Header ──────────────────────────────────────────────────── */
53
+ .header {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: space-between;
57
+ padding: var(--spacing-md) var(--spacing-lg);
58
+ background: var(--color-surface);
59
+ border-bottom: 1px solid var(--color-border);
60
+ box-shadow: var(--shadow-sm);
61
+ position: sticky;
62
+ top: 0;
63
+ z-index: 100;
64
+ }
65
+
66
+ .header__brand {
67
+ display: flex;
68
+ align-items: baseline;
69
+ gap: var(--spacing-sm);
70
+ }
71
+
72
+ .header__logo {
73
+ font-size: 1.5rem;
74
+ font-weight: 700;
75
+ color: var(--color-primary);
76
+ letter-spacing: -0.5px;
77
+ }
78
+
79
+ .header__tagline {
80
+ font-size: 0.875rem;
81
+ color: var(--color-text-muted);
82
+ }
83
+
84
+ .header__nav {
85
+ display: flex;
86
+ gap: var(--spacing-lg);
87
+ }
88
+
89
+ .header__nav-link {
90
+ text-decoration: none;
91
+ color: var(--color-text-muted);
92
+ font-size: 0.9rem;
93
+ font-weight: 500;
94
+ transition: color 0.2s;
95
+ }
96
+
97
+ .header__nav-link:hover {
98
+ color: var(--color-primary);
99
+ }
100
+
101
+ /* ── Main ────────────────────────────────────────────────────── */
102
+ .main {
103
+ flex: 1;
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: var(--spacing-xl);
107
+ padding: var(--spacing-xl) var(--spacing-lg);
108
+ max-width: 1100px;
109
+ width: 100%;
110
+ margin: 0 auto;
111
+ }
112
+
113
+ /* ── Section Title ───────────────────────────────────────────── */
114
+ .section__title {
115
+ font-size: 1.5rem;
116
+ font-weight: 700;
117
+ color: var(--color-text);
118
+ margin-bottom: var(--spacing-lg);
119
+ }
120
+
121
+ .section__title--mt {
122
+ margin-top: var(--spacing-xl);
123
+ }
124
+
125
+ /* ── Hero ────────────────────────────────────────────────────── */
126
+ .hero {
127
+ text-align: center;
128
+ padding: var(--spacing-xl) var(--spacing-md);
129
+ background: linear-gradient(
130
+ 135deg,
131
+ var(--color-primary) 0%,
132
+ var(--color-secondary) 100%
133
+ );
134
+ border-radius: var(--radius-lg);
135
+ color: #fff;
136
+ }
137
+
138
+ .hero__title {
139
+ font-size: 2.5rem;
140
+ font-weight: 800;
141
+ margin-bottom: var(--spacing-md);
142
+ }
143
+
144
+ .hero__subtitle {
145
+ font-size: 1.1rem;
146
+ opacity: 0.9;
147
+ max-width: 600px;
148
+ margin: 0 auto var(--spacing-lg);
149
+ }
150
+
151
+ /* ── Button ──────────────────────────────────────────────────── */
152
+ .btn {
153
+ display: inline-block;
154
+ padding: 0.65rem 1.5rem;
155
+ border: none;
156
+ border-radius: var(--radius-md);
157
+ font-size: 0.95rem;
158
+ font-weight: 600;
159
+ cursor: pointer;
160
+ transition:
161
+ background 0.2s,
162
+ transform 0.1s;
163
+ }
164
+
165
+ .btn--primary {
166
+ background: var(--color-primary);
167
+ color: #fff;
168
+ }
169
+
170
+ .btn--primary:hover {
171
+ background: var(--color-primary-hover);
172
+ transform: translateY(-1px);
173
+ }
174
+
175
+ /* ── Cards ───────────────────────────────────────────────────── */
176
+ .cards {
177
+ display: grid;
178
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
179
+ gap: var(--spacing-lg);
180
+ }
181
+
182
+ .card {
183
+ background: var(--color-surface);
184
+ border: 1px solid var(--color-border);
185
+ border-radius: var(--radius-md);
186
+ padding: var(--spacing-lg);
187
+ box-shadow: var(--shadow-sm);
188
+ transition:
189
+ box-shadow 0.2s,
190
+ transform 0.2s;
191
+ }
192
+
193
+ .card:hover {
194
+ box-shadow: var(--shadow-md);
195
+ transform: translateY(-2px);
196
+ }
197
+
198
+ .card__title {
199
+ font-size: 1.1rem;
200
+ font-weight: 700;
201
+ margin-bottom: var(--spacing-sm);
202
+ color: var(--color-primary);
203
+ }
204
+
205
+ .card__body {
206
+ font-size: 0.9rem;
207
+ color: var(--color-text-muted);
208
+ }
209
+
210
+ /* ── Form ────────────────────────────────────────────────────── */
211
+ .form-section {
212
+ background: var(--color-surface);
213
+ border: 1px solid var(--color-border);
214
+ border-radius: var(--radius-md);
215
+ padding: var(--spacing-lg);
216
+ box-shadow: var(--shadow-sm);
217
+ }
218
+
219
+ .form {
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: var(--spacing-md);
223
+ max-width: 600px;
224
+ }
225
+
226
+ .form__group {
227
+ display: flex;
228
+ flex-direction: column;
229
+ gap: var(--spacing-xs);
230
+ }
231
+
232
+ .form__group--inline {
233
+ flex-direction: row;
234
+ align-items: center;
235
+ gap: var(--spacing-sm);
236
+ }
237
+
238
+ .form__label {
239
+ font-size: 0.875rem;
240
+ font-weight: 600;
241
+ color: var(--color-text);
242
+ }
243
+
244
+ .form__label--inline {
245
+ font-weight: 400;
246
+ }
247
+
248
+ .form__input,
249
+ .form__select,
250
+ .form__textarea {
251
+ padding: 0.6rem 0.75rem;
252
+ border: 1px solid var(--color-border);
253
+ border-radius: var(--radius-sm);
254
+ font-size: 0.9rem;
255
+ font-family: var(--font-sans);
256
+ color: var(--color-text);
257
+ background: var(--color-bg);
258
+ transition:
259
+ border-color 0.2s,
260
+ box-shadow 0.2s;
261
+ }
262
+
263
+ .form__input:focus,
264
+ .form__select:focus,
265
+ .form__textarea:focus {
266
+ outline: none;
267
+ border-color: var(--color-primary);
268
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
269
+ }
270
+
271
+ .form__textarea {
272
+ resize: vertical;
273
+ }
274
+
275
+ .form__radio-group {
276
+ display: flex;
277
+ gap: var(--spacing-lg);
278
+ }
279
+
280
+ .form__radio-label {
281
+ display: flex;
282
+ align-items: center;
283
+ gap: var(--spacing-xs);
284
+ font-size: 0.9rem;
285
+ cursor: pointer;
286
+ }
287
+
288
+ /* ── Table ───────────────────────────────────────────────────── */
289
+ .data-section {
290
+ background: var(--color-surface);
291
+ border: 1px solid var(--color-border);
292
+ border-radius: var(--radius-md);
293
+ padding: var(--spacing-lg);
294
+ box-shadow: var(--shadow-sm);
295
+ }
296
+
297
+ .table-wrapper {
298
+ overflow-x: auto;
299
+ }
300
+
301
+ .table {
302
+ width: 100%;
303
+ border-collapse: collapse;
304
+ font-size: 0.9rem;
305
+ }
306
+
307
+ .table th {
308
+ text-align: left;
309
+ padding: var(--spacing-sm) var(--spacing-md);
310
+ background: var(--color-bg);
311
+ border-bottom: 2px solid var(--color-border);
312
+ font-weight: 700;
313
+ color: var(--color-text-muted);
314
+ text-transform: uppercase;
315
+ font-size: 0.75rem;
316
+ letter-spacing: 0.05em;
317
+ }
318
+
319
+ .table td {
320
+ padding: var(--spacing-sm) var(--spacing-md);
321
+ border-bottom: 1px solid var(--color-border);
322
+ }
323
+
324
+ .table tbody tr:hover {
325
+ background: var(--color-bg);
326
+ }
327
+
328
+ /* ── Badge ───────────────────────────────────────────────────── */
329
+ .badge {
330
+ display: inline-block;
331
+ padding: 0.2rem 0.6rem;
332
+ border-radius: 999px;
333
+ font-size: 0.75rem;
334
+ font-weight: 600;
335
+ }
336
+
337
+ .badge--active {
338
+ background: #dcfce7;
339
+ color: #166534;
340
+ }
341
+ .badge--inactive {
342
+ background: #fee2e2;
343
+ color: #991b1b;
344
+ }
345
+
346
+ /* ── List ────────────────────────────────────────────────────── */
347
+ .list {
348
+ list-style: none;
349
+ display: flex;
350
+ flex-direction: column;
351
+ gap: var(--spacing-sm);
352
+ }
353
+
354
+ .list__item {
355
+ padding: var(--spacing-sm) var(--spacing-md);
356
+ background: var(--color-bg);
357
+ border: 1px solid var(--color-border);
358
+ border-radius: var(--radius-sm);
359
+ font-size: 0.9rem;
360
+ display: flex;
361
+ align-items: center;
362
+ gap: var(--spacing-sm);
363
+ }
364
+
365
+ .list__item::before {
366
+ content: "";
367
+ display: inline-block;
368
+ width: 8px;
369
+ height: 8px;
370
+ border-radius: 50%;
371
+ background: var(--color-primary);
372
+ flex-shrink: 0;
373
+ }
374
+
375
+ /* ── Media ───────────────────────────────────────────────────── */
376
+ .media-section {
377
+ background: var(--color-surface);
378
+ border: 1px solid var(--color-border);
379
+ border-radius: var(--radius-md);
380
+ padding: var(--spacing-lg);
381
+ box-shadow: var(--shadow-sm);
382
+ }
383
+
384
+ .media-grid {
385
+ display: grid;
386
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
387
+ gap: var(--spacing-lg);
388
+ }
389
+
390
+ .media-card {
391
+ display: flex;
392
+ flex-direction: column;
393
+ gap: var(--spacing-sm);
394
+ }
395
+
396
+ .media-card__img-placeholder {
397
+ width: 100%;
398
+ aspect-ratio: 16/9;
399
+ background: linear-gradient(135deg, var(--color-border), #cbd5e1);
400
+ border-radius: var(--radius-md);
401
+ display: flex;
402
+ align-items: center;
403
+ justify-content: center;
404
+ color: var(--color-text-muted);
405
+ font-size: 0.85rem;
406
+ font-weight: 500;
407
+ }
408
+
409
+ .media-card__caption {
410
+ font-size: 0.85rem;
411
+ color: var(--color-text-muted);
412
+ text-align: center;
413
+ }
414
+
415
+ /* ── Media Dialog ────────────────────────────────────────────── */
416
+ .media-dialog {
417
+ padding: var(--spacing-lg);
418
+ display: flex;
419
+ flex-direction: column;
420
+ gap: var(--spacing-md);
421
+ aspect-ratio: 1.5 / 1;
422
+ background: var(--color-surface);
423
+ border: 1px solid var(--color-border);
424
+ border-radius: var(--radius-md);
425
+ box-shadow: var(--shadow-sm);
426
+ overflow: hidden;
427
+ }
428
+
429
+ .media-dialog__back {
430
+ align-self: flex-start;
431
+ }
432
+
433
+ .media-dialog__image {
434
+ flex: 1;
435
+ overflow: hidden;
436
+ border-radius: var(--radius-md);
437
+ }
438
+
439
+ .media-dialog__image img {
440
+ width: 100%;
441
+ height: 100%;
442
+ object-fit: contain;
443
+ display: block;
444
+ }
445
+
446
+ .media-dialog__caption {
447
+ font-size: 1rem;
448
+ color: var(--color-text-muted);
449
+ text-align: center;
450
+ }
451
+
452
+ /* ── Footer ──────────────────────────────────────────────────── */
453
+ .footer {
454
+ text-align: center;
455
+ padding: var(--spacing-lg);
456
+ background: var(--color-surface);
457
+ border-top: 1px solid var(--color-border);
458
+ display: flex;
459
+ flex-direction: column;
460
+ gap: var(--spacing-xs);
461
+ }
462
+
463
+ .footer__text {
464
+ font-size: 0.875rem;
465
+ color: var(--color-text-muted);
466
+ }
467
+ .footer__text--small {
468
+ font-size: 0.75rem;
469
+ }
470
+
471
+ /* ── Responsive ──────────────────────────────────────────────── */
472
+ @media (max-width: 768px) {
473
+ .header {
474
+ flex-direction: column;
475
+ gap: var(--spacing-md);
476
+ }
477
+ .header__nav {
478
+ gap: var(--spacing-md);
479
+ flex-wrap: wrap;
480
+ justify-content: center;
481
+ }
482
+ .hero__title {
483
+ font-size: 1.75rem;
484
+ }
485
+ .main {
486
+ padding: var(--spacing-lg) var(--spacing-md);
487
+ }
488
+ }
@@ -0,0 +1,25 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <section id="data" class="data-section">
5
+ <h2 class="section__title">Data Table</h2>
6
+ <div class="table-wrapper">
7
+ <table class="table">
8
+ <thead>
9
+ <tr>
10
+ <th>ID</th>
11
+ <th>Name</th>
12
+ <th>Role</th>
13
+ <th>Status</th>
14
+ </tr>
15
+ </thead>
16
+ <tbody id="tableBody">
17
+ </tbody>
18
+ </table>
19
+ </div>
20
+
21
+ <h2 class="section__title section__title--mt">Item List</h2>
22
+ <ul id="list" class="list">
23
+ </ul>
24
+ </section>
25
+ `;
@@ -0,0 +1,8 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <footer id="contact" class="footer">
5
+ <p class="footer__text">JOPS Framework &mdash; Built with vanilla ES6. No bundler required.</p>
6
+ <p class="footer__text footer__text--small">&copy; 2026 JOPS. All rights reserved.</p>
7
+ </footer>
8
+ `;
@@ -0,0 +1,44 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <section id="form" class="form-section">
5
+ <h2 class="section__title">Sample Form</h2>
6
+ <form class="form" type="jops-event-bind" onsubmit="onSubmit">
7
+ <div class="form__group">
8
+ <label class="form__label" for="fullname">Full Name</label>
9
+ <input class="form__input" type="text" id="fullname" name="fullname" placeholder="Enter your full name">
10
+ </div>
11
+ <div class="form__group">
12
+ <label class="form__label" for="email">Email</label>
13
+ <input class="form__input" type="email" id="email" name="email" placeholder="Enter your email">
14
+ </div>
15
+ <div class="form__group">
16
+ <label class="form__label" for="role">Role</label>
17
+ <select class="form__select" id="role" name="role">
18
+ <option value="">Select a role</option>
19
+ <option value="frontend">Frontend Developer</option>
20
+ <option value="backend">Backend Developer</option>
21
+ <option value="fullstack">Full Stack Developer</option>
22
+ <option value="mobile">Mobile Developer</option>
23
+ </select>
24
+ </div>
25
+ <div class="form__group">
26
+ <label class="form__label">Experience</label>
27
+ <div class="form__radio-group">
28
+ <label class="form__radio-label"><input type="radio" name="experience" value="junior"> Junior</label>
29
+ <label class="form__radio-label"><input type="radio" name="experience" value="mid"> Mid</label>
30
+ <label class="form__radio-label"><input type="radio" name="experience" value="senior"> Senior</label>
31
+ </div>
32
+ </div>
33
+ <div class="form__group">
34
+ <label class="form__label" for="message">Message</label>
35
+ <textarea class="form__textarea" id="message" name="message" rows="4" placeholder="Write your message here..."></textarea>
36
+ </div>
37
+ <div class="form__group form__group--inline">
38
+ <input class="form__checkbox" type="checkbox" id="agree" name="agree" value="yes">
39
+ <label class="form__label form__label--inline" for="agree">I agree to the terms and conditions</label>
40
+ </div>
41
+ <button class="btn btn--primary" type="submit">Submit</button>
42
+ </form>
43
+ </section>
44
+ `;
@@ -0,0 +1,17 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <header class="header">
5
+ <div class="header__brand">
6
+ <span class="header__logo">JOPS</span>
7
+ <span class="header__tagline">Hello World</span>
8
+ </div>
9
+ <nav class="header__nav">
10
+ <a class="header__nav-link" href="#home">Home</a>
11
+ <a class="header__nav-link" href="#features">Features</a>
12
+ <a class="header__nav-link" href="#form">Form</a>
13
+ <a class="header__nav-link" href="#data">Data</a>
14
+ <a class="header__nav-link" href="#media">Media</a>
15
+ </nav>
16
+ </header>
17
+ `;
@@ -0,0 +1,9 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <section id="home" class="hero">
5
+ <h1 class="hero__title">Welcome to JOPS</h1>
6
+ <p class="hero__subtitle">A no-bundler, vanilla-ES6-class SPA framework built for developers who think in OOP.</p>
7
+ <button class="btn btn--primary">Get Started</button>
8
+ </section>
9
+ `;
@@ -0,0 +1,39 @@
1
+ import { layout } from "jops-core";
2
+
3
+ export default layout`
4
+ <link rel="stylesheet" href="./src/css/styles.css">
5
+
6
+ <div class="jops-root">
7
+
8
+ <View type="jops" layout="/src/layout/layout_header.js"></View>
9
+
10
+ <main class="main">
11
+
12
+ <Router type="jops" animation="slide">
13
+
14
+ <View path="/home" type="jops" layout="/src/layout/layout_hero.js"></View>
15
+
16
+ <Features path="/features" type="jops"
17
+ src="/src/Features.js">
18
+ </Features>
19
+
20
+ <Form path="/form" type="jops"
21
+ src="/src/Form.js">
22
+ </Form>
23
+
24
+ <DataSection path="/data" type="jops"
25
+ src="/src/DataSection.js">
26
+ </DataSection>
27
+
28
+ <Media path="/media" type="jops"
29
+ src="/src/Media.js">
30
+ </Media>
31
+
32
+ </Router>
33
+
34
+ </main>
35
+
36
+ <View type="jops" layout="/src/layout/layout_footer.js"></View>
37
+
38
+ </div>
39
+ `;