From b5bc6c3774dcfeac87b7429ddd6b2ba6f1589ac3 Mon Sep 17 00:00:00 2001 From: javl Date: Fri, 14 Aug 2026 16:13:15 +0200 Subject: [PATCH] restyle test --- css/style.css | 765 +++++++++++++++++++++++++++++++++++++++++++------- index.html | 94 +++++-- js/script.js | 3 +- restyle.md | 404 ++++++++++++++++++++++++++ 4 files changed, 1145 insertions(+), 121 deletions(-) create mode 100644 restyle.md diff --git a/css/style.css b/css/style.css index 96d4400..b76621f 100644 --- a/css/style.css +++ b/css/style.css @@ -1,63 +1,367 @@ +:root { + /* Colors (from restyle design tokens) */ + --primary: #006b58; + --primary-container: #1abc9c; + --on-primary: #ffffff; + --on-primary-container: #004538; + --secondary: #4e6073; + --on-secondary: #ffffff; + --on-secondary-container: #526478; + --background: #f7f9fb; + --surface: #f7f9fb; + --surface-container-lowest: #ffffff; + --surface-container-low: #f2f4f6; + --surface-container: #eceef0; + --surface-container-high: #e6e8ea; + --surface-container-highest: #e0e3e5; + --on-surface: #191c1e; + --on-surface-variant: #3c4a45; + --on-background: #191c1e; + --text-muted: #64748b; + --border-subtle: #e2e8f0; + --outline: #6c7a75; + --outline-variant: #bbcac3; + --editor-bg: #1e1e1e; + --error: #ba1a1a; + + /* Radii */ + --radius: 0.125rem; + --radius-lg: 0.25rem; + --radius-xl: 0.5rem; + --radius-full: 0.75rem; + + /* Fonts */ + --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +} + * { margin: 0; padding: 0; + box-sizing: border-box; } -body{ - font-family: arial; +body { + font-family: var(--font-body); + font-size: 16px; + line-height: 24px; + color: var(--on-background); + background-color: var(--background); + min-height: 100vh; +} + +/* ---- Top nav bar ---- */ + +.topnav { + position: sticky; + top: 0; + z-index: 50; + background: var(--surface-container-lowest); + border-bottom: 1px solid var(--border-subtle); +} + +.topnav-inner { + max-width: 1200px; + margin: auto; + height: 64px; + padding: 0 24px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.topnav-left { + display: flex; + align-items: center; + gap: 32px; +} + +.brand { + font-size: 20px; + font-weight: 700; + color: var(--primary); +} + +.topnav-links { + display: flex; + gap: 24px; +} + +.topnav-links a { + color: var(--secondary); + font-weight: 500; + font-size: 14px; +} + +.topnav-links a:hover { + color: var(--primary); + text-decoration: none; +} + +.topnav-right { + display: flex; + align-items: center; + gap: 12px; +} + +.icon-btn { + background: transparent; + color: var(--secondary); + border: none; + font-size: 18px; + line-height: 1; + padding: 6px; + margin: 0; + border-radius: var(--radius-lg); + cursor: pointer; +} + +.icon-btn:hover { + color: var(--primary); + background: var(--surface-container); + opacity: 1; +} + +.theme-icon-light { + display: none; +} + +.btn-reset { + margin: 0; +} + +/* ---- Layout: sidebar + main ---- */ + +.layout { + display: flex; + gap: 32px; + max-width: 1200px; + margin: auto; + padding: 32px 24px 64px; + align-items: flex-start; +} + +.sidebar { + position: sticky; + top: 96px; + flex: 0 0 220px; + width: 220px; + background: var(--surface-container-low); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-xl); + padding: 24px 0; +} + +.sidebar-nav { + display: flex; + flex-direction: column; +} + +.sidebar-link { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 24px; + font-family: var(--font-mono); + font-size: 13px; + font-weight: 500; + color: var(--secondary); + border-right: 3px solid transparent; +} + +.sidebar-link:hover { + background: var(--surface-container-high); + text-decoration: none; +} + +.sidebar-link.active { + color: var(--primary); + font-weight: 700; + background: rgba(26, 188, 156, 0.1); + border-right-color: var(--primary); +} + +.sidebar-num { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + border-radius: 4px; + background: var(--surface-container-high); + color: var(--secondary); + font-size: 12px; + font-weight: 700; + flex-shrink: 0; +} + +.sidebar-link.active .sidebar-num { + background: var(--primary); + color: var(--on-primary); } .wrapper { display: flex; flex-direction: column; - margin: auto; - width: 900px; + gap: 24px; + flex: 1; + min-width: 0; } +/* ---- Step number rail ---- */ + +.section.step { + position: relative; + padding-left: 72px; + scroll-margin-top: 88px; +} + +.step-num { + position: absolute; + left: 16px; + top: 32px; + width: 40px; + height: 40px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + background: var(--surface-container-high); + color: var(--secondary); + border: 1px solid var(--border-subtle); + z-index: 2; +} + +.active .step-num { + background: var(--primary); + color: var(--on-primary); + border-color: var(--primary); +} + +.step::before { + content: ""; + position: absolute; + left: 35px; + top: 40px; + bottom: -24px; + width: 2px; + background: var(--border-subtle); + z-index: 1; +} + +#step-4.step::before { + display: none; +} + +/* ---- Typography ---- */ + +h1 { + font-size: 30px; + line-height: 38px; + letter-spacing: -0.02em; + font-weight: 600; + color: var(--primary); + margin-bottom: 8px; +} + +h2 { + font-size: 20px; + line-height: 28px; + font-weight: 600; + color: var(--on-surface); +} + +.sub-section-title { + font-family: var(--font-mono); + font-size: 13px; + line-height: 16px; + font-weight: 500; + color: var(--primary); + margin: 0 0 12px; +} + +p { + margin: 16px 0; + color: var(--on-surface-variant); +} + +a { + color: var(--primary); + text-decoration: none; + font-weight: 500; +} + +a:hover { + text-decoration: underline; +} + +code { + font-family: var(--font-mono); + font-size: 0.9em; + background: var(--surface-container); + padding: 1px 5px; + border-radius: var(--radius-lg); +} + +/* ---- Section cards ---- */ + .section { - margin: 10px 0; + background: var(--surface-container-lowest); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-xl); + padding: 32px; } +/* First (intro) section: keep it flush/light */ +.section:first-child { + background: transparent; + border: none; + padding: 8px 0 0; +} + +.section h2 { + margin-bottom: 16px; +} + +/* Legacy divider no longer needed; cards separate content */ .bottom-divider { - border-bottom: 2px solid #000000; - padding-bottom: 20px; + border-bottom: none; + padding-bottom: 32px; } .sub-section { clear: both; - margin-bottom: 1px; -} - -.section, -.sub-section { width: 100%; } +.section { + width: 100%; +} + +/* ---- Multi-column (select image row) ---- */ + .column { float: left; } .column-center { - min-width: 160px; + min-width: 120px; text-align: center; + color: var(--text-muted); } .column-right { float: right; } -.sub-section-title { - margin: 0 0 10px; -} - -p { - margin: 20px 0; -} +/* ---- Table layout for settings ---- */ .table { display: table; - margin: 10px 0 0; + margin: 8px 0 0; width: 100%; + border-collapse: collapse; } .table-row { @@ -67,11 +371,13 @@ p { .table-cell { display: table-cell; - padding: 5px 0; + padding: 10px 0; + vertical-align: top; } .table-cell:first-child { width: 30%; + padding-right: 16px; } .table-cell:last-child { @@ -79,11 +385,16 @@ p { } .table-cell:first-child label { - font-weight: bold; + font-family: var(--font-mono); + font-size: 13px; + font-weight: 500; + color: var(--primary); } .table-cell:last-child label { margin-right: 10px; + color: var(--on-surface-variant); + font-size: 14px; } .nested-table { @@ -91,83 +402,99 @@ p { } .nested-table .table-cell { - color: #666; - font-size: .9em; + color: var(--text-muted); + font-size: 0.9em; width: 200px; } #format-caption-container div { - color: #505050; + color: var(--text-muted); display: none; - font-size: .9em; - line-height: 1.4em; + font-size: 14px; + line-height: 1.5em; padding: 10px 0 15px; width: 100%; } +/* ---- Notes / messages ---- */ + +.note { + color: var(--text-muted); + font-size: 14px; + line-height: 1.5em; + margin: 4px 0; +} + .upload-note { - max-width: 300px; + max-width: 320px; +} + +.msg { + font-size: 16px; + color: var(--text-muted); +} + +.error-msg { + color: var(--error); + display: none; +} + +/* ---- Form controls ---- */ + +input[type="text"], +input[type="number"], +textarea, +select { + font-family: var(--font-body); + font-size: 14px; + color: var(--on-surface-variant); + background: var(--surface-container); + border: 1px solid transparent; + border-radius: var(--radius-lg); + padding: 8px 10px; + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} + +input[type="text"]:focus, +input[type="number"]:focus, +textarea:focus, +select:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(0, 107, 88, 0.25); +} + +select { + cursor: pointer; +} + +input[type="checkbox"], +input[type="radio"] { + accent-color: var(--primary); + width: 16px; + height: 16px; + vertical-align: middle; + cursor: pointer; } .byte-input { min-height: 160px; min-width: 360px; -} - -.code-output { - height: 200px; width: 100%; + font-family: var(--font-mono); + font-size: 14px; + line-height: 22px; + resize: vertical; } -.note { - color: #666666; - font-size: .9em; - line-height: 1.4em; - margin: 3px 0; +.text-input-size { + margin: 8px 0; + color: var(--on-surface-variant); + font-size: 14px; } -.file-input-entry { - display: flex; - justify-content: space-between; - margin-bottom: 10px; -} - -button, -input[type="file"] { - background: #00CB99; - border-radius: 3px; - border: none; - color: #fff; - font-size: .9em; - font-weight: bold; - margin: 10px 0 0 0; - padding: 4px 8px; -} - -input[type="file"] { - font-size: 1.0em; - padding: 6px 20px; -} - -.generate-button { - margin: 40px 0 20px; -} - -.remove-button { - margin: 0 0 0 10px; - padding: 1px 4px; -} - -.file-info { - color: #505050; - font-size: .7em; - margin-left: 20px; - max-width: 300px; - white-space: pre; -} - -.size-input{ - width: 45px; +.size-input { + width: 72px; } .glyph-input { @@ -175,18 +502,122 @@ input[type="file"] { margin-left: 10px; } +.text-input { + font-family: var(--font-mono); +} + +/* ---- Buttons ---- */ + +button { + font-family: var(--font-mono); + font-size: 13px; + font-weight: 500; + background: var(--primary-container); + color: var(--on-primary-container); + border: none; + border-radius: var(--radius-lg); + padding: 8px 16px; + margin: 10px 8px 0 0; + cursor: pointer; + transition: opacity 0.15s ease, background-color 0.15s ease; +} + +button:hover { + opacity: 0.9; +} + +button:active { + opacity: 0.8; +} + +input[type="file"] { + background: var(--surface-container); + color: var(--on-surface-variant); + border: 2px dashed var(--outline-variant); + border-radius: var(--radius-lg); + font-size: 14px; + padding: 16px 20px; + margin: 10px 0 0; + cursor: pointer; + width: 100%; + max-width: 360px; +} + +input[type="file"]:hover { + background: var(--surface-container-high); +} + +input[type="file"]::file-selector-button { + font-family: var(--font-mono); + font-weight: 500; + background: var(--primary-container); + color: var(--on-primary-container); + border: none; + border-radius: var(--radius-lg); + padding: 6px 12px; + margin-right: 12px; + cursor: pointer; +} + +.generate-button { + background: var(--primary); + color: var(--on-primary); + margin: 32px 8px 20px 0; + padding: 10px 20px; +} + +#copy-button, +#download-button { + background: var(--secondary); + color: var(--on-secondary); + margin-top: 32px; +} + +.remove-button { + margin: 0 0 0 10px; + padding: 2px 8px; + background: var(--surface-container-high); + color: var(--on-surface-variant); +} + +/* ---- File info / size list ---- */ + +.file-input-entry { + display: flex; + justify-content: space-between; + margin-bottom: 10px; +} + +.file-info { + color: var(--text-muted); + font-size: 12px; + margin-left: 20px; + max-width: 320px; + white-space: pre; +} + +.file-name { + display: block; + margin-left: 0; + margin-bottom: 8px; + font-weight: 500; + color: var(--on-surface-variant); +} + +/* Tighten gap between a row and the explanatory note row that follows */ +.note-row .table-cell { + padding-top: 0; +} + #image-size-settings { list-style-type: none; } #image-size-settings li { - margin: 4px 0; + margin: 6px 0; } -#images-canvas-container canvas { - border: 3px solid #88DAC5; - margin: 10px 15px; -} +/* ---- Preview canvases ---- */ #images-canvas-container { align-items: flex-start; @@ -194,33 +625,165 @@ input[type="file"] { flex-wrap: wrap; } +#images-canvas-container canvas { + border: 1px solid var(--outline-variant); + border-radius: var(--radius-lg); + background: var(--editor-bg); + margin: 10px 15px 10px 0; + padding: 4px; +} + +.inlineImg { + border-radius: var(--radius-lg); + margin-top: 8px; +} + +/* ---- Code output (dark editor look) ---- */ + +.code-output { + height: 400px; + width: 100%; + margin-top: 16px; + background: var(--editor-bg); + color: #dcdcaa; + border: 1px solid var(--on-surface-variant); + border-radius: var(--radius-xl); + font-family: var(--font-mono); + font-size: 14px; + line-height: 22px; + padding: 20px; + resize: vertical; +} + +.code-output:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(0, 107, 88, 0.25); +} + +/* ---- Hidden by default (toggled via JS) ---- */ + #arduino-identifier, #adafruit-gfx-settings, #all-same-size { display: none; } -.msg { - font-size: 1.2em; +/* ---- Sponsor block ---- */ + +.sp-block { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px; } -.error-msg { - color: #ff0000; +.sp-block img { + vertical-align: middle; +} + +/* ---- Responsive ---- */ + +@media (max-width: 900px) { + .layout { + flex-direction: column; + } + + .sidebar { + position: static; + width: 100%; + flex: none; + } + + .sidebar-nav { + flex-direction: row; + flex-wrap: wrap; + } + + .sidebar-link { + border-right: none; + border-radius: var(--radius-lg); + } + + .sidebar-link.active { + border-right: none; + } +} + +@media (max-width: 640px) { + .topnav-links { + display: none; + } + + .section.step { + padding-left: 32px; + } + + .step-num { + position: static; + margin-bottom: 16px; + } + + .step::before { + display: none; + } + + .column, + .column-right { + float: none; + width: 100%; + } + + .byte-input { + min-width: 0; + } + + .table-cell:first-child, + .table-cell:last-child { + display: block; + width: 100%; + } + + .table-cell:first-child { + padding-bottom: 0; + } +} + +/* ---- Dark theme ---- */ + +:root[data-theme="dark"] { + --primary: #4eddbb; + --primary-container: #1abc9c; + --on-primary: #003a2e; + --on-primary-container: #e5fff7; + --secondary: #b5c8df; + --on-secondary: #17293b; + --on-secondary-container: #cfe2f9; + --background: #0f1416; + --surface: #0f1416; + --surface-container-lowest: #171d1f; + --surface-container-low: #1a2124; + --surface-container: #22282b; + --surface-container-high: #2a3033; + --surface-container-highest: #343a3d; + --on-surface: #e0e3e5; + --on-surface-variant: #c3d0c9; + --on-background: #e0e3e5; + --text-muted: #8a9a94; + --border-subtle: #2d3133; + --outline: #8a938f; + --outline-variant: #414a47; + --editor-bg: #0b0e0f; +} + +:root[data-theme="dark"] .theme-icon-dark { display: none; } -h1{ - padding: 10px; - color: white; - background-color: #00cb99; +:root[data-theme="dark"] .theme-icon-light { + display: inline; } -/*.sp-block { - border: 1px solid rgb(65, 65, 65); - padding: .5rem; - border-radius: 1rem; +:root[data-theme="dark"] .sidebar-link.active { + background: rgba(26, 188, 156, 0.18); } -.sp-btn { - display: block; - margin-top: .5rem; -}*/ diff --git a/index.html b/index.html index 0f3bcaa..9d24cff 100644 --- a/index.html +++ b/index.html @@ -3,12 +3,43 @@ image2cpp + + + -
+
+
+
+ image2cpp + +
+
+ + +
+
+
+ +
+ + +

image2cpp

image2cpp is a simple tool to change images into byte arrays (or arrays back into an images) for use with (monochrome) displays such as OLEDs on your Arduino or Raspberry Pi.
@@ -17,20 +48,16 @@

More info (and credits) can be found in the Github repository. This is also where you can report any issues you might come across.

Did you find this tool useful? Feel free to support my open source software on Github, especially if used commercially.
- - GitHub Sponsor - - - Buy Me A Coffee - - + GitHub Sponsor + BMC

-
+
+
1
-

1. Select image

+

Select image

All processing is done locally in your browser; your images are not uploaded or stored anywhere online.

@@ -38,7 +65,7 @@

or

-

1. Paste byte array

+

Paste byte array


x @@ -53,8 +80,9 @@ -
-

2. Image Settings

+
+
2
+

Image Settings

@@ -131,7 +159,7 @@
-
+
Centering the image only works when using a canvas larger than the original image. @@ -165,16 +193,18 @@ -
-

3. Preview

+
+
3
+

Preview

No files selected
-
-

4. Output

+
+
4
+

Output

@@ -286,7 +316,35 @@
+
+ diff --git a/js/script.js b/js/script.js index bef3c87..18f75be 100644 --- a/js/script.js +++ b/js/script.js @@ -808,9 +808,8 @@ function handleImageSelection(evt) { }; const fn = document.createElement('span'); - fn.className = 'file-info'; + fn.className = 'file-info file-name'; fn.innerHTML = `${file.name} (file resolution: ${img.width} x ${img.height})`; - fn.innerHTML += '
'; const rb = document.createElement('button'); rb.className = 'remove-button'; diff --git a/restyle.md b/restyle.md new file mode 100644 index 0000000..607bb59 --- /dev/null +++ b/restyle.md @@ -0,0 +1,404 @@ + + + +image2cpp | Image to Byte Array Converter + + + + + + + + + +
+
+
+image2cpp + +
+
+ + +
+
+
+
+ + + +
+
+

Image to C++ Converter

+

Generate monochrome byte arrays for OLED displays on Arduino or Raspberry Pi. All processing happens in your browser.

+
Support onfavoritecoffee
+ +
+ +
+
+
1
+
+
+
+ +
+cloud_upload +

Drag and drop images here or Browse

+

Supports JPG, PNG, BMP, GIF

+ +
+
+
+ + +
+
+
+
+ +
+
+
2
+
+

Image Configuration

+
+ +
+ +
+ +× + +
+
+ +
+ +
+ + + +
+
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +128 +
+
+ +
+ +
+ +
+ + +
+
+
+
+
+
+ +
+
+
3
+
+
+

Preview

+
+ + +
+
+
+
+Original +
+ +
+
+
+Converted (1-bit) +
+ + +
+
+
+
+
+ +
+
+
4
+
+
+
+

Output Settings

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+ + + +
+
+
+
+
// Generated by image2cpp
+// 128x64px, myBitmap
+
+const unsigned char myBitmap [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +
+
+info +

If the preview looks scrambled on your hardware, try switching the Draw Mode between Horizontal and Vertical. +

+
+
+
+
+
+
+
+
+ + + + +