sqlite-hub 0.17.2 → 1.1.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.
Files changed (85) hide show
  1. package/README.md +143 -47
  2. package/bin/sqlite-hub.js +206 -444
  3. package/examples/api/queries.js +31 -0
  4. package/examples/api/rows.js +27 -0
  5. package/frontend/assets/mockups/charts_1_bars_1200.webp +0 -0
  6. package/frontend/assets/mockups/charts_2_pie_1200.webp +0 -0
  7. package/frontend/assets/mockups/charts_3_scatter_plot_1200.webp +0 -0
  8. package/frontend/assets/mockups/connections_1200.webp +0 -0
  9. package/frontend/assets/mockups/data_1_1200.webp +0 -0
  10. package/frontend/assets/mockups/data_2_row_editor_1200.webp +0 -0
  11. package/frontend/assets/mockups/documents_1200.webp +0 -0
  12. package/frontend/assets/mockups/media_tagging_1_setup_1200.webp +0 -0
  13. package/frontend/assets/mockups/media_tagging_2_tagging_queue_1200.webp +0 -0
  14. package/frontend/assets/mockups/media_tagging_3_media_viewer_1200.webp +0 -0
  15. package/frontend/assets/mockups/overview_1200.webp +0 -0
  16. package/frontend/assets/mockups/settings_1200.webp +0 -0
  17. package/frontend/assets/mockups/sql_editor_1_1200.webp +0 -0
  18. package/frontend/assets/mockups/sql_editor_2_query_details_1200.webp +0 -0
  19. package/frontend/assets/mockups/sql_editor_3_export_column_1200.webp +0 -0
  20. package/frontend/assets/mockups/sql_editor_4_export_column_as_markdown_1200.webp +0 -0
  21. package/frontend/assets/mockups/sql_editor_5_export_query_result_1200.webp +0 -0
  22. package/frontend/assets/mockups/structure_1_1200.webp +0 -0
  23. package/frontend/assets/mockups/structure_2_inspector_1200.webp +0 -0
  24. package/frontend/assets/mockups/table_designer_1_1200.webp +0 -0
  25. package/frontend/assets/mockups/table_designer_2_checks_1200.webp +0 -0
  26. package/frontend/js/api.js +25 -0
  27. package/frontend/js/app.js +263 -34
  28. package/frontend/js/components/formControls.js +38 -0
  29. package/frontend/js/components/modal.js +77 -21
  30. package/frontend/js/components/queryChartRenderer.js +28 -3
  31. package/frontend/js/components/queryEditor.js +20 -24
  32. package/frontend/js/components/queryHistoryDetail.js +1 -1
  33. package/frontend/js/components/queryHistoryHeader.js +48 -0
  34. package/frontend/js/components/queryHistoryList.js +132 -0
  35. package/frontend/js/components/queryHistoryPanel.js +72 -136
  36. package/frontend/js/components/structureGraph.js +699 -89
  37. package/frontend/js/components/tableDesignerEditor.js +3 -5
  38. package/frontend/js/store.js +188 -7
  39. package/frontend/js/utils/exportFilenames.js +3 -1
  40. package/frontend/js/views/charts.js +320 -169
  41. package/frontend/js/views/connections.js +59 -64
  42. package/frontend/js/views/data.js +12 -20
  43. package/frontend/js/views/editor.js +0 -2
  44. package/frontend/js/views/settings.js +219 -5
  45. package/frontend/js/views/structure.js +27 -13
  46. package/frontend/styles/components.css +155 -0
  47. package/frontend/styles/structure-graph.css +140 -35
  48. package/frontend/styles/tailwind.generated.css +2 -2
  49. package/frontend/styles/views.css +12 -6
  50. package/package.json +7 -6
  51. package/server/middleware/apiTokenAuth.js +30 -0
  52. package/server/routes/connections.js +17 -0
  53. package/server/routes/export.js +89 -22
  54. package/server/routes/externalApi.js +304 -0
  55. package/server/routes/settings.js +90 -21
  56. package/server/server.js +22 -1
  57. package/server/services/apiTokenService.js +101 -0
  58. package/server/services/appInfoService.js +215 -0
  59. package/server/services/databaseCommandService.js +443 -0
  60. package/server/services/nativeFileDialogService.js +93 -1
  61. package/server/services/sqlite/exportService.js +307 -22
  62. package/server/services/storage/appStateStore.js +113 -0
  63. package/server/utils/errors.js +7 -0
  64. package/tests/api-token-auth.test.js +236 -0
  65. package/tests/cli-args.test.js +16 -3
  66. package/tests/cli-service-delegation.test.js +43 -0
  67. package/tests/connections-file-dialog-route.test.js +43 -0
  68. package/tests/copy-column-modal.test.js +34 -0
  69. package/tests/database-command-service.test.js +139 -0
  70. package/tests/export-blob.test.js +54 -1
  71. package/tests/export-filenames.test.js +4 -0
  72. package/tests/form-controls.test.js +34 -0
  73. package/tests/native-file-dialog.test.js +27 -0
  74. package/tests/settings-api-tokens-route.test.js +97 -0
  75. package/tests/settings-metadata.test.js +99 -1
  76. package/tests/settings-view.test.js +75 -0
  77. package/frontend/assets/mockups/connections.png +0 -0
  78. package/frontend/assets/mockups/data.png +0 -0
  79. package/frontend/assets/mockups/data_row_editor.png +0 -0
  80. package/frontend/assets/mockups/home.png +0 -0
  81. package/frontend/assets/mockups/sql_editor.png +0 -0
  82. package/frontend/assets/mockups/sql_editor_croped.png +0 -0
  83. package/frontend/assets/mockups/sql_editor_querydetail.png +0 -0
  84. package/frontend/assets/mockups/structure.png +0 -0
  85. package/frontend/assets/mockups/structure_inspector.png +0 -0
