Interface improvements (#74)
* fix: interface style improvements and components in ejs templates * fix: improvement of improvements * Redesign: kind of MD3 * Working url/search switch * formatting * Add switch animation, adjust sizes, adjust btn colors, rename bg2 to outline * Format --------- Co-authored-by: DarkCat09 <gh@dc09.ru>
This commit is contained in:
parent
ead78e79ab
commit
3b5f402d77
50
package-lock.json
generated
50
package-lock.json
generated
@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "txtdot",
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "txtdot",
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/static": "^6.12.0",
|
||||
"@fastify/swagger": "^8.13.0",
|
||||
"@fastify/swagger-ui": "^1.10.2",
|
||||
"@fastify/swagger-ui": "^2.0.1",
|
||||
"@fastify/view": "^8.2.0",
|
||||
"@mozilla/readability": "^0.4.4",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"axios": "^1.6.5",
|
||||
"dompurify": "^3.0.8",
|
||||
"dotenv": "^16.3.1",
|
||||
@ -21,24 +21,24 @@
|
||||
"fastify": "^4.25.2",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"ip-range-check": "^0.2.0",
|
||||
"json-schema-to-ts": "^2.12.0",
|
||||
"json-schema-to-ts": "^3.0.0",
|
||||
"linkedom": "^0.16.6",
|
||||
"micromatch": "^4.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dompurify": "^3.0.3",
|
||||
"@types/ejs": "^3.1.2",
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/micromatch": "^4.0.2",
|
||||
"@types/node": "^20.4.10",
|
||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||
"@typescript-eslint/parser": "^6.3.0",
|
||||
"clean-css-cli": "^5.6.2",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/ejs": "^3.1.5",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/micromatch": "^4.0.6",
|
||||
"@types/node": "^20.10.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"clean-css-cli": "^5.6.3",
|
||||
"copyfiles": "^2.4.1",
|
||||
"eslint": "^8.47.0",
|
||||
"prettier": "^3.1.0",
|
||||
"eslint": "^8.56.0",
|
||||
"prettier": "^3.1.1",
|
||||
"tsc-watch": "^6.0.4",
|
||||
"typescript": "^5.1.6"
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@ -233,9 +233,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/swagger-ui": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-1.10.2.tgz",
|
||||
"integrity": "sha512-f2mRqtblm6eRAFQ3e8zSngxVNEtiYY7rISKQVjPA++ZsWc5WYlPVTb6Bx0G/zy0BIoucNqDr/Q2Vb/kTYkOq1A==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-2.0.1.tgz",
|
||||
"integrity": "sha512-sQnufSdQ5kJxaTxBisWYQjkunECuRymYRZYEZEEPpmLUzzZoS22tDLVumb3c1TV4MAlD3L1LTLpxLSXcFL+OZw==",
|
||||
"dependencies": {
|
||||
"@fastify/static": "^6.0.0",
|
||||
"fastify-plugin": "^4.0.0",
|
||||
@ -317,9 +317,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mozilla/readability": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.4.4.tgz",
|
||||
"integrity": "sha512-MCgZyANpJ6msfvVMi6+A0UAsvZj//4OHREYUB9f2087uXHVoU+H+SWhuihvb1beKpM323bReQPRio0WNk2+V6g==",
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.5.0.tgz",
|
||||
"integrity": "sha512-Z+CZ3QaosfFaTqvhQsIktyGrjFjSC0Fa4EMph4mqKnWhmyoGICsV/8QK+8HpXut6zV7zwfWwqDmEjtk1Qf6EgQ==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@ -2273,9 +2273,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-to-ts": {
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-2.12.0.tgz",
|
||||
"integrity": "sha512-uTde38yBm5lzJSRPWRaasxZo72pb+JGE4iUksNdNfAkFaLhV4N9akeBxPPUpZy5onINt9Zo0oTLrAoEXyZESiQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.0.0.tgz",
|
||||
"integrity": "sha512-2adDesYifYEXYxNySx3gG0RR69rDWIjqAFzK/JPXdOvjHLZ/UP6d2rkpy6a+AxyhtRp2SvFPZ4+EW36jBinUbA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "txtdot",
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"main": "dist/app.js",
|
||||
|
@ -1,5 +1,5 @@
|
||||
export default {
|
||||
version: '1.5.1',
|
||||
version: '1.5.2',
|
||||
description:
|
||||
'txtdot is an HTTP proxy that parses only text, links and pictures from pages reducing internet bandwidth usage, removing ads and heavy scripts',
|
||||
};
|
||||
|
@ -3,28 +3,34 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--bg: #fff;
|
||||
--fg: #111;
|
||||
--bg: #fdfbff;
|
||||
--fg: #1a1c1e;
|
||||
|
||||
--bg2: #bbb;
|
||||
--fg2: #333;
|
||||
--outline: #74777f;
|
||||
|
||||
--accent: #0070cc; /* hsl(207, 100%, 40%) */
|
||||
--accent-hl: #003866; /* hsl(207, 100%, 20%) */
|
||||
--accent: #255fa4;
|
||||
--accent-hl: #003060;
|
||||
|
||||
--error: #ff9400;
|
||||
--btn-hl: #4178c1;
|
||||
--btn2-hl: rgba(189, 199, 220, 0.5);
|
||||
|
||||
--error: #ff897d;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #222;
|
||||
--fg: #eee;
|
||||
--bg: #1a1c1e;
|
||||
--fg: #e3e2e6;
|
||||
|
||||
--bg2: #444;
|
||||
--fg2: #bbb;
|
||||
--outline: #8e9199;
|
||||
|
||||
--accent: #33a3ff; /* hsl(207, 100%, 60%) */
|
||||
--accent-hl: #99d1ff; /* hsl(207, 100%, 80%) */
|
||||
--accent: #a6c8ff;
|
||||
--accent-hl: #d6e3ff;
|
||||
|
||||
--btn-hl: #79adf9;
|
||||
--btn2-hl: rgba(189, 199, 220, 0.2);
|
||||
|
||||
--error: #ffb4ab;
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,28 +54,41 @@ main {
|
||||
.menu {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
column-gap: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 0.25rem 0.75rem;
|
||||
padding: 0.25rem 1rem;
|
||||
|
||||
border: 0.125rem solid var(--accent);
|
||||
border-radius: 0.25rem;
|
||||
border: none;
|
||||
border-radius: 1rem;
|
||||
|
||||
background: var(--accent);
|
||||
color: var(--bg);
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
transition: background-color 0.15s ease-out;
|
||||
}
|
||||
.button.secondary {
|
||||
border-color: var(--bg2);
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: var(--bg2);
|
||||
background: var(--btn-hl);
|
||||
}
|
||||
|
||||
.button.secondary {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.button.secondary:hover {
|
||||
background: var(--btn2-hl);
|
||||
}
|
||||
|
||||
a {
|
||||
|
20
static/form-inputs.css
Normal file
20
static/form-inputs.css
Normal file
@ -0,0 +1,20 @@
|
||||
input[type='text'],
|
||||
select {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
border-bottom: 1px var(--outline) solid;
|
||||
padding: 0.25rem 0.25rem;
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-size: 1rem;
|
||||
|
||||
width: 100%;
|
||||
|
||||
transition: border-bottom 0.25s ease-out;
|
||||
}
|
||||
|
||||
input[type='text']:focus,
|
||||
select:focus {
|
||||
border-bottom-color: var(--accent);
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
gap: 0.5rem 0.25rem;
|
||||
|
||||
width: fit-content;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
@ -23,41 +24,83 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#url,
|
||||
#search {
|
||||
width: 100%;
|
||||
height: 100%; /* shrink to #submit height */
|
||||
.switch-label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
outline: none;
|
||||
border: 0;
|
||||
border-bottom: 0.125rem solid var(--fg2);
|
||||
.switch-btn {
|
||||
width: 3rem;
|
||||
height: 1.75rem;
|
||||
|
||||
border-radius: 1rem;
|
||||
|
||||
background: var(--outline);
|
||||
|
||||
padding: 0.375rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.switch-btn::before {
|
||||
content: '';
|
||||
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
||||
transform: translateX(0);
|
||||
transition:
|
||||
transform 0.15s ease-out,
|
||||
opacity 0.15s ease-out;
|
||||
|
||||
border-radius: 1rem;
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-size: 1rem;
|
||||
}
|
||||
#url::placeholder {
|
||||
color: var(--fg2);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#submit {
|
||||
font-size: 1rem;
|
||||
.switch-btn:hover::before {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
select {
|
||||
border: 0;
|
||||
border-bottom: 0.125rem solid var(--accent);
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
#switch-search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#switch-search:checked ~ .switch-label > .switch-btn {
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
#switch-search:checked ~ .switch-label > .switch-btn::before {
|
||||
/* track width - handle width - (2 * horizontal track padding) */
|
||||
transform: translateX(calc(3rem - 1rem - 2 * 0.375rem));
|
||||
}
|
||||
|
||||
#switch-search:not(:checked) ~ .main-form-search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#switch-search:not(:checked) ~ .main-form-url {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
#switch-search:checked ~ .main-form-search {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
#switch-search:checked ~ .main-form-url {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
.menu .button {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
border-bottom: 0.125rem solid var(--bg2);
|
||||
border-bottom: 0.125rem solid var(--outline);
|
||||
padding-bottom: 0.125rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
@ -11,6 +7,7 @@
|
||||
a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--accent-hl);
|
||||
}
|
||||
|
@ -1,25 +1,12 @@
|
||||
.right {
|
||||
.form-search {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.25rem 0.375rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
#search {
|
||||
width: 100%;
|
||||
height: 100%; /* shrink to #submit height */
|
||||
|
||||
outline: none;
|
||||
border: 0;
|
||||
border-bottom: 0.125rem solid var(--fg2);
|
||||
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-size: 1rem;
|
||||
|
||||
margin-right: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
#search::placeholder {
|
||||
color: var(--fg2);
|
||||
opacity: 1;
|
||||
@media (max-width: 504px) {
|
||||
.form-search {
|
||||
margin: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
51
templates/components/form-main.ejs
Normal file
51
templates/components/form-main.ejs
Normal file
@ -0,0 +1,51 @@
|
||||
<% search = config.search.enabled %>
|
||||
|
||||
<% if (search) { %>
|
||||
|
||||
<input type="checkbox" id="switch-search" checked>
|
||||
|
||||
<label for="switch-search" class="switch-label">
|
||||
<span>URL</span>
|
||||
<span class="switch-btn"></span>
|
||||
<span>Search</span>
|
||||
</label>
|
||||
|
||||
<form action="/search" method="get" class="input-grid main-form-search">
|
||||
<div class="input">
|
||||
<input type="text" name="q" id="search" placeholder="Search">
|
||||
</div>
|
||||
<div class="input">
|
||||
<input type="submit" id="submit" class="button" value="Go">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<% } %>
|
||||
|
||||
<form action="/get" method="get" class="input-grid <%= search ? "main-form-url" : "" %>">
|
||||
<div class="input">
|
||||
<input type="text" name="url" id="url" placeholder="URL">
|
||||
</div>
|
||||
<div class="input">
|
||||
<input type="submit" id="submit" class="button" value="Parse">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<div class="input">
|
||||
<label for="engine">Engine</label>
|
||||
<select name="engine">
|
||||
<option value="" selected>Default</option>
|
||||
<% engineList.forEach((engine) => { %>
|
||||
<option value="<%= engine %>">
|
||||
<%= engine %>
|
||||
</option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="format">Format</label>
|
||||
<select name="format">
|
||||
<option value="html" selected>HTML</option>
|
||||
<option value="text">Text</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
14
templates/components/menu.ejs
Normal file
14
templates/components/menu.ejs
Normal file
@ -0,0 +1,14 @@
|
||||
<div class="menu">
|
||||
<a class="button secondary" href="/">Home</a>
|
||||
<a class="button secondary" href="<%= remoteUrl %>">Original page</a>
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
%>
|
||||
<form class="form-search" action="/search" method="get">
|
||||
<input type="text" name="q" id="search" placeholder="Search">
|
||||
<input class="button" type="submit" value="Go"/>
|
||||
</form>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
6
templates/components/search-styles.ejs
Normal file
6
templates/components/search-styles.ejs
Normal file
@ -0,0 +1,6 @@
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
%><link rel="stylesheet" href="/static/search.css">
|
||||
<link rel="stylesheet" href="/static/form-inputs.css"><%
|
||||
}
|
||||
%>
|
@ -1,38 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="<%= parsed.lang %>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<title><%= parsed.title %></title>
|
||||
<link rel="stylesheet" href="/static/common.css">
|
||||
<link rel="stylesheet" href="/static/get.css">
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
%><link rel="stylesheet" href="/static/search.css"><%
|
||||
}
|
||||
%>
|
||||
<link rel="stylesheet" href="/static/common.css" />
|
||||
<link rel="stylesheet" href="/static/get.css" />
|
||||
<%- include('./components/search-styles.ejs') %>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="menu">
|
||||
<a class="button secondary" href="/">Home</a>
|
||||
<a class="button secondary" href="<%= remoteUrl %>">Original page</a>
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
%>
|
||||
<form class="right" action="/search" method="get">
|
||||
<input type="text" name="q" id="search" placeholder="Search">
|
||||
<input class="button" type="submit" value="Go"/>
|
||||
</form>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
<p class="title">
|
||||
<%= parsed.title %>
|
||||
</p>
|
||||
<%- include('./components/menu.ejs') %>
|
||||
<p class="title"><%= parsed.title %></p>
|
||||
<%- parsed.content %>
|
||||
</main>
|
||||
</body>
|
||||
|
@ -9,71 +9,20 @@
|
||||
<link rel="stylesheet" href="/static/common.css">
|
||||
<link rel="stylesheet" href="/static/index.css">
|
||||
<link rel="stylesheet" href="/static/form.css">
|
||||
<link rel="stylesheet" href="/static/form-inputs.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<header>
|
||||
<h1>txt<span class="dot">.</span></h1>
|
||||
<p class="menu">
|
||||
<div class="menu">
|
||||
<a href="https://github.com/TxtDot/txtdot/releases/latest" class="button secondary">v<%= publicConfig.version %></a>
|
||||
<a href="https://github.com/txtdot/txtdot" class="button secondary">GitHub</a>
|
||||
<a href="https://txtdot.github.io/documentation" class="button secondary">Docs</a>
|
||||
</p>
|
||||
</div>
|
||||
<p><%= publicConfig.description %></p>
|
||||
</header>
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
|
||||
%>
|
||||
<form action="/search" method="get" class="input-grid">
|
||||
<div class="input">
|
||||
<input type="text" name="q" id="search" placeholder="Search">
|
||||
</div>
|
||||
<div class="input">
|
||||
<input type="submit" id="submit" class="button" value="Go">
|
||||
</div>
|
||||
</form>
|
||||
<%
|
||||
|
||||
%><details style="margin-top: 1rem;"><summary>Advanced</summary><%
|
||||
}
|
||||
%>
|
||||
<form action="/get" method="get" class="input-grid">
|
||||
<div class="input">
|
||||
<input type="text" name="url" id="url" placeholder="URL">
|
||||
</div>
|
||||
<div class="input">
|
||||
<input type="submit" id="submit" class="button" value="Parse">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<div class="input">
|
||||
<label for="engine">Engine</label>
|
||||
<select name="engine">
|
||||
<option value="" selected>Default</option>
|
||||
<% engineList.forEach((engine)=> {
|
||||
%>
|
||||
<option value="<%= engine %>">
|
||||
<%= engine %>
|
||||
</option>
|
||||
<%
|
||||
})
|
||||
%>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="format">Format</label>
|
||||
<select name="format">
|
||||
<option value="html" selected>HTML</option>
|
||||
<option value="text">Text</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<%
|
||||
if (config.search.enabled) {
|
||||
%></details><%
|
||||
}
|
||||
%>
|
||||
<%- include('./components/form-main.ejs') %>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
x
Reference in New Issue
Block a user