diff --git a/handler/AdminHandler.php b/handler/AdminHandler.php index 5caef7f..e663a90 100644 --- a/handler/AdminHandler.php +++ b/handler/AdminHandler.php @@ -243,13 +243,14 @@ class AdminHandler extends request_handler { set_title('$blog_upload'); render('admin/uploads', error: $error, - uploads: $uploads); + uploads: $uploads, + langs: PostLanguage::cases()); } function POST_uploads() { csrf_check('addupl'); - list($custom_name, $note) = input('name, note'); + list($custom_name, $note_en, $note_ru) = input('name, note_en, note_ru'); if (!isset($_FILES['files'])) redirect('/admin/uploads/?error='.urlencode('no file')); @@ -266,7 +267,8 @@ class AdminHandler extends request_handler { } if (count($files) > 1) { - $note = ''; + $note_en = ''; + $note_ru = ''; $custom_name = ''; } @@ -285,12 +287,13 @@ class AdminHandler extends request_handler { $upload_id = uploads::add( $f['tmp_name'], $name, - $note); + $note_en, + $note_ru); if (!$upload_id) redirect('/admin/uploads/?error='.urlencode('failed to create upload')); - admin_log(new \AdminActions\UploadsAdd($upload_id, $name, $note)); + admin_log(new \AdminActions\UploadsAdd($upload_id, $name, $note_en, $note_ru)); } redirect('/admin/uploads/'); @@ -308,7 +311,10 @@ class AdminHandler extends request_handler { } function POST_upload_edit_note() { - list($id, $note) = input('i:id, note'); + list($id, $note, $lang) = input('i:id, note, lang'); + $lang = PostLanguage::tryFrom($lang); + if (!$lang) + not_found(); $upload = uploads::get($id); if (!$upload) @@ -316,16 +322,19 @@ class AdminHandler extends request_handler { csrf_check('editupl'.$id); - $upload->setNote($note); + $upload->setNote($lang, $note); - admin_log(new \AdminActions\UploadsEditNote($id, $note)); + admin_log(new \AdminActions\UploadsEditNote($id, $note, $lang->value)); redirect('/admin/uploads/'); } function POST_ajax_md_preview() { ensure_xhr(); - list($md, $title, $use_image_previews) = input('md, title, b:use_image_previews'); - $html = markup::markdownToHtml($md, $use_image_previews); + list($md, $title, $use_image_previews, $lang) = input('md, title, b:use_image_previews, lang'); + $lang = PostLanguage::tryFrom($lang); + if (!$lang) + invalid_request(); + $html = markup::markdownToHtml($md, $use_image_previews, $lang); $ctx = skin('admin'); $html = $ctx->markdownPreview( unsafe_html: $html, diff --git a/htdocs/js/admin/11-write-form.js b/htdocs/js/admin/11-write-form.js index 722ab65..ff06c3e 100644 --- a/htdocs/js/admin/11-write-form.js +++ b/htdocs/js/admin/11-write-form.js @@ -81,7 +81,8 @@ extend(AdminWriteEditForm.prototype, { this.previewRequest.abort(); var params = { md: this.form.elements.text.value, - use_image_previews: this.isPage() ? 1 : 0 + use_image_previews: this.isPage() ? 1 : 0, + lang: this.getCurrentLang() }; if (this.isPost()) params.title = this.form.elements.title.value; diff --git a/htdocs/scss/app/blog.scss b/htdocs/scss/app/blog.scss index 7e00e7b..60588fd 100644 --- a/htdocs/scss/app/blog.scss +++ b/htdocs/scss/app/blog.scss @@ -95,7 +95,13 @@ font-size: $fs - 2px; } .blog-upload-item-note { - padding: 0 0 4px; + padding: 8px 0 0; + > span { + background-color: $hover-hl; + padding: 1px 5px; + color: $dark-grey; + margin-right: 6px; + } } .blog-upload-item-md { margin-top: 3px; @@ -376,51 +382,43 @@ body.wide .blog-post { color: $grey; } -.blog-list-table-wrap { - padding: 5px 0; -} -.blog-list-table { - border-collapse: collapse; -} -.blog-list-table td { - vertical-align: top; - padding: 0 0 13px; -} -.blog-list-table tr:last-child td { - padding-bottom: 0; -} -td.blog-item-date-cell { - width: 1px; - white-space: nowrap; - //text-align: right; - padding-right: 10px; -} -.blog-item-date { - color: $grey; - //text-transform: lowercase; -} -td.blog-item-title-cell { - text-align: left; -} -.blog-item-title { - //font-weight: bold; -} -.blog-item-row { - font-size: $fs; - line-height: 140%; -} -.blog-item-row.ishidden a.blog-item-title { - color: $fg; -} -.blog-item-row-year { - td { - padding-top: 10px; - //text-align: right; - font-size: $fs + 2px; - //letter-spacing: -0.5px; + +.blog-list { + &-wrap { + padding: 5px 0; } - &:first-child td { - padding-top: 0; + + &-item { + display: block; + padding: 6px 8px; + margin-left: -8px; + margin-right: -8px; + font-size: $fs; + //line-height: 140%; + + &:hover { + text-decoration: none; + background-color: $hover-hl; + @include radius(3px); + } + + &-date { + color: $grey; + float: left; + } + &-title { + margin-left: 70px; + text-align: left; + } + &.is-hidden &-title { + color: $fg; + } } } +.blog-list-title { + font-size: $fs + 2px; + padding-top: 14px; + margin-bottom: 8px; + &:first-child { padding-top: 0; } +} diff --git a/htdocs/scss/app/common.scss b/htdocs/scss/app/common.scss index 2674462..448ed9f 100644 --- a/htdocs/scss/app/common.scss +++ b/htdocs/scss/app/common.scss @@ -282,9 +282,10 @@ table.contacts div.note { max-width: 100%; } .md-image-note { - line-height: 150%; + line-height: 130%; color: $dark-grey; - padding: 2px 0 4px; + padding: 8px 0 4px; + font-style: italic; } .md-video video { diff --git a/htdocs/scss/app/form.scss b/htdocs/scss/app/form.scss index 197732c..f2bf928 100644 --- a/htdocs/scss/app/form.scss +++ b/htdocs/scss/app/form.scss @@ -1,6 +1,6 @@ @import '../vars'; -$form-field-label-width: 120px; +$form-field-label-width: 160px; form { display: block; margin: 0; } diff --git a/lib/AdminActions/UploadsAdd.php b/lib/AdminActions/UploadsAdd.php index 9a8c894..d006abb 100644 --- a/lib/AdminActions/UploadsAdd.php +++ b/lib/AdminActions/UploadsAdd.php @@ -7,7 +7,8 @@ class UploadsAdd extends BaseAction { public function __construct( public int $uploadId, public string $name, - public string $note + public string $noteEn, + public string $noteRu ) {} } \ No newline at end of file diff --git a/lib/AdminActions/UploadsEditNote.php b/lib/AdminActions/UploadsEditNote.php index 7487291..922313a 100644 --- a/lib/AdminActions/UploadsEditNote.php +++ b/lib/AdminActions/UploadsEditNote.php @@ -6,7 +6,8 @@ class UploadsEditNote extends BaseAction { public function __construct( public int $uploadId, - public string $note + public string $note, + public string $lang ) {} } \ No newline at end of file diff --git a/lib/ext/MyParsedown.php b/lib/ext/MyParsedown.php index 9fc5d38..ce9e8f8 100644 --- a/lib/ext/MyParsedown.php +++ b/lib/ext/MyParsedown.php @@ -1,12 +1,16 @@ [ @@ -44,15 +48,13 @@ class MyParsedown extends ParsedownExtended { unset($result['element']['text']); $ctx = self::getSkinContext(); - $result['element']['rawHtml'] = $ctx->fileupload($upload->name, $upload->getDirectUrl(), $upload->note, $upload->getSize()); + $result['element']['rawHtml'] = $ctx->fileupload($upload->name, $upload->getDirectUrl(), $upload->noteRu, $upload->getSize()); return $result; } } protected function inlineImage($excerpt) { - global $config; - if (preg_match('/^{image:([\w]{8}),(.*?)}{\/image}/', $excerpt['text'], $matches)) { $random_id = $matches[1]; @@ -115,7 +117,7 @@ class MyParsedown extends ParsedownExtended { url: $image_url, direct_url: $image->getDirectUrl(), - note: $image->note + note: $this->lang !== null && $this->lang == PostLanguage::Russian ? $image->noteRu : $image->noteEn ); return $result; diff --git a/lib/markup.php b/lib/markup.php index c3a2f10..1e7698a 100644 --- a/lib/markup.php +++ b/lib/markup.php @@ -1,11 +1,14 @@ text($md); } diff --git a/lib/posts.php b/lib/posts.php index a521988..9ff1a33 100644 --- a/lib/posts.php +++ b/lib/posts.php @@ -21,7 +21,7 @@ class Post extends model { protected array $texts = []; public function addText(PostLanguage $lang, string $title, string $md, bool $toc): ?PostText { - $html = markup::markdownToHtml($md); + $html = markup::markdownToHtml($md, lang: $lang); $text = markup::htmlToText($html); $data = [ @@ -128,7 +128,7 @@ class PostText extends model { public function edit(array $fields) { if ($fields['md'] != $this->md) { - $fields['html'] = markup::markdownToHtml($fields['md']); + $fields['html'] = markup::markdownToHtml($fields['md'], lang: $this->lang); $fields['text'] = markup::htmlToText($fields['html']); } @@ -141,13 +141,13 @@ class PostText extends model { } public function updateHtml(): void { - $html = markup::markdownToHtml($this->md); + $html = markup::markdownToHtml($this->md, lang: $this->lang); $this->html = $html; DB()->query("UPDATE posts_texts SET html=? WHERE id=?", $html, $this->id); } public function updateText(): void { - $html = markup::markdownToHtml($this->md); + $html = markup::markdownToHtml($this->md, lang: $this->lang); $text = markup::htmlToText($html); $this->text = $text; DB()->query("UPDATE posts_texts SET text=? WHERE id=?", $text, $this->id); diff --git a/lib/uploads.php b/lib/uploads.php index 70830db..a8649f8 100644 --- a/lib/uploads.php +++ b/lib/uploads.php @@ -19,7 +19,7 @@ class uploads { return in_array($ext, UPLOADS_ALLOWED_EXTENSIONS); } - static function add(string $tmp_name, string $name, string $note): ?int { + static function add(string $tmp_name, string $name, string $note_en, string $note_ru): ?int { global $config; $name = sanitize_filename($name); @@ -44,7 +44,8 @@ class uploads { 'image' => (int)$is_image, 'image_w' => $image_w, 'image_h' => $image_h, - 'note' => $note, + 'note_ru' => $note_ru, + 'note_en' => $note_en, 'downloads' => 0, ])) { return null; @@ -163,7 +164,8 @@ class Upload extends model { public int $image; // TODO: remove public int $imageW; public int $imageH; - public string $note; + public string $noteRu; + public string $noteEn; function getDirectory(): string { global $config; @@ -212,9 +214,9 @@ class Upload extends model { return $md; } - function setNote(string $note) { + function setNote(PostLanguage $lang, string $note) { $db = DB(); - $db->query("UPDATE uploads SET note=? WHERE id=?", $note, $this->id); + $db->query("UPDATE uploads SET note_{$lang->value}=? WHERE id=?", $note, $this->id); } function isImage(): bool { diff --git a/skin/admin.phps b/skin/admin.phps index bc80c3b..559977b 100644 --- a/skin/admin.phps +++ b/skin/admin.phps @@ -2,6 +2,7 @@ namespace skin\admin; +use PostLanguage; use Stringable; use function skin\base\layout; @@ -64,7 +65,7 @@ HTML; // uploads page // ------------ -function uploads($ctx, $uploads, $error) { +function uploads($ctx, $uploads, $error, array $langs) { return <<if_true($error, $ctx->formError, $error)} @@ -91,12 +92,8 @@ return << -
-
{$ctx->lang('blog_upload_form_note')}:
-
- -
-
+ {$ctx->for_each($langs, + fn($l) => $ctx->uploads_form_note_field($l))}
@@ -108,12 +105,14 @@ return <<
- {$ctx->for_each($uploads, fn($u) => $ctx->uploadsItem( + {$ctx->for_each($uploads, fn($u) => $ctx->uploads_item( id: $u->id, name: $u->name, direct_url: $u->getDirectUrl(), - note: $u->note, - addslashes_note: $u->note, + note_ru: $u->noteRu, + note_en: $u->noteEn, + addslashes_note_ru: $u->noteRu, + addslashes_note_en: $u->noteEn, markdown: $u->getMarkdown(), size: $u->getSize(), ))} @@ -121,17 +120,35 @@ return <<lang('blog_upload_form_note'); +$label .= ' ('.$lang->name.')'; + +return << +
{$label}:
+
+ +
+
+HTML; +} + +function uploads_item($ctx, $id, $direct_url, $note_en, $note_ru, $addslashes_note_en, $addslashes_note_ru, $markdown, $name, $size) { return <<
{$ctx->lang('blog_upload_show_md')} - | Edit note + | Edit note Ru + | Edit note En | {$ctx->lang('blog_upload_delete')}
{$name}
- {$ctx->if_true($note, '
'.$note.'
')}
{$size}
+ {$ctx->if_true($note_en, + fn() => '
En'.$note_en.'
')} + {$ctx->if_true($note_ru, + fn() => '
Ru'.$note_ru.'
')} diff --git a/skin/main.phps b/skin/main.phps index 4e49480..4144965 100644 --- a/skin/main.phps +++ b/skin/main.phps @@ -45,36 +45,35 @@ HTML; function articles($ctx, array $posts, PostLanguage $selected_lang): string { if (empty($posts)) - return $ctx->articlesEmpty($selected_lang); + return $ctx->articles_empty($selected_lang); return << - {$ctx->articlesPostsTable($posts, $selected_lang)} + {$ctx->articles_posts_table($posts, $selected_lang)}
HTML; } -function articlesEmpty($ctx, PostLanguage $selected_lang) { +function articles_empty($ctx, PostLanguage $selected_lang) { return << {$ctx->lang('blog_no')} - {$ctx->articlesRightLinks($selected_lang->value)} + {$ctx->articles_right_links($selected_lang->value)} HTML; } -function articlesPostsTable($ctx, array $posts, PostLanguage $selected_lang): string { +function articles_posts_table($ctx, array $posts, PostLanguage $selected_lang): string { $ctx->year = 3000; return << - - {$ctx->for_each($posts, fn($post, $i) => $ctx->articlesPostRow($i, $post, $selected_lang))} -
+
+ {$ctx->for_each($posts, + fn($post, $i) => $ctx->articles_post_row($i, $post, $selected_lang))}
HTML; } -function articlesPostRow($ctx, int $index, Post $post, PostLanguage $selected_lang): string { +function articles_post_row($ctx, int $index, Post $post, PostLanguage $selected_lang): string { $year = $post->getYear(); $date = $post->getDate(); $url = $post->getUrl($selected_lang); @@ -83,32 +82,29 @@ $pt = $post->getText($selected_lang); $title = $pt->title; return <<if_true($ctx->year > $year, $ctx->articlesIndexYearLine, $year, $index === 0, $selected_lang->value)} - - - {$date} - - - {$title} - - +{$ctx->if_true($ctx->year > $year, + fn() => $ctx->articles_index_year_line($year, $index === 0, $selected_lang->value))} + + +
{$date}
+
{$title}
+
HTML; } -function articlesIndexYearLine($ctx, $year, $show_right_links, string $selected_lang): string { +function articles_index_year_line($ctx, $year, $show_right_links, string $selected_lang): string { $ctx->year = $year; return << - {$year} - - {$ctx->if_true($show_right_links, $ctx->articlesRightLinks($selected_lang))} - - +
+ {$year} + + {$ctx->if_true($show_right_links, + fn() => $ctx->articles_right_links($selected_lang))} +
HTML; } - -function articlesRightLinks($ctx, string $selected_lang) { +function articles_right_links($ctx, string $selected_lang) { $links = [ ['url' => $selected_lang != 'en' ? '/articles/' : null, 'label' => lang('lang_en')], ['url' => $selected_lang != 'ru' ? '/articles/?lang=ru' : null, 'label' => lang('lang_ru')], @@ -119,12 +115,12 @@ if (is_admin()) { return << - {$ctx->for_each($links, fn($link, $index) => $ctx->articlesRightLink($link['url'], $link['label'], $index))} + {$ctx->for_each($links, fn($link, $index) => $ctx->articles_right_link($link['url'], $link['label'], $index))} HTML; } -function articlesRightLink($ctx, $url, string $label, int $index) { +function articles_right_link($ctx, $url, string $label, int $index) { $buf = ''; if ($index > 0) $buf .= ' | '; @@ -142,15 +138,15 @@ $html = << {$ctx->lang('index')} --> - {$ctx->if_admin($ctx->pageAdminLinks, $page_url, $short_name)} + {$ctx->if_admin($ctx->page_admin_links, $page_url, $short_name)}
{$unsafe_html}
HTML; -return [$html, markdownThemeChangeListener()]; +return [$html, js_markdownThemeChangeListener()]; } -function pageAdminLinks($ctx, $url, $short_name) { +function page_admin_links($ctx, $url, $short_name) { return << {$ctx->lang('edit')} @@ -177,8 +173,8 @@ $html = << {$ctx->if_not($visible, $ctx->lang('blog_post_hidden').' |')} {$date} - {$ctx->if_true($other_langs, $ctx->postOtherLangs($url, $other_langs))} - {$ctx->if_admin($ctx->postAdminLinks, $url, $id, $lang)} + {$ctx->if_true($other_langs, $ctx->post_other_langs($url, $other_langs))} + {$ctx->if_admin($ctx->post_admin_links, $url, $id, $lang)}
{$unsafe_html}
@@ -188,10 +184,10 @@ $html = << HTML; -return [$html, markdownThemeChangeListener()]; +return [$html, js_markdownThemeChangeListener()]; } -function postOtherLangs($ctx, $url, $other_langs) { +function post_other_langs($ctx, $url, $other_langs) { $buf = ''; foreach ($other_langs as $lang) { $buf .= ' | '.$ctx->lang('blog_read_in_'.$lang).''; @@ -213,14 +209,14 @@ HTML; } -function postAdminLinks($ctx, $url, $id, string $lang) { +function post_admin_links($ctx, $url, $id, string $lang) { return <<{$ctx->lang('edit')} | {$ctx->lang('delete')} HTML; } -function markdownThemeChangeListener() { +function js_markdownThemeChangeListener() { return <<
- {$ctx->if_true( - $note != '' && !$nolabel, - '
'.$note.'
' - )} + {$ctx->if_true($note != '' && !$nolabel, + fn() => '
'.$note.'
')} HTML; }