Init Void project

This commit is contained in:
2024-11-29 19:52:52 +01:00
commit 5fb1e058cd
17 changed files with 1806 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
github: [josephernest]
custom: https://afewthingz.com

7
.htaccess Normal file
View File

@@ -0,0 +1,7 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
RewriteRule \.txt$ index.php [L]
</IfModule>

19
LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2014 Joseph Ernest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

1528
Parsedown.php Normal file

File diff suppressed because it is too large Load Diff

59
README.md Normal file
View File

@@ -0,0 +1,59 @@
# Low-Tech Lab - Grenoble
## Local Development
```bash
# Start a PHP server
php -S localhost:8000
```
Void
====
**Void** is a website creation tool. Just static pages or blog articles? Both are possible with [Void](https://gget.it/void).
The core is done in a single PHP file of less than 100 lines of code. Huh, this is bad? See the discussion [here](https://gget.it/void/article/03).
What about performance? See [here](https://gget.it/void/article/05-perf).
Screenshot
----
[![screenshot](https://gget.it/9p7avesy/1.jpg)](https://gget.it/void/demo/)
About
----
Author: Joseph Ernest ([@JosephErnest](https:/twitter.com/JosephErnest))
Sponsors and consulting
----
I am available for Python, Data science, ML, Automation consulting. Please contact me on https://afewthingz.com for freelancing requests.
Do you want to support the development of my open-source projects? Please contact me!
I am currently sponsored by [CodeSigningStore.com](https://codesigningstore.com/). Thank you to them for providing a DigiCert Code Signing Certificate and supporting open source software.
Credit
----
**Void** uses the [Parsedown](https://github.com/erusev/parsedown) library, licensed under MIT license.
License
----
MIT license
FAQ
----
**Question: How to add automatic code highlighting in articles / pages?**
Use the library `highlight.js` by adding these three lines in the `<header>` part of `index.php`:
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.5/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.5/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
**Question: How to count the number of unique visitors per day (analytics)?**
[See this blog article](https://gget.it/void/article/simpleanalytics).

7
article/01.txt Normal file
View File

@@ -0,0 +1,7 @@
TITLE:First article
DATE:2015 April 9th
AUTHOR:Jo
It's very simple to remove this useless article. Just delete the file `/article/01.txt` and that's it.
![](http://gget.it/l8d61dbv/Photo06_4-001.jpg)

20
article/02-tech.txt Normal file
View File

@@ -0,0 +1,20 @@
TITLE:A technical article
DATE:2015 April 9th
AUTHOR:Jo
This Python code is really good:
def good():
a = 1
b = 2
c = a + b
return None
This one is *even better:*
def better():
a = 128
b = 256
c = a * b
return None

View File

@@ -0,0 +1,12 @@
TITLE:A new article
DATE:2015 April 10th
URL:coolarticle
AUTHOR:Jo
This is a sample blog article. What to do now?
* write a new article,
* listen to [some music](http://soundcloud.com/shura/sets/shura-just-once),
* or do something else?
![](http://gget.it/hm8jobmp/tumblr_ltjcmgHCkz1r0mxp5.jpg)

BIN
assets/brand.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

86
index.php Normal file
View File

@@ -0,0 +1,86 @@
<?php
$sitename = "SomeWebsite";
$blogpagename = "blog";
error_reporting(0);
function getpage($page)
{
$pagestr = file_get_contents($page);
list($pageheader, $pagecontent) = preg_split('~(?:\r?\n){2}~', $pagestr, 2); // split into 2 parts : before/after the first blank line
preg_match("/^TITLE:(.*)$/m", $pageheader, $matches1); // for articles: title // for pages: title displayed in top-menu
preg_match("/^AUTHOR:(.*)$/m", $pageheader, $matches2); // for articles only
preg_match("/^DATE:(.*)$/m", $pageheader, $matches3); // for articles only
preg_match("/^(NOMENU:1)$/m", $pageheader, $matches4); // for pages only: if NOMENU:1, no link in top-menu
preg_match("/^URL:(.*)$/m", $pageheader, $matches5); // for articles: article's link ; for pages: top-menu's link
return array($pagecontent, $matches1[1], trim($matches2[1]), $matches3[1], $matches4[1], trim($matches5[1]));
}
$siteroot = substr($_SERVER['PHP_SELF'], 0, - strlen(basename($_SERVER['PHP_SELF']))); // must have trailing slash, we don't use dirname because it can produce antislash on Windows
$requestedpage = basename(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
if (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) === $siteroot) { $requestedpage = ""; } // check if homepage
$type = strpos($_SERVER['REQUEST_URI'], 'article/') ? 'article' : 'page';
$pages = glob("./" . $type ."/*$requestedpage.{txt,md}", GLOB_BRACE);
if ($pages) { $page = $pages[0]; } else { $page = "./page/HIDDEN-404.txt"; $type = 'page'; } // default 404 error page
list($pagecontent, $pagetitle, $pageauthor, $pagedate, $pagenomenu, $pageurl) = getpage($page);
if (!$pageurl) { $pageurl = pathinfo($page)['filename']; }
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo (trim($pagetitle) ? "$sitename - $pagetitle" : "$sitename")?></title>
<base href="<?php echo htmlspecialchars($siteroot, ENT_QUOTES, 'UTF-8'); ?>">
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
<div class="header">
<div class="logo"><a href="."><?php echo $sitename;?></a></div>
<ul class="menu">
<?php
$pages = glob("./page/*.{txt,md}", GLOB_BRACE);
foreach($pages as $page)
{
list($menupagecontent, $menupagetitle, $menupageauthor, $menupagedate, $menupagenomenu, $menupageurl) = getpage($page);
if (!$menupagenomenu) { echo "<li><a href=\"" . ($menupageurl ? $menupageurl : strtolower($menupagetitle)) . "\">$menupagetitle</a></li>"; }
}
?>
</ul>
</div>
<div class="main">
<?php
require 'Parsedown.php';
if ($type === "article")
{
echo "<div class=\"article\"><a href=\"article/$pageurl\"><h2 class=\"articletitle\">$pagetitle</h2><div class=\"articleinfo\">by $pageauthor, on $pagedate</div></a>";
echo (new Parsedown())->text($pagecontent);
echo "</div>";
}
else if ($type === "page") { echo "<div class=\"page\">" . (new Parsedown())->text($pagecontent) . "</div>"; }
if ($requestedpage === $blogpagename)
{
$pages = array_slice(array_reverse(glob("./article/*.{txt,md}", GLOB_BRACE)), $_GET['start'], 10);
foreach($pages as $page)
{
list($pagecontent, $pagetitle, $pageauthor, $pagedate, $pagenomenu, $pageurl) = getpage($page);
if (!$pageurl) { $pageurl = pathinfo($page)['filename']; }
echo "<div class=\"article\"><a href=\"article/$pageurl\"><h2 class=\"articletitle\">$pagetitle</h2><div class=\"articleinfo\">by $pageauthor, on $pagedate</div></a>";
echo (new Parsedown())->text($pagecontent);
echo "</div>";
}
if ($_GET['start'] > 0) { echo "<a href=\"" . $blogpagename . (($_GET['start'] > 10) ? "?start=" . ($_GET['start'] - 10) : "") . "\">Newer articles</a>&nbsp; "; }
if (count(array_slice(array_reverse(glob("./article/*.{txt,md}", GLOB_BRACE)), $_GET['start'], 11)) > 10) { echo "<a href=\"" . $blogpagename . "?start=" . ($_GET['start'] + 10) . "\">Older articles</a>"; }
}
?>
</div>
<div class="footer">
<div class="left"><a href="">© <?php echo date('Y') . " " . $sitename; ?></a></div>
<div class="right">Powered by <a href="https://github.com/josephernest/void">Void</a>.</div>
</div>
</body>
</html>

6
page/01-home.txt Normal file
View File

@@ -0,0 +1,6 @@
TITLE:Home
NOMENU:1
This is a demo website powered by [Void](http://thisisvoid.org).
![](http://gget.it/mspjlhh3/P1170225.JPG)

7
page/02-about.txt Normal file
View File

@@ -0,0 +1,7 @@
TITLE:About
#About
**SomeWebsite** is a great website.
Do you want to get the latest news? The [blog](blog) is here!

2
page/03-contact.txt Normal file
View File

@@ -0,0 +1,2 @@
TITLE:Contact
URL:mailto:contact@somewebsi.te

3
page/04-blog.txt Normal file
View File

@@ -0,0 +1,3 @@
TITLE:Blog
#Blog

7
page/HIDDEN-404.txt Normal file
View File

@@ -0,0 +1,7 @@
NOMENU:1
#Page not found
Are you sure you entered the URL correctly?
Return to [home page](.).

41
style.css Normal file
View File

@@ -0,0 +1,41 @@
.header { margin-bottom: 1.5em; padding-bottom: 1em; min-height: 3.1em; border-bottom: 2px solid #2980b9; }
.header a:hover, .footer a:hover { border: none; }
.header:after { content: ''; clear: both; display: block; }
.logo { float: left; margin-top: 0.3em; }
.logo a { background-color: #2980b9; color: white; padding: 0.2em 0.2em; font-size: 1.4em; }
.logo a:hover { color: white; }
.menu { float: right; padding: 0; margin: 0; }
.menu li { display: inline-block; padding: 0.4em 0 0.4em 2em; }
.menu a { font-weight: 600; }
.main { min-height: 18em; padding-bottom: 3em; border-bottom: 2px solid #2980b9; }
.main a { border-bottom: 2px solid #D1D1D1; }
.main p, .main ul { margin-top: 0; margin-bottom: 0.5em; }
.page { font-size: 0.95em; }
.article { margin-bottom: 4em; font-size: 0.9em; line-height: 1.4em; }
.articleinfo { color: #AAA; margin-bottom: 1em; font-size: 0.9em; }
.articletitle { margin-bottom: 0; }
.footer { padding: 1em 0 2em; font-size: .75em; color: #333; }
.footer .left { float: left; }
.footer .right { float: right; }
* { margin: 0; }
html { height: 100%; font-family: sans-serif; font-size: 1.25em; }
body { margin: 0 auto; padding: 3em 3em 1em 3em; max-width: 44em; line-height: 1.5em; color: #333; }
a { color: black; text-decoration: none; transition: color .2s, background .2s, border .2s; }
a:hover { border-bottom: 2px solid black; color: #2980b9; }
img { max-width: 100%; }
h1 { font-size: 2em; font-weight: 300; margin-bottom: .5em; line-height: 1.25em; color: #2980b9; }
h2 { font-size: 1.95em; font-weight: 300; margin-bottom: .5em; line-height: 1.25em; }
h3 { font-size: 1.4em; font-weight: 400; margin-bottom: .5em; line-height: 1.25em; }
h4 { font-size: 1.2em; font-weight: 600; margin-bottom: .5em; line-height: 1.25em; }
blockquote { background: none; border-left: 3px solid #777; color: #777; padding: 0 0 0 10px; margin-left: 1.2em; }
hr { margin: 2em 0; height: 2px; background-color: #D1D1D1; border: none; }
pre { background-color: #F1F1F1; margin-bottom: 0.7em; line-height: 1.5em; }
@media (max-width: 640px) {
body { padding: 1.25em; }
.header { padding-bottom: 0; }
.logo { float:none; }
.menu { float:none; margin-top: 2em; }
.menu li { display: block; padding: 0.2em 0; margin: 0.2em; border-top: 1px solid #D1D1D1; }
}