@@ -624,13 +624,35 @@
624
624
  }
625
625
 
626
626
  .status-badge {
627
+ align-items: center;
627
628
  border: 1px solid transparent;
629
+ box-sizing: border-box;
628
630
  display: inline-flex;
629
631
  font-size: var(--font-size-micro);
630
632
  font-weight: 700;
633
+ justify-content: center;
631
634
  letter-spacing: 0.12em;
635
+ line-height: 1;
632
636
  padding: 0.125rem 0.5rem;
633
637
  text-transform: uppercase;
638
+ white-space: nowrap;
639
+ }
640
+
641
+ .query-history-badge-row {
642
+ align-items: center;
643
+ display: flex;
644
+ flex-wrap: wrap;
645
+ gap: var(--spacing-2);
646
+ width: 100%;
647
+ }
648
+
649
+ .query-history-badge-row .status-badge {
650
+ min-height: var(--button-height);
651
+ min-width: 8.5rem;
652
+ }
653
+
654
+ .query-history-badge-row--compact .status-badge {
655
+ min-width: 6.75rem;
634
656
  }
635
657
 
636
658
  .status-badge--primary {
@@ -746,6 +768,76 @@
746
768
  width: clamp(20rem, 26vw, 22.5rem);
747
769
  }
748
770
 
