docs: update refs, update script
This commit is contained in:
@@ -1 +1,10 @@
|
||||
node_modules
|
||||
|
||||
# Reference source (legacy Next.js design in refs/): branding icons are not needed
|
||||
refs/public/icon.svg
|
||||
refs/public/icon-dark-32x32.png
|
||||
refs/public/icon-light-32x32.png
|
||||
refs/public/apple-icon.png
|
||||
refs/public/placeholder-logo.svg
|
||||
refs/public/placeholder-logo.png
|
||||
refs/public/placeholder.svg
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "pnpm --dir web dev",
|
||||
"build": "pnpm --dir web build",
|
||||
"format": "pnpm --dir web format"
|
||||
"format": "pnpm --dir web format",
|
||||
"html": "pnpm --dir refs build && node scripts/extract-static.mjs refs/.next/server/app refs-html"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Ku6epXBOCTuK",
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
@layer properties {
|
||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))) {
|
||||
*,:before,:after,::backdrop {
|
||||
--tw-rotate-x:initial;
|
||||
--tw-rotate-y:initial;
|
||||
--tw-rotate-z:initial;
|
||||
--tw-skew-x:initial;
|
||||
--tw-skew-y:initial;
|
||||
--tw-border-style:solid;
|
||||
--tw-font-weight:initial;
|
||||
--tw-shadow:0 0 #0000;
|
||||
@@ -290,12 +285,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
}
|
||||
@layer components;
|
||||
@layer utilities {
|
||||
.static {
|
||||
position:static
|
||||
}
|
||||
.inline {
|
||||
display:inline
|
||||
}
|
||||
.inline-flex {
|
||||
display:inline-flex
|
||||
}
|
||||
@@ -330,9 +319,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
.shrink-0 {
|
||||
flex-shrink:0
|
||||
}
|
||||
.transform {
|
||||
transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)
|
||||
}
|
||||
.items-center {
|
||||
align-items:center
|
||||
}
|
||||
@@ -630,7 +616,7 @@ button {
|
||||
--line:#33414c;
|
||||
--muted:#91a0ac;
|
||||
--blue:#54a2ff;
|
||||
background-image:linear-gradient(#1b252d 1px,#0000 1px),linear-gradient(90deg,#1b252d 1px,#0000 1px)
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.topbar,.brand,.top-actions,.language,.status,.title-row,.pipeline-head,.step-heading,.step-tools,.pipeline-footer,.preview-top,.footer {
|
||||
align-items:center;
|
||||
@@ -643,6 +629,26 @@ button {
|
||||
height:64px;
|
||||
padding:0 clamp(20px,4vw,64px)
|
||||
}
|
||||
.topbar>.brand {
|
||||
color:var(--foreground);
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav {
|
||||
align-items:center;
|
||||
gap:22px;
|
||||
margin-left:auto;
|
||||
margin-right:28px;
|
||||
display:flex
|
||||
}
|
||||
.top-nav a {
|
||||
color:var(--muted);
|
||||
font:10px var(--font-mono);
|
||||
white-space:nowrap;
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav a:hover,.top-nav a.active {
|
||||
color:var(--blue)
|
||||
}
|
||||
.brand {
|
||||
font:600 14px var(--font-mono);
|
||||
gap:10px
|
||||
@@ -1103,6 +1109,9 @@ h1 {
|
||||
gap:32px
|
||||
}
|
||||
|
||||
}
|
||||
.dark-mode .app-shell {
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.dark-mode .tile-canvas {
|
||||
background-color:#202a31;
|
||||
@@ -1113,7 +1122,22 @@ h1 {
|
||||
}
|
||||
@media (max-width:800px) {
|
||||
.topbar {
|
||||
padding:0 16px
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
height:auto;
|
||||
min-height:64px;
|
||||
padding:12px 16px
|
||||
}
|
||||
.top-nav {
|
||||
order:3;
|
||||
gap:12px;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding-bottom:2px;
|
||||
overflow:auto
|
||||
}
|
||||
.top-nav a {
|
||||
font-size:9px
|
||||
}
|
||||
.status {
|
||||
display:none
|
||||
@@ -1532,9 +1556,9 @@ h1 {
|
||||
}
|
||||
.catalog-page {
|
||||
width:100%;
|
||||
max-width:1680px;
|
||||
margin:0 auto;
|
||||
padding:64px clamp(24px,4vw,72px) 72px
|
||||
max-width:none;
|
||||
margin:0;
|
||||
padding:60px clamp(24px,4vw,72px) 72px
|
||||
}
|
||||
.catalog-head {
|
||||
border-bottom:1px solid var(--line);
|
||||
@@ -1803,26 +1827,6 @@ h1 {
|
||||
gap:12px 18px
|
||||
}
|
||||
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-border-style {
|
||||
syntax:"*";
|
||||
@@ -1984,43 +1988,57 @@ h1 {
|
||||
<!--$-->
|
||||
<!--/$-->
|
||||
</div>
|
||||
<main class="app-shell dark-mode">
|
||||
<main class="app-shell">
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<a class="brand" href="/">
|
||||
<span class="brand-mark">EP
|
||||
</span>
|
||||
<span>easy-png-tools
|
||||
</span>
|
||||
<span class="version">/ BACKGROUND REMOVER
|
||||
<span class="version">/
|
||||
<!-- -->BACKGROUND REMOVER
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<nav class="top-nav" aria-label="Primary navigation">
|
||||
<a class="" href="/">Workspace
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/list-tools">Catalog
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/gradient">Gradient
|
||||
</a>
|
||||
<a class="active" href="/easy-png-tools/background-remover">Background remover
|
||||
</a>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<span class="status">
|
||||
<i>
|
||||
</i> AUTO PROCESSING
|
||||
</i>
|
||||
<!-- -->AUTO PROCESSING
|
||||
</span>
|
||||
<button class="icon-btn" aria-label="Toggle theme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="4">
|
||||
<button class="icon-btn" aria-label="Help">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-question-mark" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="10">
|
||||
</circle>
|
||||
<path d="M12 2v2">
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3">
|
||||
</path>
|
||||
<path d="M12 20v2">
|
||||
</path>
|
||||
<path d="m4.93 4.93 1.41 1.41">
|
||||
</path>
|
||||
<path d="m17.66 17.66 1.41 1.41">
|
||||
</path>
|
||||
<path d="M2 12h2">
|
||||
</path>
|
||||
<path d="M20 12h2">
|
||||
</path>
|
||||
<path d="m6.34 17.66-1.41 1.41">
|
||||
</path>
|
||||
<path d="m19.07 4.93-1.41 1.41">
|
||||
<path d="M12 17h.01">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" aria-label="Toggle theme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon" aria-hidden="true">
|
||||
<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="language">
|
||||
<button class="active">RU
|
||||
</button>
|
||||
<span>/
|
||||
</span>
|
||||
<button>EN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="tool-page">
|
||||
|
||||
+62
-44
@@ -7,11 +7,6 @@
|
||||
@layer properties {
|
||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))) {
|
||||
*,:before,:after,::backdrop {
|
||||
--tw-rotate-x:initial;
|
||||
--tw-rotate-y:initial;
|
||||
--tw-rotate-z:initial;
|
||||
--tw-skew-x:initial;
|
||||
--tw-skew-y:initial;
|
||||
--tw-border-style:solid;
|
||||
--tw-font-weight:initial;
|
||||
--tw-shadow:0 0 #0000;
|
||||
@@ -290,12 +285,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
}
|
||||
@layer components;
|
||||
@layer utilities {
|
||||
.static {
|
||||
position:static
|
||||
}
|
||||
.inline {
|
||||
display:inline
|
||||
}
|
||||
.inline-flex {
|
||||
display:inline-flex
|
||||
}
|
||||
@@ -330,9 +319,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
.shrink-0 {
|
||||
flex-shrink:0
|
||||
}
|
||||
.transform {
|
||||
transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)
|
||||
}
|
||||
.items-center {
|
||||
align-items:center
|
||||
}
|
||||
@@ -630,7 +616,7 @@ button {
|
||||
--line:#33414c;
|
||||
--muted:#91a0ac;
|
||||
--blue:#54a2ff;
|
||||
background-image:linear-gradient(#1b252d 1px,#0000 1px),linear-gradient(90deg,#1b252d 1px,#0000 1px)
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.topbar,.brand,.top-actions,.language,.status,.title-row,.pipeline-head,.step-heading,.step-tools,.pipeline-footer,.preview-top,.footer {
|
||||
align-items:center;
|
||||
@@ -643,6 +629,26 @@ button {
|
||||
height:64px;
|
||||
padding:0 clamp(20px,4vw,64px)
|
||||
}
|
||||
.topbar>.brand {
|
||||
color:var(--foreground);
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav {
|
||||
align-items:center;
|
||||
gap:22px;
|
||||
margin-left:auto;
|
||||
margin-right:28px;
|
||||
display:flex
|
||||
}
|
||||
.top-nav a {
|
||||
color:var(--muted);
|
||||
font:10px var(--font-mono);
|
||||
white-space:nowrap;
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav a:hover,.top-nav a.active {
|
||||
color:var(--blue)
|
||||
}
|
||||
.brand {
|
||||
font:600 14px var(--font-mono);
|
||||
gap:10px
|
||||
@@ -1103,6 +1109,9 @@ h1 {
|
||||
gap:32px
|
||||
}
|
||||
|
||||
}
|
||||
.dark-mode .app-shell {
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.dark-mode .tile-canvas {
|
||||
background-color:#202a31;
|
||||
@@ -1113,7 +1122,22 @@ h1 {
|
||||
}
|
||||
@media (max-width:800px) {
|
||||
.topbar {
|
||||
padding:0 16px
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
height:auto;
|
||||
min-height:64px;
|
||||
padding:12px 16px
|
||||
}
|
||||
.top-nav {
|
||||
order:3;
|
||||
gap:12px;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding-bottom:2px;
|
||||
overflow:auto
|
||||
}
|
||||
.top-nav a {
|
||||
font-size:9px
|
||||
}
|
||||
.status {
|
||||
display:none
|
||||
@@ -1532,9 +1556,9 @@ h1 {
|
||||
}
|
||||
.catalog-page {
|
||||
width:100%;
|
||||
max-width:1680px;
|
||||
margin:0 auto;
|
||||
padding:64px clamp(24px,4vw,72px) 72px
|
||||
max-width:none;
|
||||
margin:0;
|
||||
padding:60px clamp(24px,4vw,72px) 72px
|
||||
}
|
||||
.catalog-head {
|
||||
border-bottom:1px solid var(--line);
|
||||
@@ -1803,26 +1827,6 @@ h1 {
|
||||
gap:12px 18px
|
||||
}
|
||||
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-border-style {
|
||||
syntax:"*";
|
||||
@@ -1986,18 +1990,30 @@ h1 {
|
||||
</div>
|
||||
<main class="app-shell">
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<a class="brand" href="/">
|
||||
<span class="brand-mark">EP
|
||||
</span>
|
||||
<span>easy-png-tools
|
||||
</span>
|
||||
<span class="version">/ DEMO
|
||||
<span class="version">/
|
||||
<!-- -->WORKSPACE
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<nav class="top-nav" aria-label="Primary navigation">
|
||||
<a class="" href="/">Workspace
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/list-tools">Catalog
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/gradient">Gradient
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/background-remover">Background remover
|
||||
</a>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<span class="status">
|
||||
<i>
|
||||
</i> AUTO PIPELINE
|
||||
</i>
|
||||
<!-- -->AUTO PIPELINE
|
||||
</span>
|
||||
<button class="icon-btn" aria-label="Help">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-question-mark" aria-hidden="true">
|
||||
@@ -2018,7 +2034,9 @@ h1 {
|
||||
<div class="language">
|
||||
<button class="active">RU
|
||||
</button>
|
||||
<button class="">EN
|
||||
<span>/
|
||||
</span>
|
||||
<button>EN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+82
-60
@@ -7,11 +7,6 @@
|
||||
@layer properties {
|
||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))) {
|
||||
*,:before,:after,::backdrop {
|
||||
--tw-rotate-x:initial;
|
||||
--tw-rotate-y:initial;
|
||||
--tw-rotate-z:initial;
|
||||
--tw-skew-x:initial;
|
||||
--tw-skew-y:initial;
|
||||
--tw-border-style:solid;
|
||||
--tw-font-weight:initial;
|
||||
--tw-shadow:0 0 #0000;
|
||||
@@ -290,12 +285,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
}
|
||||
@layer components;
|
||||
@layer utilities {
|
||||
.static {
|
||||
position:static
|
||||
}
|
||||
.inline {
|
||||
display:inline
|
||||
}
|
||||
.inline-flex {
|
||||
display:inline-flex
|
||||
}
|
||||
@@ -330,9 +319,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
.shrink-0 {
|
||||
flex-shrink:0
|
||||
}
|
||||
.transform {
|
||||
transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)
|
||||
}
|
||||
.items-center {
|
||||
align-items:center
|
||||
}
|
||||
@@ -630,7 +616,7 @@ button {
|
||||
--line:#33414c;
|
||||
--muted:#91a0ac;
|
||||
--blue:#54a2ff;
|
||||
background-image:linear-gradient(#1b252d 1px,#0000 1px),linear-gradient(90deg,#1b252d 1px,#0000 1px)
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.topbar,.brand,.top-actions,.language,.status,.title-row,.pipeline-head,.step-heading,.step-tools,.pipeline-footer,.preview-top,.footer {
|
||||
align-items:center;
|
||||
@@ -643,6 +629,26 @@ button {
|
||||
height:64px;
|
||||
padding:0 clamp(20px,4vw,64px)
|
||||
}
|
||||
.topbar>.brand {
|
||||
color:var(--foreground);
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav {
|
||||
align-items:center;
|
||||
gap:22px;
|
||||
margin-left:auto;
|
||||
margin-right:28px;
|
||||
display:flex
|
||||
}
|
||||
.top-nav a {
|
||||
color:var(--muted);
|
||||
font:10px var(--font-mono);
|
||||
white-space:nowrap;
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav a:hover,.top-nav a.active {
|
||||
color:var(--blue)
|
||||
}
|
||||
.brand {
|
||||
font:600 14px var(--font-mono);
|
||||
gap:10px
|
||||
@@ -1103,6 +1109,9 @@ h1 {
|
||||
gap:32px
|
||||
}
|
||||
|
||||
}
|
||||
.dark-mode .app-shell {
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.dark-mode .tile-canvas {
|
||||
background-color:#202a31;
|
||||
@@ -1113,7 +1122,22 @@ h1 {
|
||||
}
|
||||
@media (max-width:800px) {
|
||||
.topbar {
|
||||
padding:0 16px
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
height:auto;
|
||||
min-height:64px;
|
||||
padding:12px 16px
|
||||
}
|
||||
.top-nav {
|
||||
order:3;
|
||||
gap:12px;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding-bottom:2px;
|
||||
overflow:auto
|
||||
}
|
||||
.top-nav a {
|
||||
font-size:9px
|
||||
}
|
||||
.status {
|
||||
display:none
|
||||
@@ -1532,9 +1556,9 @@ h1 {
|
||||
}
|
||||
.catalog-page {
|
||||
width:100%;
|
||||
max-width:1680px;
|
||||
margin:0 auto;
|
||||
padding:64px clamp(24px,4vw,72px) 72px
|
||||
max-width:none;
|
||||
margin:0;
|
||||
padding:60px clamp(24px,4vw,72px) 72px
|
||||
}
|
||||
.catalog-head {
|
||||
border-bottom:1px solid var(--line);
|
||||
@@ -1803,26 +1827,6 @@ h1 {
|
||||
gap:12px 18px
|
||||
}
|
||||
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-border-style {
|
||||
syntax:"*";
|
||||
@@ -1984,39 +1988,57 @@ h1 {
|
||||
<!--$-->
|
||||
<!--/$-->
|
||||
</div>
|
||||
<main class="app-shell dark-mode">
|
||||
<main class="app-shell">
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<a class="brand" href="/">
|
||||
<span class="brand-mark">EP
|
||||
</span>
|
||||
<span>easy-png-tools
|
||||
</span>
|
||||
<span class="version">/ GRADIENT
|
||||
<span class="version">/
|
||||
<!-- -->GRADIENT
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<nav class="top-nav" aria-label="Primary navigation">
|
||||
<a class="" href="/">Workspace
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/list-tools">Catalog
|
||||
</a>
|
||||
<a class="active" href="/easy-png-tools/gradient">Gradient
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/background-remover">Background remover
|
||||
</a>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<button class="icon-btn" aria-label="Toggle theme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="4">
|
||||
<span class="status">
|
||||
<i>
|
||||
</i>
|
||||
<!-- -->LIVE PREVIEW
|
||||
</span>
|
||||
<button class="icon-btn" aria-label="Help">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-question-mark" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="10">
|
||||
</circle>
|
||||
<path d="M12 2v2">
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3">
|
||||
</path>
|
||||
<path d="M12 20v2">
|
||||
</path>
|
||||
<path d="m4.93 4.93 1.41 1.41">
|
||||
</path>
|
||||
<path d="m17.66 17.66 1.41 1.41">
|
||||
</path>
|
||||
<path d="M2 12h2">
|
||||
</path>
|
||||
<path d="M20 12h2">
|
||||
</path>
|
||||
<path d="m6.34 17.66-1.41 1.41">
|
||||
</path>
|
||||
<path d="m19.07 4.93-1.41 1.41">
|
||||
<path d="M12 17h.01">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" aria-label="Toggle theme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon" aria-hidden="true">
|
||||
<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="language">
|
||||
<button class="active">RU
|
||||
</button>
|
||||
<span>/
|
||||
</span>
|
||||
<button>EN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="tool-page">
|
||||
|
||||
+62
-44
@@ -7,11 +7,6 @@
|
||||
@layer properties {
|
||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))) {
|
||||
*,:before,:after,::backdrop {
|
||||
--tw-rotate-x:initial;
|
||||
--tw-rotate-y:initial;
|
||||
--tw-rotate-z:initial;
|
||||
--tw-skew-x:initial;
|
||||
--tw-skew-y:initial;
|
||||
--tw-border-style:solid;
|
||||
--tw-font-weight:initial;
|
||||
--tw-shadow:0 0 #0000;
|
||||
@@ -290,12 +285,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
}
|
||||
@layer components;
|
||||
@layer utilities {
|
||||
.static {
|
||||
position:static
|
||||
}
|
||||
.inline {
|
||||
display:inline
|
||||
}
|
||||
.inline-flex {
|
||||
display:inline-flex
|
||||
}
|
||||
@@ -330,9 +319,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
.shrink-0 {
|
||||
flex-shrink:0
|
||||
}
|
||||
.transform {
|
||||
transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)
|
||||
}
|
||||
.items-center {
|
||||
align-items:center
|
||||
}
|
||||
@@ -630,7 +616,7 @@ button {
|
||||
--line:#33414c;
|
||||
--muted:#91a0ac;
|
||||
--blue:#54a2ff;
|
||||
background-image:linear-gradient(#1b252d 1px,#0000 1px),linear-gradient(90deg,#1b252d 1px,#0000 1px)
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.topbar,.brand,.top-actions,.language,.status,.title-row,.pipeline-head,.step-heading,.step-tools,.pipeline-footer,.preview-top,.footer {
|
||||
align-items:center;
|
||||
@@ -643,6 +629,26 @@ button {
|
||||
height:64px;
|
||||
padding:0 clamp(20px,4vw,64px)
|
||||
}
|
||||
.topbar>.brand {
|
||||
color:var(--foreground);
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav {
|
||||
align-items:center;
|
||||
gap:22px;
|
||||
margin-left:auto;
|
||||
margin-right:28px;
|
||||
display:flex
|
||||
}
|
||||
.top-nav a {
|
||||
color:var(--muted);
|
||||
font:10px var(--font-mono);
|
||||
white-space:nowrap;
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav a:hover,.top-nav a.active {
|
||||
color:var(--blue)
|
||||
}
|
||||
.brand {
|
||||
font:600 14px var(--font-mono);
|
||||
gap:10px
|
||||
@@ -1103,6 +1109,9 @@ h1 {
|
||||
gap:32px
|
||||
}
|
||||
|
||||
}
|
||||
.dark-mode .app-shell {
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.dark-mode .tile-canvas {
|
||||
background-color:#202a31;
|
||||
@@ -1113,7 +1122,22 @@ h1 {
|
||||
}
|
||||
@media (max-width:800px) {
|
||||
.topbar {
|
||||
padding:0 16px
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
height:auto;
|
||||
min-height:64px;
|
||||
padding:12px 16px
|
||||
}
|
||||
.top-nav {
|
||||
order:3;
|
||||
gap:12px;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding-bottom:2px;
|
||||
overflow:auto
|
||||
}
|
||||
.top-nav a {
|
||||
font-size:9px
|
||||
}
|
||||
.status {
|
||||
display:none
|
||||
@@ -1532,9 +1556,9 @@ h1 {
|
||||
}
|
||||
.catalog-page {
|
||||
width:100%;
|
||||
max-width:1680px;
|
||||
margin:0 auto;
|
||||
padding:64px clamp(24px,4vw,72px) 72px
|
||||
max-width:none;
|
||||
margin:0;
|
||||
padding:60px clamp(24px,4vw,72px) 72px
|
||||
}
|
||||
.catalog-head {
|
||||
border-bottom:1px solid var(--line);
|
||||
@@ -1803,26 +1827,6 @@ h1 {
|
||||
gap:12px 18px
|
||||
}
|
||||
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-border-style {
|
||||
syntax:"*";
|
||||
@@ -1986,18 +1990,30 @@ h1 {
|
||||
</div>
|
||||
<main class="app-shell">
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<a class="brand" href="/">
|
||||
<span class="brand-mark">EP
|
||||
</span>
|
||||
<span>easy-png-tools
|
||||
</span>
|
||||
<span class="version">/ DEMO
|
||||
<span class="version">/
|
||||
<!-- -->WORKSPACE
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<nav class="top-nav" aria-label="Primary navigation">
|
||||
<a class="active" href="/">Workspace
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/list-tools">Catalog
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/gradient">Gradient
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/background-remover">Background remover
|
||||
</a>
|
||||
</nav>
|
||||
<div class="top-actions">
|
||||
<span class="status">
|
||||
<i>
|
||||
</i> AUTO PIPELINE
|
||||
</i>
|
||||
<!-- -->AUTO PIPELINE
|
||||
</span>
|
||||
<button class="icon-btn" aria-label="Help">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-question-mark" aria-hidden="true">
|
||||
@@ -2018,7 +2034,9 @@ h1 {
|
||||
<div class="language">
|
||||
<button class="active">RU
|
||||
</button>
|
||||
<button class="">EN
|
||||
<span>/
|
||||
</span>
|
||||
<button>EN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+92
-46
@@ -7,11 +7,6 @@
|
||||
@layer properties {
|
||||
@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))) {
|
||||
*,:before,:after,::backdrop {
|
||||
--tw-rotate-x:initial;
|
||||
--tw-rotate-y:initial;
|
||||
--tw-rotate-z:initial;
|
||||
--tw-skew-x:initial;
|
||||
--tw-skew-y:initial;
|
||||
--tw-border-style:solid;
|
||||
--tw-font-weight:initial;
|
||||
--tw-shadow:0 0 #0000;
|
||||
@@ -290,12 +285,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
}
|
||||
@layer components;
|
||||
@layer utilities {
|
||||
.static {
|
||||
position:static
|
||||
}
|
||||
.inline {
|
||||
display:inline
|
||||
}
|
||||
.inline-flex {
|
||||
display:inline-flex
|
||||
}
|
||||
@@ -330,9 +319,6 @@ button,input:where([type=button],[type=reset],[type=submit]) {
|
||||
.shrink-0 {
|
||||
flex-shrink:0
|
||||
}
|
||||
.transform {
|
||||
transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)
|
||||
}
|
||||
.items-center {
|
||||
align-items:center
|
||||
}
|
||||
@@ -630,7 +616,7 @@ button {
|
||||
--line:#33414c;
|
||||
--muted:#91a0ac;
|
||||
--blue:#54a2ff;
|
||||
background-image:linear-gradient(#1b252d 1px,#0000 1px),linear-gradient(90deg,#1b252d 1px,#0000 1px)
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.topbar,.brand,.top-actions,.language,.status,.title-row,.pipeline-head,.step-heading,.step-tools,.pipeline-footer,.preview-top,.footer {
|
||||
align-items:center;
|
||||
@@ -643,6 +629,26 @@ button {
|
||||
height:64px;
|
||||
padding:0 clamp(20px,4vw,64px)
|
||||
}
|
||||
.topbar>.brand {
|
||||
color:var(--foreground);
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav {
|
||||
align-items:center;
|
||||
gap:22px;
|
||||
margin-left:auto;
|
||||
margin-right:28px;
|
||||
display:flex
|
||||
}
|
||||
.top-nav a {
|
||||
color:var(--muted);
|
||||
font:10px var(--font-mono);
|
||||
white-space:nowrap;
|
||||
text-decoration:none
|
||||
}
|
||||
.top-nav a:hover,.top-nav a.active {
|
||||
color:var(--blue)
|
||||
}
|
||||
.brand {
|
||||
font:600 14px var(--font-mono);
|
||||
gap:10px
|
||||
@@ -1103,6 +1109,9 @@ h1 {
|
||||
gap:32px
|
||||
}
|
||||
|
||||
}
|
||||
.dark-mode .app-shell {
|
||||
background-image:linear-gradient(#1e2a3447 1px,#0000 1px),linear-gradient(90deg,#1e2a3447 1px,#0000 1px)
|
||||
}
|
||||
.dark-mode .tile-canvas {
|
||||
background-color:#202a31;
|
||||
@@ -1113,7 +1122,22 @@ h1 {
|
||||
}
|
||||
@media (max-width:800px) {
|
||||
.topbar {
|
||||
padding:0 16px
|
||||
flex-wrap:wrap;
|
||||
gap:12px;
|
||||
height:auto;
|
||||
min-height:64px;
|
||||
padding:12px 16px
|
||||
}
|
||||
.top-nav {
|
||||
order:3;
|
||||
gap:12px;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding-bottom:2px;
|
||||
overflow:auto
|
||||
}
|
||||
.top-nav a {
|
||||
font-size:9px
|
||||
}
|
||||
.status {
|
||||
display:none
|
||||
@@ -1532,9 +1556,9 @@ h1 {
|
||||
}
|
||||
.catalog-page {
|
||||
width:100%;
|
||||
max-width:1680px;
|
||||
margin:0 auto;
|
||||
padding:64px clamp(24px,4vw,72px) 72px
|
||||
max-width:none;
|
||||
margin:0;
|
||||
padding:60px clamp(24px,4vw,72px) 72px
|
||||
}
|
||||
.catalog-head {
|
||||
border-bottom:1px solid var(--line);
|
||||
@@ -1803,26 +1827,6 @@ h1 {
|
||||
gap:12px 18px
|
||||
}
|
||||
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax:"*";
|
||||
inherits:false
|
||||
}
|
||||
@property --tw-border-style {
|
||||
syntax:"*";
|
||||
@@ -1984,19 +1988,60 @@ h1 {
|
||||
<!--$-->
|
||||
<!--/$-->
|
||||
</div>
|
||||
<main class="catalog-page">
|
||||
<header class="catalog-nav">
|
||||
<a class="catalog-brand" href="/">easy-png-tools
|
||||
<main class="app-shell">
|
||||
<header class="topbar">
|
||||
<a class="brand" href="/">
|
||||
<span class="brand-mark">EP
|
||||
</span>
|
||||
<span>easy-png-tools
|
||||
</span>
|
||||
<span class="version">/
|
||||
<!-- -->CATALOG
|
||||
</span>
|
||||
</a>
|
||||
<nav>
|
||||
<a href="/">Workspace
|
||||
<nav class="top-nav" aria-label="Primary navigation">
|
||||
<a class="" href="/">Workspace
|
||||
</a>
|
||||
<a class="current" href="/easy-png-tools/list-tools">Catalog
|
||||
<a class="active" href="/easy-png-tools/list-tools">Catalog
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/gradient">Gradient
|
||||
</a>
|
||||
<a class="" href="/easy-png-tools/background-remover">Background remover
|
||||
</a>
|
||||
</nav>
|
||||
<span class="catalog-nav-status">LOCAL MODE / READY
|
||||
<div class="top-actions">
|
||||
<span class="status">
|
||||
<i>
|
||||
</i>
|
||||
<!-- -->LOCAL MODE / READY
|
||||
</span>
|
||||
<button class="icon-btn" aria-label="Help">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-question-mark" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="10">
|
||||
</circle>
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3">
|
||||
</path>
|
||||
<path d="M12 17h.01">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="icon-btn" aria-label="Toggle theme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon" aria-hidden="true">
|
||||
<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="language">
|
||||
<button class="active">RU
|
||||
</button>
|
||||
<span>/
|
||||
</span>
|
||||
<button>EN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="catalog-page">
|
||||
<div class="catalog-head">
|
||||
<div>
|
||||
<div class="eyebrow">EASY-PNG-TOOLS / CATALOG
|
||||
@@ -2901,6 +2946,7 @@ h1 {
|
||||
<span>•
|
||||
</span> YOUR FILES NEVER LEAVE THIS DEVICE
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
<!--$-->
|
||||
<!--/$-->
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
'use client'
|
||||
|
||||
import TopBar from '@/components/top-bar'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Download, Moon, RotateCcw, Sun, Upload, Check } from 'lucide-react'
|
||||
import { Download, RotateCcw, Upload, Check } from 'lucide-react'
|
||||
|
||||
export default function BackgroundRemoverPage() {
|
||||
const [color, setColor] = useState('#E8EEF2')
|
||||
const [similarity, setSimilarity] = useState(72)
|
||||
const [outerOnly, setOuterOnly] = useState(true)
|
||||
const [showMask, setShowMask] = useState(false)
|
||||
const [dark, setDark] = useState(true)
|
||||
const [downloaded, setDownloaded] = useState(false)
|
||||
const previewBackground = showMask ? 'repeating-conic-gradient(#7b8791 0 25%, #cbd3da 0 50%) 50% / 28px 28px' : 'repeating-conic-gradient(#d7dce0 0 25%, #f3f5f6 0 50%) 50% / 28px 28px'
|
||||
const subjectStyle = useMemo(() => ({ background: showMask ? '#596773' : 'linear-gradient(145deg,#1769d2 0 38%,#00a8c7 38% 66%,#bd7411 66%)', opacity: showMask ? .88 : 1, clipPath: `polygon(23% 11%, 73% 8%, 89% 30%, 79% 81%, 52% 93%, 17% 78%, 8% 39%)` }), [showMask])
|
||||
const reset = () => { setColor('#E8EEF2'); setSimilarity(72); setOuterOnly(true); setShowMask(false) }
|
||||
return <main className={`app-shell ${dark ? 'dark-mode' : ''}`}>
|
||||
<header className="topbar"><div className="brand"><span className="brand-mark">EP</span><span>easy-png-tools</span><span className="version">/ BACKGROUND REMOVER</span></div><div className="top-actions"><span className="status"><i /> AUTO PROCESSING</span><button className="icon-btn" aria-label="Toggle theme" onClick={() => setDark(!dark)}>{dark ? <Sun size={17} /> : <Moon size={17} />}</button></div></header>
|
||||
return <main className="app-shell">
|
||||
<TopBar section="BACKGROUND REMOVER" status="AUTO PROCESSING" />
|
||||
<div className="tool-page"><div className="eyebrow">PNG PROCESSING <span>/</span> SINGLE TOOL</div><div className="tool-title"><div><h1>Remove background.</h1><p className="lede">Select a background color and tune the edge detection. Changes are processed automatically in your browser.</p></div><span className="tool-status"><i /> LIVE PREVIEW</span></div>
|
||||
<div className="remover-layout"><section className="settings-panel"><div className="panel-heading"><div><span className="label">REMOVER SETTINGS</span><strong>Configure detection</strong></div><span className="step-type">TOOL 02</span></div>
|
||||
<div className="setting-group"><label>BACKGROUND COLOR</label><div className="color-field"><span className="swatch" style={{ background: color }} /><input value={color} onChange={e => setColor(e.target.value)} /><input className="native-color" type="color" value={color} onChange={e => setColor(e.target.value)} aria-label="Choose background color" /></div><div className="color-reference"><span style={{ background: color }} /> sampled from image background</div></div>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import TopBar from '@/components/top-bar'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Check, ChevronDown, Copy, Download, Moon, RotateCcw, Sun } from 'lucide-react'
|
||||
import { Check, ChevronDown, Copy, Download, RotateCcw } from 'lucide-react'
|
||||
|
||||
const directions = ['0° →', '45° ↗', '90° ↑', '135° ↖', '180° ←', '225° ↙', '270° ↓', '315° ↘']
|
||||
|
||||
@@ -11,14 +12,13 @@ export default function GradientPage() {
|
||||
const [direction, setDirection] = useState(135)
|
||||
const [opacity, setOpacity] = useState(100)
|
||||
const [type, setType] = useState<'linear' | 'radial'>('linear')
|
||||
const [dark, setDark] = useState(true)
|
||||
const [copied, setCopied] = useState(false)
|
||||
const gradient = useMemo(() => type === 'linear' ? `linear-gradient(${direction}deg, ${start} 0%, ${end} 100%)` : `radial-gradient(circle, ${start} 0%, ${end} 100%)`, [direction, end, start, type])
|
||||
const css = `background: ${gradient};\nopacity: ${opacity / 100};`
|
||||
const reset = () => { setStart('#1769D2'); setEnd('#00A8C7'); setDirection(135); setOpacity(100); setType('linear') }
|
||||
const copyCss = async () => { await navigator.clipboard?.writeText(css); setCopied(true); setTimeout(() => setCopied(false), 1400) }
|
||||
return <main className={`app-shell ${dark ? 'dark-mode' : ''}`}>
|
||||
<header className="topbar"><div className="brand"><span className="brand-mark">EP</span><span>easy-png-tools</span><span className="version">/ GRADIENT</span></div><div className="top-actions"><button className="icon-btn" aria-label="Toggle theme" onClick={() => setDark(!dark)}>{dark ? <Sun size={17} /> : <Moon size={17} />}</button></div></header>
|
||||
return <main className="app-shell">
|
||||
<TopBar section="GRADIENT" status="LIVE PREVIEW" />
|
||||
<div className="tool-page"><div className="eyebrow">PNG PROCESSING <span>/</span> SINGLE TOOL</div><div className="tool-title"><div><h1>Gradient background.</h1><p className="lede">Create a clean, export-ready gradient with precise control over color, direction and transparency.</p></div><span className="tool-status"><i /> LIVE PREVIEW</span></div>
|
||||
<div className="gradient-layout"><section className="settings-panel"><div className="panel-heading"><div><span className="label">GRADIENT SETTINGS</span><strong>Configure output</strong></div><span className="step-type">TOOL 01</span></div>
|
||||
<div className="setting-group"><label>GRADIENT TYPE</label><div className="segmented wide"><button className={type === 'linear' ? 'selected' : ''} onClick={() => setType('linear')}>Linear</button><button className={type === 'radial' ? 'selected' : ''} onClick={() => setType('radial')}>Radial</button></div></div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import TopBar from '@/components/top-bar'
|
||||
import Link from "next/link"
|
||||
import { useMemo, useState } from "react"
|
||||
import { ArrowUpRight, FileImage, Filter, Search, Sparkles } from "lucide-react"
|
||||
@@ -17,11 +18,11 @@ export default function ListToolsPage() {
|
||||
const [query, setQuery] = useState("")
|
||||
const [active, setActive] = useState("ALL")
|
||||
const filtered = useMemo(() => groups.map(group => ({ ...group, tools: group.tools.filter(([name, description]) => (active === "ALL" || active === group.name) && `${name} ${description}`.toLowerCase().includes(query.toLowerCase())) })).filter(group => group.tools.length), [query, active])
|
||||
return <main className="catalog-page"><header className="catalog-nav"><Link href="/" className="catalog-brand">easy-png-tools</Link><nav><Link href="/">Workspace</Link><Link className="current" href="/easy-png-tools/list-tools">Catalog</Link></nav><span className="catalog-nav-status">LOCAL MODE / READY</span></header>
|
||||
return <main className="app-shell"><TopBar section="CATALOG" status="LOCAL MODE / READY" /><div className="catalog-page">
|
||||
<div className="catalog-head"><div><div className="eyebrow">EASY-PNG-TOOLS / CATALOG</div><h1>Tool catalog</h1><p>Focused utilities for working with PNG. Inspect, transform, and export — locally in your browser.</p></div><div className="catalog-total"><b>32</b><span>TOOLS<br />AVAILABLE</span></div></div>
|
||||
<div className="catalog-toolbar"><label className="catalog-search"><Search size={16} /><input aria-label="Search tools" placeholder="Search tools..." value={query} onChange={e => setQuery(e.target.value)} /></label><div className="catalog-filters"><Filter size={15} />{["ALL", ...groups.map(g => g.name)].map(name => <button key={name} className={active === name ? "active" : ""} onClick={() => setActive(name)}>{name}</button>)}</div></div>
|
||||
<div className="catalog-groups">{filtered.map(group => <section className="catalog-group" key={group.name}><div className="group-title"><span>{group.name}</span><i>{String(group.tools.length).padStart(2, "0")} TOOLS</i></div><div className="tool-cards">{group.tools.map(([name, description, href], index) => <Link className="tool-card" href={href || "#"} key={name} onClick={e => { if (!href) e.preventDefault() }}><span className="tool-icon"><FileImage size={19} /></span><span className="tool-copy"><strong>{name}</strong><span>{description}</span></span><span className="tool-index">{String(index + 1).padStart(2, "0")}</span><ArrowUpRight size={16} className="tool-arrow" /></Link>)}</div></section>)}</div>
|
||||
{!filtered.length && <div className="catalog-empty"><Sparkles size={18} /> No tools match your search.</div>}
|
||||
<footer className="catalog-footer">ALL OPERATIONS RUN LOCALLY <span>•</span> YOUR FILES NEVER LEAVE THIS DEVICE</footer>
|
||||
</main>
|
||||
</div></main>
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+4
-4
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import TopBar from '@/components/top-bar'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { ArrowDownToLine, Check, ChevronDown, CircleHelp, Download, GripVertical, Link2, Moon, MoreHorizontal, Plus, RotateCcw, Settings2, SlidersHorizontal, Sun, Upload, X } from 'lucide-react'
|
||||
import { ArrowDownToLine, Check, ChevronDown, Download, GripVertical, Link2, MoreHorizontal, Plus, RotateCcw, Settings2, SlidersHorizontal, Upload, X } from 'lucide-react'
|
||||
|
||||
const initialSteps = [
|
||||
{ id: 1, title: 'Gradient background', type: 'BACKGROUND' },
|
||||
@@ -20,14 +21,13 @@ export default function Page() {
|
||||
const [radius, setRadius] = useState(18)
|
||||
const [outline, setOutline] = useState(2)
|
||||
const [language, setLanguage] = useState('RU')
|
||||
const [dark, setDark] = useState(false)
|
||||
const [showIntermediate, setShowIntermediate] = useState(true)
|
||||
const [gradient, setGradient] = useState('#DCEBFF')
|
||||
const gradientStyle = useMemo(() => ({ background: `linear-gradient(${angle}deg, ${gradient}, #8BC8F5)` }), [angle, gradient])
|
||||
const finalStyle = { ...gradientStyle, borderRadius: radius, boxShadow: `0 0 0 ${outline}px #16202B` }
|
||||
|
||||
return <main className={dark ? 'app-shell dark-mode' : 'app-shell'}>
|
||||
<header className="topbar"><div className="brand"><span className="brand-mark">EP</span><span>easy-png-tools</span><span className="version">/ DEMO</span></div><div className="top-actions"><span className="status"><i /> AUTO PIPELINE</span><button className="icon-btn" aria-label="Help"><CircleHelp size={17} /></button><button className="icon-btn" aria-label="Toggle theme" onClick={() => setDark(!dark)}>{dark ? <Sun size={17} /> : <Moon size={17} />}</button><div className="language"><button className={language === 'RU' ? 'active' : ''} onClick={() => setLanguage('RU')}>RU</button><button className={language === 'EN' ? 'active' : ''} onClick={() => setLanguage('EN')}>EN</button></div></div></header>
|
||||
return <main className="app-shell">
|
||||
<TopBar section="WORKSPACE" status="AUTO PIPELINE" />
|
||||
<div className="page-grid">
|
||||
<section className="workspace"><div className="eyebrow">PNG PROCESSING <span>/</span> WORKSPACE</div><div className="title-row"><div><h1>Build your image pipeline.</h1><p className="lede">Chain simple tools together. Every change is processed automatically and previewed at each stage.</p></div><div className="file-chip"><Upload size={15} /><span>source.png</span><b>1.8 MB</b></div></div>
|
||||
<div className="pipeline-head"><div><span className="label">PROCESSING PIPELINE</span><strong>{steps.length} active steps <em>• LIVE</em></strong></div><button className="add-btn" onClick={() => setSteps([...steps, { id: Date.now(), title: 'New adjustment', type: 'STYLE' }])}><Plus size={15} /> Add tool</button></div>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import { CircleHelp, Moon, Sun } from "lucide-react"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
const links = [
|
||||
["Workspace", "/"],
|
||||
["Catalog", "/easy-png-tools/list-tools"],
|
||||
["Gradient", "/easy-png-tools/gradient"],
|
||||
["Background remover", "/easy-png-tools/background-remover"],
|
||||
] as const
|
||||
|
||||
export function TopBar({ section = "WORKSPACE", status = "LOCAL MODE / READY" }: { section?: string; status?: string }) {
|
||||
const pathname = usePathname()
|
||||
const [dark, setDark] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const stored = window.localStorage.getItem("ep-theme")
|
||||
const isDark = stored === "dark"
|
||||
setDark(isDark)
|
||||
document.documentElement.classList.toggle("dark-mode", isDark)
|
||||
}, [])
|
||||
|
||||
const toggleTheme = () => {
|
||||
const next = !dark
|
||||
setDark(next)
|
||||
document.documentElement.classList.toggle("dark-mode", next)
|
||||
window.localStorage.setItem("ep-theme", next ? "dark" : "light")
|
||||
}
|
||||
|
||||
return <header className="topbar"><Link href="/" className="brand"><span className="brand-mark">EP</span><span>easy-png-tools</span><span className="version">/ {section}</span></Link><nav className="top-nav" aria-label="Primary navigation">{links.map(([label, href]) => <Link key={href} className={pathname === href ? "active" : ""} href={href}>{label}</Link>)}</nav><div className="top-actions"><span className="status"><i /> {status}</span><button className="icon-btn" aria-label="Help"><CircleHelp size={17} /></button><button className="icon-btn" aria-label="Toggle theme" onClick={toggleTheme}>{dark ? <Sun size={17} /> : <Moon size={17} />}</button><div className="language"><button className="active">RU</button><span>/</span><button>EN</button></div></div></header>
|
||||
}
|
||||
|
||||
export default TopBar
|
||||
@@ -5,7 +5,6 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"html": "node extract-static.mjs .next\\server\\app ..\\refs-html",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
Generated
+1
-4
@@ -4,9 +4,6 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
hono: 4.12.25
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -268,7 +265,7 @@ packages:
|
||||
resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==}
|
||||
engines: {node: '>=18.14.1'}
|
||||
peerDependencies:
|
||||
hono: 4.12.25
|
||||
hono: ^4
|
||||
|
||||
'@img/colour@1.1.0':
|
||||
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Reference in New Issue
Block a user