mirror of
https://github.com/standardebooks/web.git
synced 2025-07-12 17:42:29 -04:00
Merge reset.css into core.css, and add settings page for specifying dark mode preferences
This commit is contained in:
parent
27d081b644
commit
11224136d1
9 changed files with 272 additions and 196 deletions
|
@ -138,6 +138,14 @@ Define domain standardebooks.org
|
|||
ProxySet connectiontimeout=5 timeout=240
|
||||
</Proxy>
|
||||
|
||||
# In RewriteCond, RewriteRule gets evaluated BEFORE RewriteCond, so $1 refers to the first
|
||||
# match in RewriteRule
|
||||
# Rewrite POST /some/url -> POST /some/url/post.php
|
||||
RewriteCond %{REQUEST_METHOD} ^POST$
|
||||
RewriteCond %{DOCUMENT_ROOT}/$1/ -d
|
||||
RewriteCond %{DOCUMENT_ROOT}/$1/post.php -f
|
||||
RewriteRule ^([^\.]+)$ $1/post.php [L]
|
||||
|
||||
# In case of 404, serve the 404 page specified by ErrorDocument, not the default FPM error page.
|
||||
# Note that we can't use `ProxyErrorOverride on` because that catches ALL 4xx and 5xx HTTP headers
|
||||
# and serves the default Apache page for them.
|
||||
|
|
|
@ -137,6 +137,14 @@ Define domain standardebooks.test
|
|||
ProxySet connectiontimeout=5 timeout=240
|
||||
</Proxy>
|
||||
|
||||
# In RewriteCond, RewriteRule gets evaluated BEFORE RewriteCond, so $1 refers to the first
|
||||
# match in RewriteRule
|
||||
# Rewrite POST /some/url -> POST /some/url/post.php
|
||||
RewriteCond %{REQUEST_METHOD} ^POST$
|
||||
RewriteCond %{DOCUMENT_ROOT}/$1/ -d
|
||||
RewriteCond %{DOCUMENT_ROOT}/$1/post.php -f
|
||||
RewriteRule ^([^\.]+)$ $1/post.php [L]
|
||||
|
||||
# In case of 404, serve the 404 page specified by ErrorDocument, not the default FPM error page.
|
||||
# Note that we can't use `ProxyErrorOverride on` because that catches ALL 4xx and 5xx HTTP headers
|
||||
# and serves the default Apache page for them.
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
<li>
|
||||
<a href="/donate">Donate</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/settings">Settings</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/standardebooks">GitHub</a>
|
||||
</li>
|
||||
|
|
|
@ -16,6 +16,8 @@ if(!isset($manual)){
|
|||
$manual = false;
|
||||
}
|
||||
|
||||
$colorScheme = $_COOKIE['color-scheme'] ?? 'auto';
|
||||
|
||||
# We hash with crc32 because it's faster than md5 and "good enough" for this simple cache-busting use case
|
||||
|
||||
header('content-type: application/xhtml+xml');
|
||||
|
@ -28,8 +30,10 @@ print("\n");
|
|||
<title><? if($title != ''){ ?><?= Formatter::ToPlainText($title) ?> - <? } ?>Standard Ebooks: Free and liberated ebooks, carefully produced for the true book lover.</title>
|
||||
<? if($description != ''){ ?><meta content="<?= Formatter::ToPlainText($description) ?>" name="description"/><? } ?>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<link href="/css/reset.css" media="screen" rel="stylesheet" type="text/css"/>
|
||||
<link href="/css/core.css?version=<?= crc32(file_get_contents(WEB_ROOT . '/css/core.css')) ?>" media="screen" rel="stylesheet" type="text/css"/>
|
||||
<? if($colorScheme == 'auto' || $colorScheme == 'dark'){ ?>
|
||||
<link href="/css/dark.css?version=<?= crc32(file_get_contents(WEB_ROOT . '/css/dark.css')) ?>" media="screen<? if($colorScheme == 'auto'){ ?> and (prefers-color-scheme: dark)<? } ?>" rel="stylesheet" type="text/css"/>
|
||||
<? } ?>
|
||||
<? if($manual){ ?>
|
||||
<link href="/css/manual.css?version=<?= crc32(file_get_contents(WEB_ROOT . '/css/manual.css')) ?>" media="screen" rel="stylesheet" type="text/css"/>
|
||||
<? } ?>
|
||||
|
|
226
www/css/core.css
226
www/css/core.css
|
@ -95,22 +95,85 @@
|
|||
--link-highlight: var(--button);
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: dark){
|
||||
:root{
|
||||
--body-text: var(--dark-body-text);
|
||||
--header: var(--dark-header);
|
||||
--button: var(--dark-button);
|
||||
--button-highlight: var(--dark-button-highlight);
|
||||
--border: var(--dark-border);
|
||||
--sub-text: var(--dark-sub-text);
|
||||
--body-bg: var(--dark-body-bg);
|
||||
--input-hover: var(--dark-input-hover);
|
||||
--input-border: var(--dark-input-border);
|
||||
--input-outline: var(--dark-input-outline);
|
||||
--link-highlight: var(--button-highlight); /* lighter looks better in dark mode */
|
||||
}
|
||||
/* Start CSS reset */
|
||||
/* Dont @import this, to prevent FOUC */
|
||||
html{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a{
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
blockquote{
|
||||
margin: 0;
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ol{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h4{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h5{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h6{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
figure{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
q{
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner{
|
||||
border: 0;
|
||||
}
|
||||
/* End reset */
|
||||
|
||||
html{
|
||||
color: var(--body-text);
|
||||
font-family: "Crimson Pro", Georgia, serif;
|
||||
|
@ -539,6 +602,11 @@ form button{
|
|||
hyphens: none;
|
||||
}
|
||||
|
||||
form button{
|
||||
line-height: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.ebooks nav li.highlighted a:focus,
|
||||
a.button:focus,
|
||||
input[type="search"]:focus,
|
||||
|
@ -1480,6 +1548,10 @@ select[multiple] option:last-child{
|
|||
margin-bottom: 1rem; /* needed for firefox */
|
||||
}
|
||||
|
||||
form[action="/settings"]{
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
form[action="/ebooks"] label{
|
||||
max-width: 100%;
|
||||
}
|
||||
|
@ -1932,7 +2004,7 @@ article.ebook section aside.donation p::after{
|
|||
display: inline;
|
||||
}
|
||||
|
||||
footer ul li:nth-child(3)::after{
|
||||
footer ul li:nth-child(4)::after{
|
||||
content: "\A"; /* This is a line break */
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
|
@ -2051,6 +2123,24 @@ article.ebook section aside.donation p::after{
|
|||
main.ebooks > ol{
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
footer ul li:nth-child(2)::after{
|
||||
content: "\A"; /* This is a line break */
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
footer ul li:nth-child(4)::after{
|
||||
content: "\b7";
|
||||
white-space: normal;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
footer ul li:nth-child(5)::after{
|
||||
content: "\A"; /* This is a line break */
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 680px){
|
||||
|
@ -2242,10 +2332,16 @@ article.ebook section aside.donation p::after{
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
footer ul li:nth-child(5)::after{
|
||||
content: "\A"; /* This is a line break */
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
form[action="/settings"] button{
|
||||
display: block;
|
||||
margin-top: 1rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
form[action="/settings"] button,
|
||||
form[action="/settings"] span,
|
||||
form[action="/settings"] select{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2259,16 +2355,6 @@ article.ebook section aside.donation p::after{
|
|||
.masthead ol li img.contact{
|
||||
height: .75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 380px){
|
||||
main.front-page h1{
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6,code,.ebook h1 + p{
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
body > footer{
|
||||
padding-top: 0;
|
||||
|
@ -2282,6 +2368,16 @@ article.ebook section aside.donation p::after{
|
|||
footer ul li::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 380px){
|
||||
main.front-page h1{
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6,code,.ebook h1 + p{
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
main.ebooks > ol{
|
||||
grid-template-columns: 1fr;
|
||||
|
@ -2308,7 +2404,6 @@ article.ebook section aside.donation p::after{
|
|||
grid-row: 6;
|
||||
}
|
||||
|
||||
|
||||
body > header ul li:nth-child(2n)::after{
|
||||
display: none;
|
||||
}
|
||||
|
@ -2321,7 +2416,6 @@ article.ebook section aside.donation p::after{
|
|||
display: none;
|
||||
}
|
||||
|
||||
|
||||
body > header ul li:nth-child(2) ~ li,
|
||||
body > header ul li + li{
|
||||
margin-top: 1rem;
|
||||
|
@ -2341,73 +2435,3 @@ article.ebook section aside.donation p::after{
|
|||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: dark){
|
||||
|
||||
|
||||
main.front-page > section > section figure img{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
body > header > a:focus{
|
||||
/* Since we use invert() to change the color of the SE logo,
|
||||
we must specify the light outline (which is dark)
|
||||
so that it inverts to white */
|
||||
outline: 1px dashed var(--light-input-outline);
|
||||
}
|
||||
|
||||
article.ebook section#read-online a::before,
|
||||
article.ebook section#download ul li a[class]::before,
|
||||
article.ebook section#details ul li a[class]::before,
|
||||
footer p:last-child a::before,
|
||||
main.front-page > section > section figure.oss img + img,
|
||||
main.front-page > section > h2::before,
|
||||
main.front-page > section > h2::after{
|
||||
filter: invert() grayscale(100%) brightness(120%) drop-shadow(3px 3px 1px rgba(0, 0, 0, .25)); /* grayscale and brightness makes it hit about #eeeeee */
|
||||
}
|
||||
|
||||
.masthead img[src*="portrait.svg"],
|
||||
.masthead img.contact{
|
||||
filter: invert();
|
||||
}
|
||||
|
||||
.masthead img[src*="portrait.svg"]{
|
||||
border-color: var(--border-light);
|
||||
}
|
||||
|
||||
aside.donation,
|
||||
article.ebook section aside.donation{
|
||||
background: rgba(0, 0, 0, .25);
|
||||
}
|
||||
|
||||
aside.donation,
|
||||
article.ebook section aside.donation{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
select,
|
||||
input[type="search"]{
|
||||
box-shadow: 1px 1px 0 rgba(0, 0, 0, .5) inset;
|
||||
}
|
||||
|
||||
input::placeholder{
|
||||
color: rgba(255, 255, 255, .75);
|
||||
}
|
||||
|
||||
main.ebooks > ol img:hover{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
article.ebook #more-ebooks img:hover{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
label.select > span + span::after,
|
||||
label.search::before{
|
||||
text-shadow: 1px 1px 0 #000;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
text-shadow: 2px 2px 0 rgba(0, 0, 0, .75);
|
||||
}
|
||||
}
|
||||
|
|
79
www/css/dark.css
Normal file
79
www/css/dark.css
Normal file
|
@ -0,0 +1,79 @@
|
|||
:root{
|
||||
--body-text: var(--dark-body-text);
|
||||
--header: var(--dark-header);
|
||||
--button: var(--dark-button);
|
||||
--button-highlight: var(--dark-button-highlight);
|
||||
--border: var(--dark-border);
|
||||
--sub-text: var(--dark-sub-text);
|
||||
--body-bg: var(--dark-body-bg);
|
||||
--input-hover: var(--dark-input-hover);
|
||||
--input-border: var(--dark-input-border);
|
||||
--input-outline: var(--dark-input-outline);
|
||||
--link-highlight: var(--button-highlight); /* lighter looks better in dark mode */
|
||||
}
|
||||
|
||||
main.front-page > section > section figure img{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
body > header > a:focus{
|
||||
/* Since we use invert() to change the color of the SE logo,
|
||||
we must specify the light outline (which is dark)
|
||||
so that it inverts to white */
|
||||
outline: 1px dashed var(--light-input-outline);
|
||||
}
|
||||
|
||||
article.ebook section#read-online a::before,
|
||||
article.ebook section#download ul li a[class]::before,
|
||||
article.ebook section#details ul li a[class]::before,
|
||||
footer p:last-child a::before,
|
||||
main.front-page > section > section figure.oss img + img,
|
||||
main.front-page > section > h2::before,
|
||||
main.front-page > section > h2::after{
|
||||
filter: invert() grayscale(100%) brightness(120%) drop-shadow(3px 3px 1px rgba(0, 0, 0, .25)); /* grayscale and brightness makes it hit about #eeeeee */
|
||||
}
|
||||
|
||||
.masthead img[src*="portrait.svg"],
|
||||
.masthead img.contact{
|
||||
filter: invert();
|
||||
}
|
||||
|
||||
.masthead img[src*="portrait.svg"]{
|
||||
border-color: var(--border-light);
|
||||
}
|
||||
|
||||
aside.donation,
|
||||
article.ebook section aside.donation{
|
||||
background: rgba(0, 0, 0, .25);
|
||||
}
|
||||
|
||||
aside.donation,
|
||||
article.ebook section aside.donation{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
select,
|
||||
input[type="search"]{
|
||||
box-shadow: 1px 1px 0 rgba(0, 0, 0, .5) inset;
|
||||
}
|
||||
|
||||
input::placeholder{
|
||||
color: rgba(255, 255, 255, .75);
|
||||
}
|
||||
|
||||
main.ebooks > ol img:hover{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
article.ebook #more-ebooks img:hover{
|
||||
box-shadow: 3px 3px 1px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
label.select > span + span::after,
|
||||
label.search::before{
|
||||
text-shadow: 1px 1px 0 #000;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
text-shadow: 2px 2px 0 rgba(0, 0, 0, .75);
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/* Dont @import this, to prevent FOUC */
|
||||
html{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a{
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
blockquote{
|
||||
margin: 0;
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
p{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ol{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h4{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h5{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h6{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
q{
|
||||
quotes: none;
|
||||
}
|
||||
|
||||
figure{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner{
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ie 11 compatibility */
|
||||
header{
|
||||
display: block;
|
||||
}
|
||||
|
||||
nav{
|
||||
display: block;
|
||||
}
|
||||
|
||||
main{
|
||||
display: block;
|
||||
}
|
||||
|
||||
footer{
|
||||
display: block;
|
||||
}
|
||||
/* end ie 11 compatibility */
|
23
www/settings/index.php
Normal file
23
www/settings/index.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?
|
||||
require_once('Core.php');
|
||||
|
||||
$colorScheme = $_COOKIE['color-scheme'] ?? 'auto';
|
||||
|
||||
?><?= Template::Header(['title' => 'Website Settings', 'description' => 'Adjust your settings for viewing the Standard Ebooks website.']) ?>
|
||||
<main>
|
||||
<h1>Website Settings</h1>
|
||||
<form action="/settings" method="post">
|
||||
<label class="select">
|
||||
<span>Color scheme</span>
|
||||
<span>
|
||||
<select name="color-scheme">
|
||||
<option value="auto"<? if($colorScheme == 'auto'){ ?> selected="selected"<? } ?>>Automatic</option>
|
||||
<option value="light"<? if($colorScheme == 'light'){ ?> selected="selected"<? } ?>>Light</option>
|
||||
<option value="dark"<? if($colorScheme == 'dark'){ ?> selected="selected"<? } ?>>Dark</option>
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
<button>Apply</button>
|
||||
</form>
|
||||
</main>
|
||||
<?= Template::Footer() ?>
|
21
www/settings/post.php
Normal file
21
www/settings/post.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?
|
||||
require_once('Core.php');
|
||||
|
||||
$colorScheme = $_POST['color-scheme'] ?? 'auto';
|
||||
|
||||
if($colorScheme !== 'dark' && $colorScheme !== 'light' && $colorScheme !== 'auto'){
|
||||
$colorScheme = 'auto';
|
||||
}
|
||||
|
||||
if($colorScheme == 'auto'){
|
||||
// Delete the cookie; auto is the default
|
||||
setcookie('color-scheme', null, ['expires' => 0, 'path' => '/', 'secure' => true, 'httponly' => true]);
|
||||
}
|
||||
else{
|
||||
setcookie('color-scheme', $colorScheme, ['expires' => strtotime('+10 years'), 'path' => '/', 'secure' => true, 'httponly' => true]);
|
||||
}
|
||||
|
||||
// HTTP 303, See other
|
||||
http_response_code(303);
|
||||
header('Location: /settings');
|
||||
?>
|
Loading…
Add table
Add a link
Reference in a new issue