771
+ .query-history-panel__header {
772
+ border-bottom: 1px solid var(--border-medium);
773
+ padding: var(--spacing-4);
774
+ }
775
+
776
+ .query-history-tabs {
777
+ align-items: center;
778
+ display: flex;
779
+ gap: var(--spacing-2);
780
+ margin-top: var(--spacing-4);
781
+ }
782
+
783
+ .query-history-tabs__count {
784
+ color: var(--text-variant-subtle);
785
+ font-family: var(--font-family-mono);
786
+ font-size: 10px;
787
+ letter-spacing: 0.16em;
788
+ margin-left: auto;
789
+ text-transform: uppercase;
790
+ }
791
+
792
+ .query-history-list-scroll {
793
+ flex: 1;
794
+ min-height: 0;
795
+ overflow: auto;
796
+ padding: var(--spacing-3);
797
+ }
798
+
799
+ .query-history-list {
800
+ display: flex;
801
+ flex-direction: column;
802
+ gap: var(--spacing-3);
803
+ }
804
+
805
+ .query-editor-toolbar {
806
+ align-items: center;
807
+ display: grid;
808
+ gap: var(--spacing-4);
809
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
810
+ }
811
+
812
+ .query-editor-toolbar__left,
813
+ .query-editor-toolbar__center,
814
+ .query-editor-toolbar__right {
815
+ align-items: center;
816
+ display: flex;
817
+ gap: var(--spacing-3);
818
+ }
819
+
820
+ .query-editor-toolbar__center {
821
+ flex-wrap: wrap;
822
+ justify-content: center;
823
+ }
824
+
825
+ .query-editor-toolbar__right {
826
+ justify-content: flex-end;
827
+ }
828
+
829
+ @media (max-width: 980px) {
830
+ .query-editor-toolbar {
831
+ grid-template-columns: 1fr;
832
+ }
833
+
834
+ .query-editor-toolbar__left,
835
+ .query-editor-toolbar__center,
836
+ .query-editor-toolbar__right {
837
+ justify-content: flex-start;
838
+ }
839
+ }
840
+
749
841
  .table-designer-sidebar {
750
842
  background: var(--color-surface-low);
751
843
  border-right: 1px solid var(--border-medium);
@@ -1478,6 +1570,63 @@ input.table-designer-main__name[type='text'] {
1478
1570
  background: var(--primary-alpha-08);
1479
1571
  }
1480
1572
 
1573
+ .query-history-item-main {
1574
+ display: flex;
1575
+ flex-direction: column;
1576
+ gap: var(--spacing-2);
1577
+ text-align: left;
1578
+ }
1579
+
1580
+ .query-history-item-title {
1581
+ color: var(--color-on-surface);
1582
+ display: block;
1583
+ font-family: var(--font-family-headline);
1584
+ font-size: 0.875rem;
1585
+ font-weight: 700;
1586
+ letter-spacing: 0;
1587
+ line-height: 1.15;
1588
+ min-width: 0;
1589
+ overflow: hidden;
1590
+ text-overflow: ellipsis;
1591
+ text-transform: uppercase;
1592
+ white-space: nowrap;
1593
+ width: 100%;
1594
+ }
1595
+
1596
+ .query-history-item.is-active .query-history-item-title,
1597
+ .query-history-item-hit.is-active .query-history-item-title {
1598
+ color: var(--color-primary-container);
1599
+ }
1600
+
1601
+ .query-history-item-footer {
1602
+ align-items: center;
1603
+ border-top: 1px solid var(--border-subtle);
1604
+ display: flex;
1605
+ gap: var(--spacing-3);
1606
+ justify-content: space-between;
1607
+ padding: var(--spacing-2) var(--spacing-3) var(--spacing-3);
1608
+ }
1609
+
1610
+ .query-history-item-meta {
1611
+ color: var(--text-variant-subtle);
1612
+ display: flex;
1613
+ flex-wrap: wrap;
1614
+ font-family: var(--font-family-mono);
1615
+ font-size: 10px;
1616
+ gap: var(--spacing-2);
1617
+ letter-spacing: 0.14em;
1618
+ min-width: 0;
1619
+ text-transform: uppercase;
1620
+ }
1621
+
1622
+ .query-history-item-actions {
1623
+ align-items: center;
1624
+ display: flex;
1625
+ flex-shrink: 0;
1626
+ gap: var(--spacing-1);
1627
+ margin-left: auto;
1628
+ }
1629
+
1481
1630
  .query-history-icon-button {
1482
1631
  background: transparent;
1483
1632
  border: 0;
@@ -1522,10 +1671,16 @@ input.table-designer-main__name[type='text'] {
1522
1671
  }
1523
1672
 
1524
1673
  .query-history-sql-preview {
1674
+ color: rgb(var(--rgb-on-surface-variant) / 0.75);
1525
1675
  display: -webkit-box;
1526
1676
  -webkit-box-orient: vertical;
1527
1677
  -webkit-line-clamp: 2;
1678
+ font-family: var(--font-family-mono);
1679
+ font-size: 0.75rem;
1680
+ line-height: 1.25rem;
1681
+ margin-top: var(--spacing-2);
1528
1682
  overflow: hidden;
1683
+ text-align: left;
1529
1684
  }
1530
1685
 
1531
1686
  .query-history-detail-sql {
@@ -12,26 +12,36 @@
12
12
  display: flex;
13
13
  flex-wrap: wrap;
14
14
  gap: 1rem;
15
- justify-content: space-between;
16
15
  padding: 1rem 1.25rem;
17
16
  }
18
17
 
19
18
  .structure-graph__toolbar-main {
20
19
  align-items: center;
21
20
  display: flex;
22
- flex: 1 1 20rem;
21
+ flex: 1 1 0;
23
22
  flex-wrap: wrap;
24
23
  gap: 0.875rem;
24
+ justify-content: flex-start;
25
25
  min-width: 0;
26
26
  }
27
27
 
28
28
  .structure-graph__toolbar-actions {
29
29
  align-items: center;
30
30
  display: flex;
31
- flex: 0 0 auto;
31
+ flex: 0 1 auto;
32
+ flex-wrap: wrap;
33
+ gap: 0.625rem;
34
+ justify-content: center;
35
+ }
36
+
37
+ .structure-graph__toolbar-inspector {
38
+ align-items: center;
39
+ display: flex;
40
+ flex: 1 1 0;
32
41
  flex-wrap: wrap;
33
42
  gap: 0.625rem;
34
43
  justify-content: flex-end;
44
+ min-width: 0;
35
45
  }
36
46
 
37
47
  .structure-graph__toolbar .standard-button,
@@ -72,11 +82,11 @@
72
82
 
73
83
  .structure-graph__canvas-shell {
74
84
  background:
75
- linear-gradient(rgba(138, 123, 52, 0.09) 1px, transparent 1px),
76
- linear-gradient(90deg, rgba(138, 123, 52, 0.08) 1px, transparent 1px),
77
- radial-gradient(circle at top left, rgb(var(--rgb-primary) / 0.14), transparent 30%),
78
- radial-gradient(circle at bottom right, rgba(45, 250, 255, 0.1), transparent 24%),
79
- linear-gradient(to bottom, rgba(27, 27, 24, 0.99), rgba(9, 10, 11, 0.99));
85
+ linear-gradient(rgba(201, 168, 29, 0.15) 1px, transparent 1px),
86
+ linear-gradient(90deg, rgba(201, 168, 29, 0.13) 1px, transparent 1px),
87
+ radial-gradient(circle at top left, rgb(var(--rgb-primary) / 0.2), transparent 30%),
88
+ radial-gradient(circle at bottom right, rgba(30, 246, 255, 0.16), transparent 24%),
89
+ linear-gradient(to bottom, rgba(25, 24, 16, 0.99), rgba(6, 10, 11, 0.99));
80
90
  background-size:
81
91
  28px 28px,
82
92
  28px 28px,
@@ -93,9 +103,49 @@
93
103
  position: absolute;
94
104
  }
95
105
 
106
+ .structure-graph__edge-readout {
107
+ background: rgba(5, 7, 6, 0.97);
108
+ border: 1px solid rgba(30, 246, 255, 0.68);
109
+ box-shadow:
110
+ 0 0 0 1px rgba(252, 227, 0, 0.16),
111
+ 0 14px 32px rgba(0, 0, 0, 0.48);
112
+ color: #fffbd3;
113
+ left: 0;
114
+ max-width: min(24rem, calc(100% - 1.5rem));
115
+ min-width: 14rem;
116
+ padding: 0.625rem 0.75rem;
117
+ pointer-events: none;
118
+ position: absolute;
119
+ top: 0;
120
+ z-index: 3;
121
+ }
122
+
123
+ .structure-graph__edge-readout[hidden] {
124
+ display: none;
125
+ }
126
+
127
+ .structure-graph__edge-readout-meta {
128
+ color: #1ef6ff;
129
+ font-family: var(--font-family-mono);
130
+ font-size: 0.625rem;
131
+ font-weight: 700;
132
+ letter-spacing: 0.1em;
133
+ text-transform: uppercase;
134
+ }
135
+
136
+ .structure-graph__edge-readout-path {
137
+ color: #fffbd3;
138
+ font-family: var(--font-family-mono);
139
+ font-size: 0.8125rem;
140
+ font-weight: 700;
141
+ line-height: 1.35;
142
+ margin-top: 0.25rem;
143
+ overflow-wrap: anywhere;
144
+ }
145
+
96
146
  .structure-graph__empty {
97
147
  align-items: center;
98
- color: rgba(231, 223, 189, 0.58);
148
+ color: rgba(255, 251, 211, 0.68);
99
149
  display: flex;
100
150
  flex-direction: column;
101
151
  gap: 0.625rem;
@@ -107,13 +157,13 @@
107
157
  }
108
158
 
109
159
  .structure-graph__empty-icon {
110
- color: rgb(var(--rgb-primary) / 0.42);
160
+ color: rgb(var(--rgb-primary) / 0.58);
111
161
  font-size: 2.25rem;
112
162
  }
113
163
 
114
164
  .structure-graph__inspector {
115
- background: linear-gradient(to bottom, rgba(26, 25, 23, 0.98), rgba(11, 11, 10, 0.99));
116
- border-left: 1px solid rgba(138, 123, 52, 0.24);
165
+ background: linear-gradient(to bottom, rgba(29, 27, 18, 0.98), rgba(7, 9, 9, 0.99));
166
+ border-left: 1px solid rgba(201, 168, 29, 0.36);
117
167
  height: 100%;
118
168
  min-height: 0;
119
169
  overflow-y: auto;
@@ -138,8 +188,15 @@
138
188
  text-align: center;
139
189
  }
140
190
 
191
+ .structure-graph__panel-heading {
192
+ align-items: center;
193
+ display: flex;
194
+ gap: 0.75rem;
195
+ justify-content: space-between;
196
+ }
197
+
141
198
  .structure-graph__eyebrow {
142
- color: rgba(231, 223, 189, 0.62);
199
+ color: rgba(255, 251, 211, 0.72);
143
200
  font-family: var(--font-family-mono);
144
201
  font-size: 0.625rem;
145
202
  letter-spacing: 0.2em;
@@ -158,7 +215,7 @@
158
215
  }
159
216
 
160
217
  .structure-graph__subtitle {
161
- color: rgba(231, 223, 189, 0.62);
218
+ color: rgba(255, 251, 211, 0.68);
162
219
  font-family: var(--font-family-mono);
163
220
  font-size: 0.625rem;
164
221
  letter-spacing: 0.18em;
@@ -172,8 +229,8 @@
172
229
  }
173
230
 
174
231
  .structure-graph__summary-card {
175
- background: rgba(15, 15, 13, 0.94);
176
- border: 1px solid rgba(138, 123, 52, 0.26);
232
+ background: rgba(10, 11, 10, 0.96);
233
+ border: 1px solid rgba(201, 168, 29, 0.38);
177
234
  display: flex;
178
235
  align-items: center;
179
236
  justify-content: space-between;
@@ -183,7 +240,7 @@
183
240
  }
184
241
 
185
242
  .structure-graph__summary-label {
186
- color: rgba(231, 223, 189, 0.52);
243
+ color: rgba(255, 251, 211, 0.58);
187
244
  flex: 1;
188
245
  font-family: var(--font-family-mono);
189
246
  font-size: 0.5625rem;
@@ -202,8 +259,8 @@
202
259
  }
203
260
 
204
261
  .structure-graph__section {
205
- background: rgba(15, 15, 13, 0.84);
206
- border: 1px solid rgba(138, 123, 52, 0.22);
262
+ background: rgba(8, 10, 9, 0.9);
263
+ border: 1px solid rgba(201, 168, 29, 0.32);
207
264
  display: flex;
208
265
  flex-direction: column;
209
266
  gap: 0.875rem;
@@ -248,7 +305,7 @@
248
305
  }
249
306
 
250
307
  .structure-graph__column-type {
251
- color: rgba(231, 223, 189, 0.58);
308
+ color: rgba(255, 251, 211, 0.62);
252
309
  font-family: var(--font-family-mono);
253
310
  font-size: 0.625rem;
254
311
  letter-spacing: 0.14em;
@@ -263,9 +320,9 @@
263
320
  }
264
321
 
265
322
  .structure-graph__flag {
266
- background: rgba(39, 38, 34, 0.94);
267
- border: 1px solid rgba(138, 123, 52, 0.24);
268
- color: rgba(244, 239, 232, 0.82);
323
+ background: rgba(48, 43, 18, 0.96);
324
+ border: 1px solid rgba(201, 168, 29, 0.4);
325
+ color: rgba(255, 251, 211, 0.86);
269
326
  font-family: var(--font-family-mono);
270
327
  font-size: 0.5625rem;
271
328
  letter-spacing: 0.14em;
@@ -274,19 +331,19 @@
274
331
  }
275
332
 
276
333
  .structure-graph__flag.is-key {
277
- background: var(--primary-alpha-18);
278
- border-color: rgb(var(--rgb-primary) / 0.34);
279
- color: #fff6ae;
334
+ background: rgb(var(--rgb-primary) / 0.24);
335
+ border-color: rgb(var(--rgb-primary) / 0.58);
336
+ color: #fffbd3;
280
337
  }
281
338
 
282
339
  .structure-graph__flag.is-link {
283
- background: rgba(45, 250, 255, 0.14);
284
- border-color: rgba(45, 250, 255, 0.28);
285
- color: #9ffcff;
340
+ background: rgba(30, 246, 255, 0.18);
341
+ border-color: rgba(30, 246, 255, 0.52);
342
+ color: #c9fdff;
286
343
  }
287
344
 
288
345
  .structure-graph__flag.is-nullable {
289
- color: rgba(231, 223, 189, 0.58);
346
+ color: rgba(255, 251, 211, 0.62);
290
347
  }
291
348
 
292
349
  .structure-graph__list {
@@ -304,15 +361,59 @@
304
361
  }
305
362
 
306
363
  .structure-graph__list-item-label {
307
- color: rgba(231, 223, 189, 0.62);
364
+ color: rgba(255, 251, 211, 0.68);
308
365
  font-family: var(--font-family-mono);
309
366
  font-size: 0.625rem;
310
367
  letter-spacing: 0.14em;
311
368
  text-transform: uppercase;
312
369
  }
313
370
 
371
+ .structure-graph__join-flow {
372
+ align-items: center;
373
+ display: grid;
374
+ gap: 0.625rem;
375
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
376
+ }
377
+
378
+ .structure-graph__join-table {
379
+ background: rgba(48, 43, 18, 0.96);
380
+ border: 1px solid rgba(201, 168, 29, 0.42);
381
+ color: #fffbd3;
382
+ font-family: var(--font-family-mono);
383
+ font-size: 0.6875rem;
384
+ font-weight: 700;
385
+ overflow-wrap: anywhere;
386
+ padding: 0.5rem 0.625rem;
387
+ }
388
+
389
+ .structure-graph__join-arrow {
390
+ color: #1ef6ff;
391
+ font-size: 1rem;
392
+ }
393
+
394
+ .structure-graph__join-condition-list {
395
+ display: flex;
396
+ flex-direction: column;
397
+ gap: 0.5rem;
398
+ }
399
+
400
+ .structure-graph__join-condition {
401
+ align-items: center;
402
+ color: rgba(255, 251, 211, 0.82);
403
+ display: grid;
404
+ font-family: var(--font-family-mono);
405
+ font-size: 0.625rem;
406
+ gap: 0.5rem;
407
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
408
+ }
409
+
410
+ .structure-graph__join-condition span {
411
+ min-width: 0;
412
+ overflow-wrap: anywhere;
413
+ }
414
+
314
415
  .structure-graph__ddl {
315
- color: rgba(244, 239, 232, 0.78);
416
+ color: rgba(255, 251, 211, 0.82);
316
417
  font-family: var(--font-family-mono);
317
418
  font-size: 0.6875rem;
318
419
  line-height: 1.65;
@@ -322,13 +423,17 @@
322
423
  white-space: pre-wrap;
323
424
  }
324
425
 
426
+ .structure-graph__join-sql {
427
+ max-height: 14rem;
428
+ }
429
+
325
430
  .structure-entry--graph-active {
326
- border-color: rgb(var(--rgb-primary) / 0.44);
327
- box-shadow: inset 0 0 0 1px var(--primary-alpha-18);
431
+ border-color: rgb(var(--rgb-primary) / 0.6);
432
+ box-shadow: inset 0 0 0 1px rgb(var(--rgb-primary) / 0.28);
328
433
  }
329
434
 
330
435
  .structure-entry--graph-related {
331
- border-color: rgba(45, 250, 255, 0.34);
436
+ border-color: rgba(30, 246, 255, 0.58);
332
437
  }
333
438
 
334
439
  @media (max-width: 1279px) {