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:
Artemy Egorov 2024-02-14 10:23:13 +03:00 committed by GitHub
parent ead78e79ab
commit 3b5f402d77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 250 additions and 183 deletions

50
package-lock.json generated
View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"name": "txtdot",
"version": "1.5.1",
"version": "1.5.2",
"private": true,
"description": "",
"main": "dist/app.js",

View File

@ -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',
};

View File

@ -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
View 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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
@media (max-width: 504px) {
.form-search {
margin: 0.25rem;
}
#search::placeholder {
color: var(--fg2);
opacity: 1;
}

View 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>

View 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>

View File

@ -0,0 +1,6 @@
<%
if (config.search.enabled) {
%><link rel="stylesheet" href="/static/search.css">
<link rel="stylesheet" href="/static/form-inputs.css"><%
}
%>

View File

@ -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>

View File

@ -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>