diff --git a/classes/handler/ArticlesHandler.php b/classes/handler/ArticlesHandler.php
new file mode 100644
index 0000000..3d78979
--- /dev/null
+++ b/classes/handler/ArticlesHandler.php
@@ -0,0 +1,19 @@
+skin->title = \LangData::getInstance()['articles'];
+ return $this->skin->renderPage('main/articles',
+ posts: $posts);
+ }
+}
\ No newline at end of file
diff --git a/classes/handler/IndexHandler.php b/classes/handler/IndexHandler.php
index e470f4a..81bddf6 100644
--- a/classes/handler/IndexHandler.php
+++ b/classes/handler/IndexHandler.php
@@ -8,11 +8,16 @@ use posts;
class IndexHandler extends \RequestHandler {
public function get(): \Response {
- $page = \pages::getPageByName('index-wgm9Fkl');
+ global $config;
+
+ $page = \pages::getPageByName($config['index_page_id']);
$this->skin->title = $page->title;
$this->skin->fixedTitle = true;
- return $this->skin->renderPage('main/index',
- unsafe_content: $page->getHtml($this->isRetina(), \themes::getUserTheme()));
+ return $this->skin->renderPage('main/page',
+ unsafe_html: $page->getHtml($this->isRetina(), \themes::getUserTheme()),
+ page_url: $page->getUrl(),
+ short_name: $page->shortName);
}
-}
\ No newline at end of file
+}
+
diff --git a/classes/handler/admin/IndexHandler.php b/classes/handler/admin/IndexHandler.php
index e177edf..78531bd 100644
--- a/classes/handler/admin/IndexHandler.php
+++ b/classes/handler/admin/IndexHandler.php
@@ -7,6 +7,7 @@ use Response;
class IndexHandler extends AdminRequestHandler {
public function get(): Response {
+ $this->skin->title = 'Admin';
return $this->skin->renderPage('admin/index');
}
diff --git a/classes/handler/admin/UploadDeleteHandler.php b/classes/handler/admin/UploadDeleteHandler.php
index 63cb7e2..a0508ed 100644
--- a/classes/handler/admin/UploadDeleteHandler.php
+++ b/classes/handler/admin/UploadDeleteHandler.php
@@ -13,13 +13,13 @@ class UploadDeleteHandler extends AdminRequestHandler {
$upload = \uploads::get($id);
if (!$upload)
- return new RedirectResponse('/uploads/?error='.urlencode('upload not found'));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('upload not found'));
csrf::check('delupl'.$id);
\uploads::delete($id);
- return new RedirectResponse('/uploads/');
+ return new RedirectResponse('/admin/uploads/');
}
}
\ No newline at end of file
diff --git a/classes/handler/admin/UploadEditNoteHandler.php b/classes/handler/admin/UploadEditNoteHandler.php
index 020aca3..fe7c360 100644
--- a/classes/handler/admin/UploadEditNoteHandler.php
+++ b/classes/handler/admin/UploadEditNoteHandler.php
@@ -12,14 +12,14 @@ class UploadEditNoteHandler extends AdminRequestHandler {
$upload = \uploads::get($id);
if (!$upload)
- return new \RedirectResponse('/uploads/?error='.urlencode('upload not found'));
+ return new \RedirectResponse('/admin/uploads/?error='.urlencode('upload not found'));
csrf::check('editupl'.$id);
$note = $_POST['note'] ?? '';
$upload->setNote($note);
- return new \RedirectResponse('/uploads/');
+ return new \RedirectResponse('/admin/uploads/');
}
}
\ No newline at end of file
diff --git a/classes/handler/admin/UploadsHandler.php b/classes/handler/admin/UploadsHandler.php
index da6b015..2360c27 100644
--- a/classes/handler/admin/UploadsHandler.php
+++ b/classes/handler/admin/UploadsHandler.php
@@ -29,7 +29,7 @@ class UploadsHandler extends AdminRequestHandler {
list($custom_name, $note) = $this->input('name, note');
if (!isset($_FILES['files']))
- return new RedirectResponse('/uploads/?error='.urlencode('no file'));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('no file'));
$files = [];
for ($i = 0; $i < count($_FILES['files']['name']); $i++) {
@@ -49,14 +49,14 @@ class UploadsHandler extends AdminRequestHandler {
foreach ($files as $f) {
if ($f['error'])
- return new RedirectResponse('/uploads/?error='.urlencode('error code '.$f['error']));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('error code '.$f['error']));
if (!$f['size'])
- return new RedirectResponse('/uploads/?error='.urlencode('received empty file'));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('received empty file'));
$ext = extension($f['name']);
if (!\uploads::isExtensionAllowed($ext))
- return new RedirectResponse('/uploads/?error='.urlencode('extension not allowed'));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('extension not allowed'));
$upload_id = \uploads::add(
$f['tmp_name'],
@@ -64,10 +64,10 @@ class UploadsHandler extends AdminRequestHandler {
$note);
if (!$upload_id)
- return new RedirectResponse('/uploads/?error='.urlencode('failed to create upload'));
+ return new RedirectResponse('/admin/uploads/?error='.urlencode('failed to create upload'));
}
- return new RedirectResponse('/uploads/');
+ return new RedirectResponse('/admin/uploads/');
}
}
\ No newline at end of file
diff --git a/classes/markup.php b/classes/markup.php
index f6ddd0f..d3c8e68 100644
--- a/classes/markup.php
+++ b/classes/markup.php
@@ -33,7 +33,7 @@ class markup {
global $config;
$is_dark_theme = $user_theme === 'dark';
return preg_replace_callback(
- '/('.preg_quote($config['uploads_host'], '/').'\/\w{8}\/)([ap])(\d+)x(\d+)(\.jpg)/',
+ '/(uploads\/\w{8}\/)([ap])(\d+)x(\d+)(\.jpg)/',
function($match) use ($is_retina, $is_dark_theme) {
$mult = $is_retina ? 2 : 1;
$is_alpha = $match[2] == 'a';
diff --git a/classes/model/Upload.php b/classes/model/Upload.php
index 782159e..a924326 100644
--- a/classes/model/Upload.php
+++ b/classes/model/Upload.php
@@ -1,7 +1,6 @@
randomId.'/'.$this->name;
+ return $config['uploads_path'].'/'.$this->randomId.'/'.$this->name;
}
public function getDirectPreviewUrl(int $w, int $h, bool $retina = false): string {
@@ -44,11 +43,11 @@ class Upload extends Model
}
$prefix = $this->imageMayHaveAlphaChannel() ? 'a' : 'p';
- return 'https://'.$config['uploads_host'].'/'.$this->randomId.'/'.$prefix.$w.'x'.$h.'.jpg';
+ return $config['uploads_path'].'/'.$this->randomId.'/'.$prefix.$w.'x'.$h.'.jpg';
}
// TODO remove?
- public function incrementDownloads() {
+ public function incrementDownloads(): void {
$db = getDb();
$db->query("UPDATE uploads SET downloads=downloads+1 WHERE id=?", $this->id);
$this->downloads++;
@@ -70,7 +69,7 @@ class Upload extends Model
return $md;
}
- public function setNote(string $note) {
+ public function setNote(string $note): void {
$db = getDb();
$db->query("UPDATE uploads SET note=? WHERE id=?", $note, $this->id);
}
diff --git a/classes/uploads.php b/classes/uploads.php
index 81a16f3..cd76d1e 100644
--- a/classes/uploads.php
+++ b/classes/uploads.php
@@ -82,7 +82,7 @@ class uploads {
public static function getAll(): array {
$db = getDb();
$q = $db->query("SELECT * FROM uploads ORDER BY id DESC");
- return array_map('\Upload', $db->fetchAll($q));
+ return array_map('model\Upload::create_instance', $db->fetchAll($q));
}
public static function get(int $id): ?Upload {
diff --git a/config.php b/config.php
index b1f1244..ff58284 100644
--- a/config.php
+++ b/config.php
@@ -18,10 +18,10 @@ return [
'password_salt' => '12345',
'csrf_token' => '12345',
'uploads_dir' => '/home/user/files.example.com',
- 'uploads_host' => 'files.example.com',
'dirs_mode' => 0775,
'files_mode' => 0664,
'group' => 33, // id -g www-data
'is_dev' => false,
+ 'index_page_id' => 'index-wgm9Fkl'
];
diff --git a/htdocs/index.php b/htdocs/index.php
index da5850e..fa8b6cb 100644
--- a/htdocs/index.php
+++ b/htdocs/index.php
@@ -6,20 +6,20 @@ $r = (new Router())
// route handler input
// ----- ------- -----
->add('/', 'index')
- ->add('([a-zA-Z0-9\-]+)/', 'auto name=$(1)')
-
+ ->add('([a-zA-Z0-9\-]+)/', 'auto name=$(1)')
->add('feed.rss', 'RSS')
+ //->add('articles/', 'articles')
+ ->add('articles/write/', 'admin/post_add')
+ // admin
->add('admin/', 'admin/index')
->add('admin/{login,logout,log}/', 'admin/${1}')
-
- ->add('([a-zA-Z0-9\-]+)/{delete,edit}/', 'admin/auto_${1} short_name=$(1)')
- ->add('([a-zA-Z0-9\-]+)/create/', 'admin/page_add short_name=$(1)')
- //->add('write/', 'admin/post_add')
+ ->add('([a-zA-Z0-9\-]+)/{delete,edit}/', 'admin/auto_${1} short_name=$(1)')
+ ->add('([a-zA-Z0-9\-]+)/create/', 'admin/page_add short_name=$(1)')
->add('admin/markdown-preview.ajax', 'admin/markdown_preview')
- ->add('uploads/', 'admin/uploads')
- ->add('uploads/{edit_note,delete}/(\d+)/','admin/upload_${1} id=$(1)')
+ ->add('admin/uploads/', 'admin/uploads')
+ ->add('admin/uploads/{edit_note,delete}/(\d+)/', 'admin/upload_${1} id=$(1)')
;
(new RequestDispatcher($r))->dispatch();
\ No newline at end of file
diff --git a/htdocs/js/common/03-dom.js b/htdocs/js/common/03-dom.js
index d05bcd0..31a53b3 100644
--- a/htdocs/js/common/03-dom.js
+++ b/htdocs/js/common/03-dom.js
@@ -85,7 +85,6 @@ function cancelEvent(evt) {
return false;
}
-
//
// Cookies
//
diff --git a/htdocs/js/common/35-theme-switcher.js b/htdocs/js/common/35-theme-switcher.js
index c612152..01cf854 100644
--- a/htdocs/js/common/35-theme-switcher.js
+++ b/htdocs/js/common/35-theme-switcher.js
@@ -129,11 +129,14 @@ var ThemeSwitcher = (function() {
}
/**
- * @param {string} mode
+ * @param {string} selectedMode
*/
- function setLabel(mode) {
- var labelEl = ge('theme-switcher-label');
- labelEl.innerHTML = escape(lang('theme_'+mode));
+ function setIcon(selectedMode) {
+ document.body.setAttribute('data-theme', selectedMode);
+ for (var i = 0; i < modes.length; i++) {
+ var mode = modes[i];
+ document.getElementById('moon_'+mode).style.display = mode === selectedMode ? 'block': 'none';
+ }
}
return {
@@ -171,7 +174,7 @@ var ThemeSwitcher = (function() {
onSystemChange(window.matchMedia('(prefers-color-scheme: dark)').matches === true);
}
- setLabel(modes[currentModeIndex]);
+ setIcon(modes[currentModeIndex]);
},
next: function(e) {
@@ -198,7 +201,7 @@ var ThemeSwitcher = (function() {
break;
}
- setLabel(modes[currentModeIndex]);
+ setIcon(modes[currentModeIndex]);
setCookie('theme', modes[currentModeIndex]);
return cancelEvent(e);
diff --git a/htdocs/scss/app/head.scss b/htdocs/scss/app/head.scss
index ebc6d35..59d2f08 100644
--- a/htdocs/scss/app/head.scss
+++ b/htdocs/scss/app/head.scss
@@ -60,7 +60,19 @@ a.head-item {
font-size: $fs - 1px;
display: inline-block;
padding: 8px 12px;
- //margin-right: -16px;
+ vertical-align: middle;
+
+ &.is-theme-switcher,
+ &.is-settings {
+ padding: 8px;
+ }
+ &.is-settings {
+ font-size: 0;
+ > svg {
+ width: 18px;
+ height: 18px;
+ }
+ }
&:hover {
border-radius: 4px;
@@ -68,31 +80,13 @@ a.head-item {
text-decoration: none;
}
- > span {
- position: relative;
-
- > span {
- padding: 2px 0;
-
- &.moon-icon {
- padding: 0;
- position: absolute;
- top: 0;
- left: 0;
-
- > svg path {
- fill: $fg;
- }
- }
- }
- }
-
- &.is-theme-switcher > span {
- padding-left: 20px;
- }
-
//&:last-child > span {
// border-right: 0;
// padding-right: 1px;
//}
-}
\ No newline at end of file
+}
+
+body a.head-item.is-theme-switcher svg path,
+body a.head-item.is-settings svg path {
+ fill: $fg;
+}
diff --git a/lang/en.php b/lang/en.php
index 557408a..c900cc1 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -8,10 +8,9 @@ return [
'posts' => 'posts',
'all_posts' => 'all posts',
- 'blog' => 'blog',
+ 'articles' => 'Articles',
'contacts' => 'contacts',
'email' => 'email',
- 'projects' => 'projects',
'unknown_error' => 'Unknown error',
'error' => 'Error',
'write' => 'Write',
@@ -22,9 +21,9 @@ return [
'toc' => 'Table of Contents',
// theme switcher
- 'theme_auto' => 'auto',
- 'theme_dark' => 'dark',
- 'theme_light' => 'light',
+ //'theme_auto' => 'auto',
+ //'theme_dark' => 'dark',
+ //'theme_light' => 'light',
// contacts
'contacts_email' => 'email',
@@ -40,7 +39,6 @@ return [
'blog_post_hidden' => 'Hidden',
'blog_tag_title' => 'Posts tagged with "%s"',
'blog_tag_not_found' => 'No posts found.',
- 'blog_comments_text' => 'If you have any comments, contact me by email.',
'blog_write_form_preview_btn' => 'Preview',
'blog_write_form_submit_btn' => 'Submit',
diff --git a/model/Upload.php b/model/Upload.php
index 06b348b..c7205e6 100644
--- a/model/Upload.php
+++ b/model/Upload.php
@@ -24,8 +24,7 @@ class Upload extends Model {
}
public function getDirectUrl(): string {
- global $config;
- return 'https://'.$config['uploads_host'].'/'.$this->randomId.'/'.$this->name;
+ return '/upload/'.$this->randomId.'/'.$this->name;
}
public function getDirectPreviewUrl(int $w, int $h, bool $retina = false): string {
@@ -39,7 +38,7 @@ class Upload extends Model {
}
$prefix = $this->imageMayHaveAlphaChannel() ? 'a' : 'p';
- return 'https://'.$config['uploads_host'].'/'.$this->randomId.'/'.$prefix.$w.'x'.$h.'.jpg';
+ return $config['uploads_dir'].'/'.$this->randomId.'/'.$prefix.$w.'x'.$h.'.jpg';
}
// TODO remove?
diff --git a/skin/admin.phps b/skin/admin.phps
index b2d9bb4..17c60a2 100644
--- a/skin/admin.phps
+++ b/skin/admin.phps
@@ -40,7 +40,8 @@ return [$html, $js];
function index($ctx) {
return <<
-
+
+ Uploads
Sign out
HTML;
@@ -55,7 +56,7 @@ return <<if_true($error, $ctx->formError, $error)}