First commit

This commit is contained in:
Knah Tsaeb 2020-10-08 17:00:12 +02:00
parent b1e1f3e081
commit 47f0f2e90c
14 changed files with 1095 additions and 2 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
composer.lock
vendor/
content/*
!content/default.md

4
.htaccess Normal file
View file

@ -0,0 +1,4 @@
RewriteEngine On
RewriteCond $1 !^(css)
RewriteRule ^([^/]*)/([^/]*)$ /?dir=$1&file=$2 [L]
AddType text/css .css

View file

@ -1,3 +1,40 @@
# MyNoVi
# Welcome to MyNoVi
MyNovi | My Notes Viewer is simple markdown viewer made for my usage.
MyNovi | My Notes Viewer is simple markdown viewer made for my usage.
## Features
- No configuration
- Easy install
- Auto ToC (Table of Content)
- KISS
---
## Setup
Clone this Mynovi using git
`git clone https://forge.leslibres.org/Knah-Tsaeb/MyNoVi.git`
Use composer to install external lib
`cd MyNoVi`
`composer install`
---
## Usage
Put your markdown file in 'content' dir via FTP OR SSH.
That's all.
### Advanced usage
Use synchronisation tools like NextCloud. Sync 'content' dir with your desktop.
Now just edit your local file and when you save file, after synchro your file is online.
---
## License
This project is licensed under the terms of the **[AGPLv3](https://www.gnu.org/licenses/agpl-3.0.txt)** license.

64
apps/apps.php Normal file
View file

@ -0,0 +1,64 @@
<?php
/**
* Améliore la sortie print
*
* @author Tatane http://www.tatane.info/index.php/print_rn
* @author http://www.blog.cactuscrew.com/77-print_rn.html
* @param $data (array) tableau ou variable à examiner
* @param $name (string) nom a afficher
* @return false affiche les clef valeur du tableau $data
* @example n_print($array, 'Tableau de valeur');
*/
function n_print($data, $name = '')
{
$aBackTrace = debug_backtrace();
echo '<h2>', $name, '</h2>';
echo '<fieldset style="border: 1px solid orange; padding: 5px;color: #333; background-color: #fff;">';
echo '<legend style="border:1px solid orange;padding: 1px;background-color:#eee;color:orange;">', basename($aBackTrace[0]['file']), ' ligne => ', $aBackTrace[0]['line'], '</legend>';
echo '<pre>', htmlentities(print_r($data, 1)), '</pre>';
echo '</fieldset><br />';
}
function listDir()
{
$dirList = array();
foreach (glob("content/*", GLOB_ONLYDIR) as $dir) {
$dirList[basename($dir)] = listFile($dir);
}
return $dirList;
}
function listFile($dir)
{
$fileList = array();
foreach (glob($dir . "/*.md") as $dir) {
$fileList[] = str_replace('.md', '', basename($dir));
}
return $fileList;
}
function makeMenu($getDir = null)
{
$dirList = listDir();
$menu = '';
foreach ($dirList as $dir => $files) {
if ($getDir === $dir) {
$expand = 'open';
} else {
$expand = 'close';
}
$menu .= '
<details ' . $expand . '>
<summary>' . $dir . '</summary>
<ul>';
foreach ($files as $value) {
$menu .= '<li><a href="/' . urlencode($dir) . '/' . urlencode($value) . '">' . $value . '</a></li>';
}
$menu .= '
</ul>
</details>';
}
return $menu;
}

6
composer.json Normal file
View file

@ -0,0 +1,6 @@
{
"require": {
"erusev/parsedown": "^1.7",
"keinos/parsedown-toc": "dev-master"
}
}

40
content/default.md Normal file
View file

