mirror of
https://github.com/javl/image2cpp.git
synced 2026-09-11 09:03:04 +00:00
restyle test
This commit is contained in:
+664
-101
@@ -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;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
body{
|
body {
|
||||||
font-family: arial;
|
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 {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: auto;
|
gap: 24px;
|
||||||
width: 900px;
|
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 {
|
.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 {
|
.bottom-divider {
|
||||||
border-bottom: 2px solid #000000;
|
border-bottom: none;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-section {
|
.sub-section {
|
||||||
clear: both;
|
clear: both;
|
||||||
margin-bottom: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section,
|
|
||||||
.sub-section {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Multi-column (select image row) ---- */
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-center {
|
.column-center {
|
||||||
min-width: 160px;
|
min-width: 120px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-right {
|
.column-right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-section-title {
|
/* ---- Table layout for settings ---- */
|
||||||
margin: 0 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
.table {
|
||||||
display: table;
|
display: table;
|
||||||
margin: 10px 0 0;
|
margin: 8px 0 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-row {
|
.table-row {
|
||||||
@@ -67,11 +371,13 @@ p {
|
|||||||
|
|
||||||
.table-cell {
|
.table-cell {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding: 5px 0;
|
padding: 10px 0;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-cell:first-child {
|
.table-cell:first-child {
|
||||||
width: 30%;
|
width: 30%;
|
||||||
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-cell:last-child {
|
.table-cell:last-child {
|
||||||
@@ -79,11 +385,16 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table-cell:first-child label {
|
.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 {
|
.table-cell:last-child label {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
color: var(--on-surface-variant);
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nested-table {
|
.nested-table {
|
||||||
@@ -91,83 +402,99 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nested-table .table-cell {
|
.nested-table .table-cell {
|
||||||
color: #666;
|
color: var(--text-muted);
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#format-caption-container div {
|
#format-caption-container div {
|
||||||
color: #505050;
|
color: var(--text-muted);
|
||||||
display: none;
|
display: none;
|
||||||
font-size: .9em;
|
font-size: 14px;
|
||||||
line-height: 1.4em;
|
line-height: 1.5em;
|
||||||
padding: 10px 0 15px;
|
padding: 10px 0 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- Notes / messages ---- */
|
||||||
|
|
||||||
|
.note {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.upload-note {
|
.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 {
|
.byte-input {
|
||||||
min-height: 160px;
|
min-height: 160px;
|
||||||
min-width: 360px;
|
min-width: 360px;
|
||||||
}
|
|
||||||
|
|
||||||
.code-output {
|
|
||||||
height: 200px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note {
|
.text-input-size {
|
||||||
color: #666666;
|
margin: 8px 0;
|
||||||
font-size: .9em;
|
color: var(--on-surface-variant);
|
||||||
line-height: 1.4em;
|
font-size: 14px;
|
||||||
margin: 3px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-input-entry {
|
.size-input {
|
||||||
display: flex;
|
width: 72px;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.glyph-input {
|
.glyph-input {
|
||||||
@@ -175,18 +502,122 @@ input[type="file"] {
|
|||||||
margin-left: 10px;
|
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 {
|
#image-size-settings {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#image-size-settings li {
|
#image-size-settings li {
|
||||||
margin: 4px 0;
|
margin: 6px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#images-canvas-container canvas {
|
/* ---- Preview canvases ---- */
|
||||||
border: 3px solid #88DAC5;
|
|
||||||
margin: 10px 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#images-canvas-container {
|
#images-canvas-container {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -194,33 +625,165 @@ input[type="file"] {
|
|||||||
flex-wrap: wrap;
|
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,
|
#arduino-identifier,
|
||||||
#adafruit-gfx-settings,
|
#adafruit-gfx-settings,
|
||||||
#all-same-size {
|
#all-same-size {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg {
|
/* ---- Sponsor block ---- */
|
||||||
font-size: 1.2em;
|
|
||||||
|
.sp-block {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-msg {
|
.sp-block img {
|
||||||
color: #ff0000;
|
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;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1{
|
:root[data-theme="dark"] .theme-icon-light {
|
||||||
padding: 10px;
|
display: inline;
|
||||||
color: white;
|
|
||||||
background-color: #00cb99;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.sp-block {
|
:root[data-theme="dark"] .sidebar-link.active {
|
||||||
border: 1px solid rgb(65, 65, 65);
|
background: rgba(26, 188, 156, 0.18);
|
||||||
padding: .5rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
}
|
}
|
||||||
.sp-btn {
|
|
||||||
display: block;
|
|
||||||
margin-top: .5rem;
|
|
||||||
}*/
|
|
||||||
|
|||||||
+76
-18
@@ -3,12 +3,43 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>image2cpp</title>
|
<title>image2cpp</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||||
<script src="./js/dithering.js" defer></script>
|
<script src="./js/dithering.js" defer></script>
|
||||||
<script src="./js/script.js" defer></script>
|
<script src="./js/script.js" defer></script>
|
||||||
<link rel="stylesheet" href="./css/style.css">
|
<link rel="stylesheet" href="./css/style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<header class="topnav">
|
||||||
|
<div class="topnav-inner">
|
||||||
|
<div class="topnav-left">
|
||||||
|
<span class="brand">image2cpp</span>
|
||||||
|
<nav class="topnav-links">
|
||||||
|
<a href="https://github.com/javl/image2cpp" target="_blank">GitHub Repository</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="topnav-right">
|
||||||
|
<button class="icon-btn" id="theme-toggle" title="Toggle dark mode" aria-label="Toggle dark mode">
|
||||||
|
<span class="theme-icon-dark">☽</span>
|
||||||
|
<span class="theme-icon-light">☼</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn-reset" onclick="location.reload()">Reset page</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="sidebar">
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<a href="#step-1" class="sidebar-link" data-step="step-1"><span class="sidebar-num">1</span>Select Image</a>
|
||||||
|
<a href="#step-2" class="sidebar-link" data-step="step-2"><span class="sidebar-num">2</span>Settings</a>
|
||||||
|
<a href="#step-3" class="sidebar-link" data-step="step-3"><span class="sidebar-num">3</span>Preview</a>
|
||||||
|
<a href="#step-4" class="sidebar-link" data-step="step-4"><span class="sidebar-num">4</span>Output</a>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="wrapper">
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<h1>image2cpp</h1>
|
<h1>image2cpp</h1>
|
||||||
<p><strong>image2cpp</strong> 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.<br>
|
<p><strong>image2cpp</strong> 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.<br>
|
||||||
@@ -17,20 +48,16 @@
|
|||||||
<p>More info (and credits) can be found in the <a href="https://github.com/javl/image2cpp" target="_blank">Github repository</a>. This is also where you can report any <a href="https://github.com/javl/image2cpp/issues" target="_blank">issues</a> you might come across.</p>
|
<p>More info (and credits) can be found in the <a href="https://github.com/javl/image2cpp" target="_blank">Github repository</a>. This is also where you can report any <a href="https://github.com/javl/image2cpp/issues" target="_blank">issues</a> you might come across.</p>
|
||||||
<p class="sp-block">
|
<p class="sp-block">
|
||||||
Did you find this tool useful? Feel free to support my open source software on Github, especially if used commercially.<br />
|
Did you find this tool useful? Feel free to support my open source software on Github, especially if used commercially.<br />
|
||||||
<a href="https://github.com/sponsors/javl" target="_blank">
|
<a href="https://github.com/sponsors/javl"><img src="https://camo.githubusercontent.com/7fcc34127227d7a0293435c20a74bce4bf3eb26d86f6c5000aa620da147223dd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5f2d73706f6e736f725f6f6e5f4769746875622d626c75653f6c6f676f3d676974687562" alt="GitHub Sponsor" data-canonical-src="https://img.shields.io/badge/_-sponsor_on_Github-blue?logo=github" style="max-width: 100%;"></a>
|
||||||
<img src="https://img.shields.io/github/sponsors/javl?label=Sponsor&logo=GitHub" alt="GitHub Sponsor">
|
<a href="https://www.buymeacoffee.com/javl" rel="nofollow"><img src="https://camo.githubusercontent.com/0eeabd01753f37f754419d1b3f1b9fd755b1653c23283c8c8b17b1fbb18191e4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4275795f4d655f615f436f666665652d6f72616e67653f6c6f676f3d6275796d6561636f66666565" alt="BMC" data-canonical-src="https://img.shields.io/badge/Buy_Me_a_Coffee-orange?logo=buymeacoffee" style="max-width: 100%;"></a>
|
||||||
</a>
|
|
||||||
<a href="https://www.buymeacoffee.com/javl" target="_blank" rel="noopener">
|
|
||||||
<img decoding="async" class="" style="height: 34px; width: 123px;" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section bottom-divider">
|
<section class="section step bottom-divider" id="step-1">
|
||||||
|
<div class="step-num">1</div>
|
||||||
<section class="sub-section">
|
<section class="sub-section">
|
||||||
<div class="column" id="file-input-column">
|
<div class="column" id="file-input-column">
|
||||||
<h2 class="sub-section-title">1. Select image</h2>
|
<h2 class="sub-section-title">Select image</h2>
|
||||||
<div class="note upload-note">All processing is done locally in your browser; your images are not uploaded or stored anywhere online.</div>
|
<div class="note upload-note">All processing is done locally in your browser; your images are not uploaded or stored anywhere online.</div>
|
||||||
<input type="file" id="file-input" name="file-input" multiple/><br />
|
<input type="file" id="file-input" name="file-input" multiple/><br />
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +65,7 @@
|
|||||||
<h2 class="sub-section-title">or</h2>
|
<h2 class="sub-section-title">or</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="column column-right">
|
<div class="column column-right">
|
||||||
<h2 class="sub-section-title">1. Paste byte array</h2>
|
<h2 class="sub-section-title">Paste byte array</h2>
|
||||||
<textarea id="byte-input" class="byte-input"></textarea><br />
|
<textarea id="byte-input" class="byte-input"></textarea><br />
|
||||||
<div class="text-input-size">
|
<div class="text-input-size">
|
||||||
<input type="number" min="0" id="text-input-width" class="size-input" value="128" /> x
|
<input type="number" min="0" id="text-input-width" class="size-input" value="128" /> x
|
||||||
@@ -53,8 +80,9 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section bottom-divider">
|
<section class="section step bottom-divider" id="step-2">
|
||||||
<h2>2. Image Settings</h2>
|
<div class="step-num">2</div>
|
||||||
|
<h2>Image Settings</h2>
|
||||||
<section class="sub-section">
|
<section class="sub-section">
|
||||||
<div class="table">
|
<div class="table">
|
||||||
|
|
||||||
@@ -131,7 +159,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-row">
|
<div class="table-row note-row">
|
||||||
<div class="table-cell"></div>
|
<div class="table-cell"></div>
|
||||||
<div class="table-cell">
|
<div class="table-cell">
|
||||||
<i class="note">Centering the image only works when using a canvas larger than the original image.</i>
|
<i class="note">Centering the image only works when using a canvas larger than the original image.</i>
|
||||||
@@ -165,16 +193,18 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section bottom-divider">
|
<section class="section step bottom-divider" id="step-3">
|
||||||
<h2>3. Preview</h2>
|
<div class="step-num">3</div>
|
||||||
|
<h2>Preview</h2>
|
||||||
<section class="sub-section">
|
<section class="sub-section">
|
||||||
<div class="no-file-selected" class="msg">No files selected</div>
|
<div class="no-file-selected" class="msg">No files selected</div>
|
||||||
<div id="images-canvas-container"></div>
|
<div id="images-canvas-container"></div>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section step" id="step-4">
|
||||||
<h2>4. Output</h2>
|
<div class="step-num">4</div>
|
||||||
|
<h2>Output</h2>
|
||||||
<section class="sub-section">
|
<section class="sub-section">
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<div class="table-row">
|
<div class="table-row">
|
||||||
@@ -286,7 +316,35 @@
|
|||||||
<textarea id="code-output" class="code-output"></textarea>
|
<textarea id="code-output" class="code-output"></textarea>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Dark mode toggle (persisted)
|
||||||
|
(function () {
|
||||||
|
var root = document.documentElement;
|
||||||
|
var stored = localStorage.getItem('theme');
|
||||||
|
if (stored) root.setAttribute('data-theme', stored);
|
||||||
|
var btn = document.getElementById('theme-toggle');
|
||||||
|
if (btn) btn.addEventListener('click', function () {
|
||||||
|
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
|
||||||
|
root.setAttribute('data-theme', next);
|
||||||
|
localStorage.setItem('theme', next);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sidebar scrollspy
|
||||||
|
var links = Array.prototype.slice.call(document.querySelectorAll('.sidebar-link'));
|
||||||
|
var steps = links.map(function (l) { return document.getElementById(l.dataset.step); });
|
||||||
|
function onScroll() {
|
||||||
|
var pos = window.scrollY + 120;
|
||||||
|
var active = 0;
|
||||||
|
steps.forEach(function (s, i) { if (s && s.offsetTop <= pos) active = i; });
|
||||||
|
links.forEach(function (l, i) { l.classList.toggle('active', i === active); });
|
||||||
|
steps.forEach(function (s, i) { if (s) s.classList.toggle('active', i === active); });
|
||||||
|
}
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
onScroll();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+1
-2
@@ -808,9 +808,8 @@ function handleImageSelection(evt) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fn = document.createElement('span');
|
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 = `${file.name} (file resolution: ${img.width} x ${img.height})`;
|
||||||
fn.innerHTML += '<br />';
|
|
||||||
|
|
||||||
const rb = document.createElement('button');
|
const rb = document.createElement('button');
|
||||||
rb.className = 'remove-button';
|
rb.className = 'remove-button';
|
||||||
|
|||||||
+404
@@ -0,0 +1,404 @@
|
|||||||
|
<!DOCTYPE html><html class="light" lang="en" style=""><head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
|
<title>image2cpp | Image to Byte Array Converter</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||||||
|
<script id="tailwind-config">
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
"colors": {
|
||||||
|
"on-primary-container": "#004538",
|
||||||
|
"on-tertiary": "#ffffff",
|
||||||
|
"surface-variant": "#e0e3e5",
|
||||||
|
"on-primary-fixed": "#002019",
|
||||||
|
"on-secondary-fixed": "#091d2e",
|
||||||
|
"border-subtle": "#E2E8F0",
|
||||||
|
"outline": "#6c7a75",
|
||||||
|
"inverse-surface": "#2d3133",
|
||||||
|
"tertiary-container": "#fa866f",
|
||||||
|
"tertiary-fixed-dim": "#ffb4a5",
|
||||||
|
"success-teal": "#1ABC9C",
|
||||||
|
"secondary-fixed-dim": "#b5c8df",
|
||||||
|
"inverse-on-surface": "#eff1f3",
|
||||||
|
"on-secondary-container": "#526478",
|
||||||
|
"surface-container-low": "#f2f4f6",
|
||||||
|
"on-tertiary-fixed-variant": "#7f2a1a",
|
||||||
|
"on-primary": "#ffffff",
|
||||||
|
"editor-bg": "#1E1E1E",
|
||||||
|
"secondary": "#4e6073",
|
||||||
|
"surface-tint": "#006b58",
|
||||||
|
"primary-container": "#1abc9c",
|
||||||
|
"on-secondary": "#ffffff",
|
||||||
|
"tertiary": "#9f402e",
|
||||||
|
"on-surface": "#191c1e",
|
||||||
|
"on-primary-fixed-variant": "#005141",
|
||||||
|
"text-muted": "#64748B",
|
||||||
|
"tertiary-fixed": "#ffdad3",
|
||||||
|
"surface-bright": "#f7f9fb",
|
||||||
|
"on-tertiary-fixed": "#3f0400",
|
||||||
|
"error": "#ba1a1a",
|
||||||
|
"on-surface-variant": "#3c4a45",
|
||||||
|
"inverse-primary": "#4eddbb",
|
||||||
|
"primary": "#006b58",
|
||||||
|
"surface-container": "#eceef0",
|
||||||
|
"surface-container-high": "#e6e8ea",
|
||||||
|
"error-container": "#ffdad6",
|
||||||
|
"on-error": "#ffffff",
|
||||||
|
"primary-fixed-dim": "#4eddbb",
|
||||||
|
"surface-container-lowest": "#ffffff",
|
||||||
|
"secondary-container": "#cfe2f9",
|
||||||
|
"surface-dim": "#d8dadc",
|
||||||
|
"on-secondary-fixed-variant": "#36485b",
|
||||||
|
"background": "#f7f9fb",
|
||||||
|
"surface": "#f7f9fb",
|
||||||
|
"on-tertiary-container": "#711f10",
|
||||||
|
"outline-variant": "#bbcac3",
|
||||||
|
"on-background": "#191c1e",
|
||||||
|
"surface-container-highest": "#e0e3e5",
|
||||||
|
"secondary-fixed": "#d1e4fb",
|
||||||
|
"on-error-container": "#93000a",
|
||||||
|
"primary-fixed": "#6ff9d6"
|
||||||
|
},
|
||||||
|
"borderRadius": {
|
||||||
|
"DEFAULT": "0.125rem",
|
||||||
|
"lg": "0.25rem",
|
||||||
|
"xl": "0.5rem",
|
||||||
|
"full": "0.75rem"
|
||||||
|
},
|
||||||
|
"spacing": {
|
||||||
|
"step-gap": "48px",
|
||||||
|
"container-max": "1200px",
|
||||||
|
"margin-desktop": "40px",
|
||||||
|
"margin-mobile": "16px",
|
||||||
|
"gutter": "24px"
|
||||||
|
},
|
||||||
|
"fontFamily": {
|
||||||
|
"body-md": ["Inter"],
|
||||||
|
"headline-lg-mobile": ["Inter"],
|
||||||
|
"code-block": ["JetBrains Mono"],
|
||||||
|
"body-sm": ["Inter"],
|
||||||
|
"headline-lg": ["Inter"],
|
||||||
|
"label-mono": ["JetBrains Mono"],
|
||||||
|
"headline-md": ["Inter"]
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"body-md": ["16px", {"lineHeight": "24px", "fontWeight": "400"}],
|
||||||
|
"headline-lg-mobile": ["24px", {"lineHeight": "32px", "fontWeight": "600"}],
|
||||||
|
"code-block": ["14px", {"lineHeight": "22px", "fontWeight": "400"}],
|
||||||
|
"body-sm": ["14px", {"lineHeight": "20px", "fontWeight": "400"}],
|
||||||
|
"headline-lg": ["30px", {"lineHeight": "38px", "letterSpacing": "-0.02em", "fontWeight": "600"}],
|
||||||
|
"label-mono": ["13px", {"lineHeight": "16px", "fontWeight": "500"}],
|
||||||
|
"headline-md": ["20px", {"lineHeight": "28px", "fontWeight": "600"}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
}
|
||||||
|
.step-active { color: #006b58; }
|
||||||
|
.step-line { position: absolute; left: 19px; top: 40px; bottom: -20px; width: 2px; background-color: #E2E8F0; }
|
||||||
|
.last-step-line { display: none; }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar { width: 8px; }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f1f1; }
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background text-on-background font-body-md min-h-screen">
|
||||||
|
<!-- TopNavBar -->
|
||||||
|
<header class="bg-surface dark:bg-background border-b border-border-subtle dark:border-outline-variant full-width top-0 sticky z-50">
|
||||||
|
<div class="flex justify-between items-center h-16 px-margin-desktop max-w-container-max mx-auto">
|
||||||
|
<div class="flex items-center gap-8">
|
||||||
|
<span class="font-headline-md text-headline-md font-bold text-primary dark:text-primary-fixed-dim cursor-pointer">image2cpp</span>
|
||||||
|
<nav class="hidden md:flex gap-6 font-body-md text-body-md"><a class="text-secondary dark:text-secondary-fixed-dim hover:text-primary transition-colors cursor-pointer" href="#">GitHub</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button class="material-symbols-outlined text-secondary hover:text-primary transition-colors cursor-pointer" data-icon="dark_mode">dark_mode</button>
|
||||||
|
<button class="bg-primary-container text-on-primary-container px-4 py-2 font-label-mono text-label-mono rounded-lg hover:opacity-90 active:opacity-80 transition-all"><div class="">Reset page</div></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="flex max-w-container-max mx-auto">
|
||||||
|
<!-- SideNavBar -->
|
||||||
|
<aside class="hidden lg:flex flex-col py-6 h-screen w-64 fixed left-0 top-16 bg-surface-container-low dark:bg-surface-container border-r border-border-subtle dark:border-outline-variant">
|
||||||
|
<div class="px-6 mb-8">
|
||||||
|
<h2 class="font-headline-md text-headline-md text-primary">Workflow</h2>
|
||||||
|
<p class="font-body-sm text-body-sm text-text-muted">Conversion Steps</p>
|
||||||
|
</div>
|
||||||
|
<nav class="flex-1 space-y-1 font-label-mono text-label-mono">
|
||||||
|
<div class="flex items-center gap-3 text-primary dark:text-primary-fixed-dim font-bold bg-primary-container/10 dark:bg-primary-container/20 border-r-4 border-primary dark:border-primary-fixed-dim py-3 px-6 cursor-pointer hover:bg-surface-container-high transition-all">
|
||||||
|
<span class="material-symbols-outlined" data-icon="upload_file">upload_file</span>
|
||||||
|
<span class="">1. Select Image</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 text-secondary dark:text-secondary-fixed-dim py-3 px-6 cursor-pointer hover:bg-surface-container-high transition-all">
|
||||||
|
<span class="material-symbols-outlined" data-icon="tune">tune</span>
|
||||||
|
<span class="">2. Settings</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 text-secondary dark:text-secondary-fixed-dim py-3 px-6 cursor-pointer hover:bg-surface-container-high transition-all">
|
||||||
|
<span class="material-symbols-outlined" data-icon="visibility">visibility</span>
|
||||||
|
<span class="">3. Preview</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 text-secondary dark:text-secondary-fixed-dim py-3 px-6 cursor-pointer hover:bg-surface-container-high transition-all">
|
||||||
|
<span class="material-symbols-outlined" data-icon="code">code</span>
|
||||||
|
<span class="">4. Output</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="p-6 mt-auto"><button class="w-full bg-secondary text-on-secondary py-2 rounded font-label-mono text-label-mono hover:bg-on-secondary-container transition-colors">Export All</button></div></aside>
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="flex-1 lg:ml-64 px-margin-desktop py-12 max-w-4xl mx-auto">
|
||||||
|
<div class="mb-12">
|
||||||
|
<h1 class="font-headline-lg text-headline-lg mb-2">Image to C++ Converter</h1>
|
||||||
|
<p class="text-text-muted">Generate monochrome byte arrays for OLED displays on Arduino or Raspberry Pi. All processing happens in your browser.</p>
|
||||||
|
<div class="flex items-center gap-4 mt-4"><span class="text-text-muted font-body-sm">Support on</span><a class="w-10 h-10 rounded-full bg-surface-container-high flex items-center justify-center text-primary hover:bg-primary hover:text-on-primary transition-all" href="#"><span class="material-symbols-outlined" style="font-variation-settings: "FILL" 1;">favorite</span></a><a class="w-10 h-10 rounded-full bg-surface-container-high flex items-center justify-center text-primary hover:bg-primary hover:text-on-primary transition-all" href="#"><span class="material-symbols-outlined" style="font-variation-settings: "FILL" 1;">coffee</span></a></div></div>
|
||||||
|
<!-- Workflow Steps -->
|
||||||
|
<div class="space-y-step-gap">
|
||||||
|
<!-- Step 1: Select Image -->
|
||||||
|
<section class="relative pl-12" id="step-1">
|
||||||
|
<div class="step-line"></div>
|
||||||
|
<div class="absolute left-0 top-0 w-10 h-10 bg-primary rounded-full flex items-center justify-center text-on-primary font-bold shadow-sm z-10">1</div>
|
||||||
|
<div class="bg-surface-container-lowest border border-border-subtle rounded-xl p-8 space-y-6">
|
||||||
|
<div class="flex flex-col md:flex-row gap-6">
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-2">Upload Image File</label>
|
||||||
|
<div class="border-2 border-dashed border-outline-variant rounded-lg p-10 flex flex-col items-center justify-center bg-surface-container hover:bg-surface-container-high transition-colors cursor-pointer group">
|
||||||
|
<span class="material-symbols-outlined text-4xl text-outline mb-3 group-hover:scale-110 transition-transform" data-icon="cloud_upload">cloud_upload</span>
|
||||||
|
<p class="font-body-md text-body-md text-on-surface-variant text-center">Drag and drop images here or <span class="text-primary font-bold">Browse</span></p>
|
||||||
|
<p class="font-body-sm text-body-sm text-text-muted mt-2">Supports JPG, PNG, BMP, GIF</p>
|
||||||
|
<input class="hidden" multiple="" type="file">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-2">Or Paste Byte Array</label>
|
||||||
|
<textarea class="w-full h-[180px] bg-surface-container text-on-surface-variant font-code-block text-code-block p-4 rounded-lg border-none focus:ring-2 focus:ring-primary focus:outline-none resize-none" placeholder="0xFF, 0x00, 0xAA..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Step 2: Settings -->
|
||||||
|
<section class="relative pl-12" id="step-2">
|
||||||
|
<div class="step-line"></div>
|
||||||
|
<div class="absolute left-0 top-0 w-10 h-10 bg-surface-container-high border border-border-subtle rounded-full flex items-center justify-center text-secondary font-bold z-10">2</div>
|
||||||
|
<div class="bg-surface-container-lowest border border-border-subtle rounded-xl p-8 space-y-8">
|
||||||
|
<div class="flex justify-between items-center mb-6"><h3 class="font-headline-md text-headline-md text-on-surface">Image Configuration</h3><div class="flex gap-2"><button class="p-1 text-secondary hover:text-primary transition-colors"></button></div></div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-gutter gap-y-8">
|
||||||
|
<!-- Canvas Size -->
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Canvas Size (px)</label>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input class="w-full bg-surface-container border-none rounded p-2 font-label-mono" type="number" value="128">
|
||||||
|
<span class="text-outline">×</span>
|
||||||
|
<input class="w-full bg-surface-container border-none rounded p-2 font-label-mono" type="number" value="64">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Background Color -->
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Background Color</label>
|
||||||
|
<div class="flex gap-1 bg-surface-container p-1 rounded-lg">
|
||||||
|
<button class="flex-1 py-1.5 rounded text-label-mono bg-on-secondary-container text-white shadow-sm">White</button>
|
||||||
|
<button class="flex-1 py-1.5 rounded text-label-mono text-secondary hover:bg-surface-container-high">Black</button>
|
||||||
|
<button class="flex-1 py-1.5 rounded text-label-mono text-secondary hover:bg-surface-container-high">Transp.</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Scaling -->
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Scaling</label>
|
||||||
|
<select class="w-full bg-surface-container border-none rounded p-2 font-body-sm focus:ring-primary">
|
||||||
|
<option>Original Size</option>
|
||||||
|
<option>Scale to Fit</option>
|
||||||
|
<option>Stretch to Fill</option>
|
||||||
|
<option>Stretch Horizontally</option>
|
||||||
|
<option>Stretch Vertically</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<!-- Dithering -->
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Dithering Algorithm</label>
|
||||||
|
<select class="w-full bg-surface-container border-none rounded p-2 font-body-sm focus:ring-primary">
|
||||||
|
<option>Binary (Threshold)</option>
|
||||||
|
<option>Bayer (Ordered)</option>
|
||||||
|
<option>Floyd-Steinberg</option>
|
||||||
|
<option>Atkinson</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<!-- Brightness -->
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Threshold (0-255)</label>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<input class="flex-1 accent-primary" max="255" min="0" type="range" value="128">
|
||||||
|
<span class="font-label-mono text-primary">128</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Toggles -->
|
||||||
|
<div class="">
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-3">Image Adjustments</label>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<div class="relative inline-flex items-center">
|
||||||
|
<input class="sr-only peer" type="checkbox">
|
||||||
|
<div class="w-11 h-6 bg-outline-variant peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
|
||||||
|
</div>
|
||||||
|
<span class="font-body-sm">Invert Colors</span>
|
||||||
|
</label>
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<button class="flex items-center gap-2 text-label-mono text-secondary hover:text-primary transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-sm">rotate_right</span> Rotate Image</button>
|
||||||
|
<button class="flex items-center gap-2 text-label-mono text-secondary hover:text-primary transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-sm">flip</span> Flip Image</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Step 3: Preview -->
|
||||||
|
<section class="relative pl-12" id="step-3">
|
||||||
|
<div class="step-line"></div>
|
||||||
|
<div class="absolute left-0 top-0 w-10 h-10 bg-surface-container-high border border-border-subtle rounded-full flex items-center justify-center text-secondary font-bold z-10">3</div>
|
||||||
|
<div class="bg-surface-container-lowest border border-border-subtle rounded-xl p-8">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h3 class="font-headline-md text-headline-md text-on-surface">Preview</h3>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button class="p-1 text-secondary hover:text-primary transition-colors"></button>
|
||||||
|
<button class="p-1 text-secondary hover:text-primary transition-colors"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<span class="font-label-mono text-label-mono text-text-muted">Original</span>
|
||||||
|
<div class="aspect-video bg-surface-container-high rounded-lg flex items-center justify-center border border-dashed border-outline-variant relative overflow-hidden">
|
||||||
|
<img class="max-w-full max-h-full object-contain" data-alt="A clean, high-resolution original digital photo of a detailed robot head against a neutral gray background. The lighting is crisp and highlights the mechanical textures and metallic finishes. The composition is centered, creating a professional studio-quality look for image processing software. The aesthetic is tech-focused and minimal." src="https://lh3.googleusercontent.com/aida-public/AB6AXuAq1r2m_Da66R4eXvBlWq7d0AICWfEENZNfsexBvtCHmM5luhvCaPECRItz1w85o1XVfQtgy1XdkamKUDYAaRIQBJHQTB1Mt8pfbUMK7GNzDWYCQx6MUC1DEqnG0QSJBPc_zMJj6hZPoBKjAz_NUOg-mD4nC2cszzgH8dPaU_Z1B5fGEeHecdKtRIlPwCAjuArVWmSh1ayhApkbopqBSNOWmVjLk0RX5VkT_IwoHSYQFYFTtWJqAShF1g">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<span class="font-label-mono text-label-mono text-text-muted">Converted (1-bit)</span>
|
||||||
|
<div class="aspect-video bg-editor-bg rounded-lg flex items-center justify-center border border-on-surface-variant relative overflow-hidden">
|
||||||
|
<!-- This would be the canvas rendering -->
|
||||||
|
<img class="max-w-full max-h-full object-contain grayscale brightness-200 contrast-200" data-alt="A stylized 1-bit black and white monochrome rendering of the previous robot head image. The image is pixelated and high-contrast, mimicking an OLED display output with crisp white pixels on a deep black background. The conversion uses a dithered effect to represent shadows, creating a high-tech retro-digital aesthetic." src="https://lh3.googleusercontent.com/aida-public/AB6AXuBPXPnQHpXR6vyt7gdrlrgvIepXIaQ6-86RRIK88PdiKphM3fnxyX1eP2V4py6FTykrNAL4OpC8kmEFdzZhRfjPtMOmqisw66exgyOzOF6keumlvHUzPvVrBeWj7cr2gB88geHSizBpGdRxu8N30B0Kgl9VEdLwrE2juDzZM7169j4gPDbn6UcyKHHSjvMmkSGbynfboN3URFYfDA1CsyegObewcHcJ--8-gMSF1OzJ57FqHbvzpMjEtQ">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Step 4: Output -->
|
||||||
|
<section class="relative pl-12" id="step-4">
|
||||||
|
<div class="step-line last-step-line"></div>
|
||||||
|
<div class="absolute left-0 top-0 w-10 h-10 bg-surface-container-high border border-border-subtle rounded-full flex items-center justify-center text-secondary font-bold z-10">4</div>
|
||||||
|
<div class="bg-surface-container-lowest border border-border-subtle rounded-xl p-8 space-y-8">
|
||||||
|
<div class="flex flex-col lg:flex-row justify-between items-start gap-8">
|
||||||
|
<div class="w-full lg:w-1/3 space-y-6">
|
||||||
|
<h3 class="font-headline-md text-headline-md text-on-surface">Output Settings</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-2">Output Format</label>
|
||||||
|
<select class="w-full bg-surface-container border-none rounded p-2 font-body-sm focus:ring-primary">
|
||||||
|
<option>Plain bytes</option>
|
||||||
|
<option selected="">Arduino code</option>
|
||||||
|
<option>Arduino code (Single Bitmap)</option>
|
||||||
|
<option>Adafruit GFX Bitmap Font</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-2">Identifier / Prefix</label>
|
||||||
|
<input class="w-full bg-surface-container border-none rounded p-2 font-label-mono focus:ring-primary" type="text" value="myBitmap">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block font-label-mono text-label-mono text-primary mb-2">Draw Mode</label>
|
||||||
|
<select class="w-full bg-surface-container border-none rounded p-2 font-body-sm focus:ring-primary">
|
||||||
|
<option>Horizontal - 1 bit per pixel</option>
|
||||||
|
<option>Vertical - 1 bit per pixel</option>
|
||||||
|
<option>Horizontal - 2 bytes per pixel (565)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="pt-2 space-y-3">
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input class="w-5 h-5 rounded border-outline-variant text-primary focus:ring-primary" type="checkbox">
|
||||||
|
<span class="font-body-sm">Swap bits in byte</span>
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input class="w-5 h-5 rounded border-outline-variant text-primary focus:ring-primary" type="checkbox">
|
||||||
|
<span class="font-body-sm">Remove '0x' and commas</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full lg:w-2/3 space-y-4">
|
||||||
|
<div class="flex justify-between items-end">
|
||||||
|
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button class="bg-primary text-on-primary px-4 py-2 rounded-lg font-label-mono text-label-mono hover:bg-on-primary-fixed-variant transition-all flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-sm" data-icon="play_arrow">play_arrow</span> Generate
|
||||||
|
</button>
|
||||||
|
<button class="bg-surface-container-high text-on-surface-variant px-4 py-2 rounded-lg font-label-mono text-label-mono hover:bg-surface-container-highest transition-all flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-sm" data-icon="content_copy">content_copy</span> Copy
|
||||||
|
</button>
|
||||||
|
<button class="bg-secondary text-on-secondary px-4 py-2 rounded-lg font-label-mono text-label-mono hover:opacity-90 transition-all flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-sm" data-icon="download">download</span> .bin
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-editor-bg rounded-xl p-6 font-code-block text-code-block text-white overflow-hidden border border-on-surface-variant h-[400px] flex flex-col">
|
||||||
|
<div class="flex-1 overflow-auto custom-scrollbar">
|
||||||
|
<pre class="text-green-400 opacity-60 italic mb-2">// Generated by image2cpp
|
||||||
|
// 128x64px, myBitmap
|
||||||
|
</pre>
|
||||||
|
<code class="block text-[#dcdcaa]">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
|
||||||
|
};</code>
|
||||||
|
</div>
|
||||||
|
<div class="bg-surface-container-low p-4 rounded-lg flex items-start gap-3">
|
||||||
|
<span class="material-symbols-outlined text-primary text-xl" data-icon="info">info</span>
|
||||||
|
<p class="font-body-sm text-body-sm text-on-secondary-container leading-relaxed">If the preview looks scrambled on your hardware, try switching the <strong>Draw Mode</strong> between Horizontal and Vertical.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div></section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<!-- Footer -->
|
||||||
|
<script>
|
||||||
|
// Simple interactivity for demonstration
|
||||||
|
document.querySelectorAll('nav div, nav a').forEach(item => {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
// Remove active classes from all
|
||||||
|
document.querySelectorAll('nav div').forEach(d => {
|
||||||
|
d.classList.remove('text-primary', 'font-bold', 'bg-primary-container/10', 'border-r-4', 'border-primary');
|
||||||
|
d.classList.add('text-secondary');
|
||||||
|
});
|
||||||
|
// Add to clicked
|
||||||
|
if (this.tagName === 'DIV') {
|
||||||
|
this.classList.add('text-primary', 'font-bold', 'bg-primary-container/10', 'border-r-4', 'border-primary');
|
||||||
|
this.classList.remove('text-secondary');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sticky side nav highlight on scroll logic could be added here
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
||||||
Reference in New Issue
Block a user