@ -0,0 +1,40 @@
# Welcome to MyNoVi
MyNovi | My Notes Viewer is simple markdown viewer made for my usage.
## Features
- No configuration
- Easy install
- Auto ToC (Table of Content)
- KISS
---
## Setup
Clone this Mynovi using git
`git clone https://forge.leslibres.org/Knah-Tsaeb/MyNoVi.git`
Use composer to install external lib
`cd MyNoVi`
`composer install`
---
## Usage
Put your markdown file in 'content' dir via FTP OR SSH.
That's all.
### Advanced usage
Use synchronisation tools like NextCloud. Sync 'content' dir with your desktop.
Now just edit your local file and when you save file, after synchro your file is online.
---
## License
This project is licensed under the terms of the **[AGPLv3](https://www.gnu.org/licenses/agpl-3.0.txt)** license.

800
css/light.css Normal file
View file

@ -0,0 +1,800 @@
/**
* Forced light theme version
*/
:root {
--background-body: #fff;
--background: #efefef;
--background-alt: #f7f7f7;
--selection: #9e9e9e;
--text-main: #363636;
--text-bright: #000;
--text-muted: #70777f;
--links: #0076d1;
--focus: #0096bfab;
--border: #dbdbdb;
--code: #000;
--animation-duration: 0.1s;
--button-hover: #ddd;
--scrollbar-thumb: rgb(213, 213, 213);
--scrollbar-thumb-hover: rgb(196, 196, 196);
--form-placeholder: #949494;
--form-text: #000;
--variable: #39a33c;
--highlight: #ff0;
--select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23161f27'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E");
}
html {
scrollbar-color: rgb(213, 213, 213) #fff;
scrollbar-color: var(--scrollbar-thumb) var(--background-body);
scrollbar-width: thin;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
line-height: 1.4;
max-width: 800px;
margin: 20px auto;
padding: 0 10px;
word-wrap: break-word;
color: #363636;
color: var(--text-main);
background: #fff;
background: var(--background-body);
text-rendering: optimizeLegibility;
}
button {
transition:
background-color 0.1s linear,
border-color 0.1s linear,
color 0.1s linear,
box-shadow 0.1s linear,
transform 0.1s ease;
transition:
background-color var(--animation-duration) linear,
border-color var(--animation-duration) linear,
color var(--animation-duration) linear,
box-shadow var(--animation-duration) linear,
transform var(--animation-duration) ease;
}
input {
transition:
background-color 0.1s linear,
border-color 0.1s linear,
color 0.1s linear,
box-shadow 0.1s linear,
transform 0.1s ease;
transition:
background-color var(--animation-duration) linear,
border-color var(--animation-duration) linear,
color var(--animation-duration) linear,
box-shadow var(--animation-duration) linear,
transform var(--animation-duration) ease;
}
textarea {
transition:
background-color 0.1s linear,
border-color 0.1s linear,
color 0.1s linear,
box-shadow 0.1s linear,
transform 0.1s ease;
transition:
background-color var(--animation-duration) linear,
border-color var(--animation-duration) linear,
color var(--animation-duration) linear,
box-shadow var(--animation-duration) linear,
transform var(--animation-duration) ease;
}
h1 {
font-size: 2.2em;
margin-top: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-bottom: 12px;
margin-top: 24px;
}
h1 {
color: #000;
color: var(--text-bright);
}
h2 {
color: #000;
color: var(--text-bright);
}
h3 {
color: #000;
color: var(--text-bright);
}
h4 {
color: #000;
color: var(--text-bright);
}
h5 {
color: #000;
color: var(--text-bright);
}
h6 {
color: #000;
color: var(--text-bright);
}
strong {
color: #000;
color: var(--text-bright);
}
h1,
h2,
h3,
h4,
h5,
h6,
b,
strong,
th {
font-weight: 600;
}
q::before {
content: none;
}
q::after {
content: none;
}
blockquote {
border-left: 4px solid #0096bfab;
border-left: 4px solid var(--focus);
margin: 1.5em 0;
padding: 0.5em 1em;
font-style: italic;
}
q {
border-left: 4px solid #0096bfab;
border-left: 4px solid var(--focus);
margin: 1.5em 0;
padding: 0.5em 1em;
font-style: italic;
}
blockquote > footer {
font-style: normal;
border: 0;
}
blockquote cite {
font-style: normal;
}
address {
font-style: normal;
}
a[href^='mailto\:']::before {
content: '📧 ';
}
a[href^='tel\:']::before {
content: '📞 ';
}
a[href^='sms\:']::before {
content: '💬 ';
}
mark {
background-color: #ff0;
background-color: var(--highlight);
border-radius: 2px;
padding: 0 2px 0 2px;
color: #000;
}
button,
select,
input[type='submit'],
input[type='button'],
input[type='checkbox'],
input[type='range'],
input[type='radio'] {
cursor: pointer;
}
input:not([type='checkbox']):not([type='radio']),
select {
display: block;
}
input {
color: #000;
color: var(--form-text);
background-color: #efefef;
background-color: var(--background);
font-family: inherit;
font-size: inherit;
margin-right: 6px;
margin-bottom: 6px;
padding: 10px;
border: none;
border-radius: 6px;
outline: none;
}
button {
color: #000;
color: var(--form-text);
background-color: #efefef;
background-color: var(--background);
font-family: inherit;
font-size: inherit;
margin-right: 6px;
margin-bottom: 6px;
padding: 10px;
border: none;
border-radius: 6px;
outline: none;
}
textarea {
color: #000;
color: var(--form-text);
background-color: #efefef;
background-color: var(--background);
font-family: inherit;
font-size: inherit;
margin-right: 6px;
margin-bottom: 6px;
padding: 10px;
border: none;
border-radius: 6px;
outline: none;
}
select {
color: #000;
color: var(--form-text);
background-color: #efefef;
background-color: var(--background);
font-family: inherit;
font-size: inherit;
margin-right: 6px;
margin-bottom: 6px;
padding: 10px;
border: none;
border-radius: 6px;
outline: none;
}
input[type='checkbox'],
input[type='radio'] {
height: 1em;
width: 1em;
}
input[type='radio'] {
border-radius: 100%;
}
input {
vertical-align: top;
}
label {
vertical-align: middle;
margin-bottom: 4px;
display: inline-block;
}
input:not([type='checkbox']):not([type='radio']),
input[type='range'],
select,
button,
textarea {
-webkit-appearance: none;
}
textarea {
display: block;
margin-right: 0;
box-sizing: border-box;
resize: vertical;
}
textarea:not([cols]) {
width: 100%;
}
textarea:not([rows]) {
min-height: 40px;
height: 140px;
}
select {
background: #efefef url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23161f27'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat;
background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat;
padding-right: 35px;
}
select::-ms-expand {
display: none;
}
select[multiple] {
padding-right: 10px;
background-image: none;
overflow-y: auto;
}
button,
input[type='submit'],
input[type='button'] {
padding-right: 30px;
padding-left: 30px;
}
button:hover {
background: #ddd;
background: var(--button-hover);
}
input[type='submit']:hover {
background: #ddd;
background: var(--button-hover);
}
input[type='button']:hover {
background: #ddd;
background: var(--button-hover);
}
input:focus {
box-shadow: 0 0 0 2px #0096bfab;
box-shadow: 0 0 0 2px var(--focus);
}
select:focus {
box-shadow: 0 0 0 2px #0096bfab;
box-shadow: 0 0 0 2px var(--focus);
}
button:focus {
box-shadow: 0 0 0 2px #0096bfab;
box-shadow: 0 0 0 2px var(--focus);
}
textarea:focus {
box-shadow: 0 0 0 2px #0096bfab;
box-shadow: 0 0 0 2px var(--focus);
}
input[type='checkbox']:active,
input[type='radio']:active,
input[type='submit']:active,
input[type='button']:active,
input[type='range']:active,
button:active {
transform: translateY(2px);
}
input:disabled,
select:disabled,
button:disabled,
textarea:disabled {
cursor: not-allowed;
opacity: 0.5;
}
::-moz-placeholder {
color: #949494;
color: var(--form-placeholder);
}
:-ms-input-placeholder {
color: #949494;
color: var(--form-placeholder);
}
::-ms-input-placeholder {
color: #949494;
color: var(--form-placeholder);
}
::placeholder {
color: #949494;
color: var(--form-placeholder);
}
fieldset {
border: 1px #0096bfab solid;
border: 1px var(--focus) solid;
border-radius: 6px;
margin: 0;
margin-bottom: 12px;
padding: 10px;
}
legend {
font-size: 0.9em;
font-weight: 600;
}
input[type='range'] {
margin: 10px 0;
padding: 10px 0;
background: transparent;
}
input[type='range']:focus {
outline: none;
}
input[type='range']::-webkit-slider-runnable-track {
width: 100%;
height: 9.5px;
-webkit-transition: 0.2s;
transition: 0.2s;
background: #efefef;
background: var(--background);
border-radius: 3px;
}
input[type='range']::-webkit-slider-thumb {
box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d;
height: 20px;
width: 20px;
border-radius: 50%;
background: #dbdbdb;
background: var(--border);
-webkit-appearance: none;
margin-top: -7px;
}
input[type='range']:focus::-webkit-slider-runnable-track {
background: #efefef;
background: var(--background);
}
input[type='range']::-moz-range-track {
width: 100%;
height: 9.5px;
-moz-transition: 0.2s;
transition: 0.2s;
background: #efefef;
background: var(--background);
border-radius: 3px;
}
input[type='range']::-moz-range-thumb {
box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
height: 20px;
width: 20px;
border-radius: 50%;
background: #dbdbdb;
background: var(--border);
}
input[type='range']::-ms-track {
width: 100%;
height: 9.5px;
background: transparent;
border-color: transparent;
border-width: 16px 0;
color: transparent;
}
input[type='range']::-ms-fill-lower {
background: #efefef;
background: var(--background);
border: 0.2px solid #010101;
border-radius: 3px;
box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
}
input[type='range']::-ms-fill-upper {
background: #efefef;
background: var(--background);
border: 0.2px solid #010101;
border-radius: 3px;
box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
}
input[type='range']::-ms-thumb {
box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
border: 1px solid #000;
height: 20px;
width: 20px;
border-radius: 50%;
background: #dbdbdb;
background: var(--border);
}
input[type='range']:focus::-ms-fill-lower {
background: #efefef;
background: var(--background);
}
input[type='range']:focus::-ms-fill-upper {
background: #efefef;
background: var(--background);
}
a {
text-decoration: none;
color: #0076d1;
color: var(--links);
}
a:hover {
text-decoration: underline;
}
code {
background: #efefef;
background: var(--background);
color: #000;
color: var(--code);
padding: 2.5px 5px;
border-radius: 6px;
font-size: 1em;
}
samp {
background: #efefef;
background: var(--background);
color: #000;
color: var(--code);
padding: 2.5px 5px;
border-radius: 6px;
font-size: 1em;
}
time {
background: #efefef;
background: var(--background);
color: #000;
color: var(--code);
padding: 2.5px 5px;
border-radius: 6px;
font-size: 1em;
}
pre > code {
padding: 10px;
display: block;
overflow-x: auto;
}
var {
color: #39a33c;
color: var(--variable);
font-style: normal;
font-family: monospace;
}
kbd {
background: #efefef;
background: var(--background);
border: 1px solid #dbdbdb;
border: 1px solid var(--border);
border-radius: 2px;
color: #363636;
color: var(--text-main);
padding: 2px 4px 2px 4px;
}
img,
video {
max-width: 100%;
height: auto;
}
hr {
border: none;
border-top: 1px solid #dbdbdb;
border-top: 1px solid var(--border);
}
table {
border-collapse: collapse;
margin-bottom: 10px;
width: 100%;
table-layout: fixed;
}
table caption {
text-align: left;
}
td,
th {
padding: 6px;
text-align: left;
vertical-align: top;
word-wrap: break-word;
}
thead {
border-bottom: 1px solid #dbdbdb;
border-bottom: 1px solid var(--border);
}
tfoot {
border-top: 1px solid #dbdbdb;
border-top: 1px solid var(--border);
}
tbody tr:nth-child(even) {
background-color: #f7f7f7;
background-color: var(--background-alt);
}
::-webkit-scrollbar {
height: 10px;
width: 10px;
}
::-webkit-scrollbar-track {
background: #efefef;
background: var(--background);
border-radius: 6px;
}
::-webkit-scrollbar-thumb {
background: rgb(213, 213, 213);
background: var(--scrollbar-thumb);
border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover {
background: rgb(196, 196, 196);
background: var(--scrollbar-thumb-hover);
}
::-moz-selection {
background-color: #9e9e9e;
background-color: var(--selection);
color: #000;
color: var(--text-bright);
}
::selection {
background-color: #9e9e9e;
background-color: var(--selection);
color: #000;
color: var(--text-bright);
}
details {
display: flex;
flex-direction: column;
align-items: flex-start;
background-color: #f7f7f7;
background-color: var(--background-alt);
padding: 10px 10px 0;
margin: 1em 0;
border-radius: 6px;
overflow: hidden;
}
details[open] {
padding: 10px;
}
details > :last-child {
margin-bottom: 0;
}
details[open] summary {
margin-bottom: 10px;
}
summary {
display: list-item;
background-color: #efefef;
background-color: var(--background);
padding: 10px;
margin: -10px -10px 0;
cursor: pointer;
outline: none;
}
summary:hover,
summary:focus {
text-decoration: underline;
}
details > :not(summary) {
margin-top: 0;
}
summary::-webkit-details-marker {
color: #363636;
color: var(--text-main);
}
footer {
border-top: 1px solid #dbdbdb;
border-top: 1px solid var(--border);
padding-top: 10px;
color: #70777f;
color: var(--text-muted);
}
body > footer {
margin-top: 40px;
}
@media print {
body,
pre,
code,
summary,
details,
button,
input,
textarea {
background-color: #fff;
}
button,
input,
textarea {
border: 1px solid #000;
}
body,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
code,
button,
input,
textarea,
footer,
summary,
strong {
color: #000;
}
summary::marker {
color: #000;
}
summary::-webkit-details-marker {
color: #000;
}
tbody tr:nth-child(even) {
background-color: #f2f2f2;
}
a {
color: #00f;
text-decoration: underline;
}
}
/*# sourceMappingURL=light.css.map */

42
css/main.css Normal file
View file

@ -0,0 +1,42 @@
@media (min-width: 540px) {
body {
display: grid;
grid-template-columns: 20% 1fr 20%;
gap: 0em 1em;
grid-template-areas:
"menu main toc"
"footer footer footer";
}
.toc>* {
position: fixed;
}
}
body {
max-width: 1000px;
}
.menu {
grid-area: menu;
font-size: .9rem;
}
.main {
grid-area: main;
}
.toc {
grid-area: toc;
font-size: .9rem;
}
.toc ul {
padding: 0 0 0 1em;
}
.footer {
grid-area: footer;
margin: .9rem 0;
}

17
humans.txt Normal file
View file

@ -0,0 +1,17 @@
/* TEAM */
Chef:Juanjo Bernabeu
Contact: Knah-Tsaeb_mynovi [at] knah-tsaeb.org
/* DEV */
OS: ArchLinux
IDE: Code
OTHER: GIT
/* TECHNOLOGY */
PHP
HTML5
CSS Water.css https://watercss.netlify.app/
Parsedown http://parsedown.org
Parsedown ToC https://github.com/KEINOS/parsedown-extension_table-of-contents

40
index.php Normal file
View file

@ -0,0 +1,40 @@
<?php
require 'vendor/autoload.php';
require 'apps/apps.php';
$dir = $_GET['dir'] ?? '';
$file = $_GET['file'] ?? '';
if (!empty($dir)) {
$dir = filter_input(INPUT_GET, 'dir', FILTER_SANITIZE_STRING);
}
if (isset($file)) {
$file = filter_input(INPUT_GET, 'file', FILTER_SANITIZE_STRING);
}
if (empty($file) || !file_exists('content/' . urldecode($dir) . '/' . urldecode($file) . '.md')) {
$dir = '';
if(file_exists('content/index.md')){
$file = 'index';
} else {
$file = 'default';
}
}
$Parsedown = new ParsedownToc();
$content = file_get_contents('content/' . urldecode($dir) . '/' . urldecode($file) . '.md');
$Parsedown = new ParsedownToc();
$body = $Parsedown->text($content);
$toc = $Parsedown->contentsList();
$body = str_replace("[ ]", '<input type="checkbox" disabled>', $body);
$body = str_replace("[x]", '<input type="checkbox" checked disabled>', $body);
require 'tpl/header.html';
require 'tpl/aside.html';
require 'tpl/main.html';
require 'tpl/footer.html';

8
tpl/aside.html Normal file
View file

@ -0,0 +1,8 @@
<aside class="menu">
<nav role="navigation">
<h1>MyNoVi</h1>
<p>
<?php echo makeMenu($dir); ?>
</p>
</nav>
</aside>

9
tpl/footer.html Normal file
View file

@ -0,0 +1,9 @@
<footer class="footer">
<div>
<hr>
<a href="https://forge.leslibres.org/Knah-Tsaeb/MyNoVi">MyNoVi</a> is under <a href="/LICENSE">AGPLv3</a> | Made in 2020 by Knah Tsaeb
</div>
</footer>
</body>
</html>

16
tpl/header.html Normal file
View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MyNoVi</title>
<link rel="author" href="humans.txt" />
<link rel="stylesheet" href="/css/light.css" />
<link rel="stylesheet" href="/css/main.css" />
<link rel="icon" href="/images/favicon.png" />
</head>
<body>

6
tpl/main.html Normal file
View file

@ -0,0 +1,6 @@
<aside class="toc">
<?php echo $toc;?>
</aside>
<main role="main" class="main">
<?php echo $body;?>
</main>