270 lines
8.8 KiB
PHP
270 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace skin\main;
|
|
|
|
// articles page
|
|
// -------------
|
|
|
|
use Post;
|
|
use PostLanguage;
|
|
use function is_admin;
|
|
|
|
function index($ctx, array $versions, array $posts, PostLanguage $posts_lang) {
|
|
return <<<HTML
|
|
<div class="page is-index">
|
|
<div class="blog-post-text">
|
|
<div class="clearfix index-book">
|
|
<div class="index-book-image-wrap">
|
|
<a class="index-book-image" id="index-book-image" href="https://files.4in1.ws/Images/4in1-cover-en.png" target="_blank" data-link-template="https://files.4in1.ws/Images/4in1-cover-{lang}.png"></a>
|
|
</div>
|
|
|
|
<a class="index-dl-line" href="https://files.4in1.ws/4in1-en.pdf?{$versions['en']}" onmouseenter="IndexPage.setCoverLang('en')">
|
|
<b>Download in English</b><br>
|
|
<div class="index-dl-line-info">
|
|
PDF <span class="bullet">•</span> 379 pp. <span class="bullet">•</span> 22 MiB
|
|
</div>
|
|
</a>
|
|
<a class="index-dl-line" href="https://files.4in1.ws/4in1-ru.pdf?{$versions['ru']}" onmouseenter="IndexPage.setCoverLang('ru')">
|
|
<b>Скачать на русском</b>
|
|
<div class="index-dl-line-info">
|
|
PDF <span class="bullet">•</span> 453 стр. <span class="bullet">•</span> 26 MiB
|
|
</div>
|
|
</a>
|
|
|
|
<div class="index-book-updates">
|
|
Released by <a href="https://kiwibyrd.org" target="_blank">kiwi arXiv</a> & <a href="https://kniganews.org" target="_blank">kniganews</a> in 2023<br>
|
|
English translation by Eline Cat<br>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="blog-list">
|
|
<div class="blog-list-title">{$ctx->lang('recent_articles')}</div>
|
|
<div class="blog-list-wrap">
|
|
{$ctx->for_each($posts,
|
|
fn($post, $i) => $ctx->articles_post_row($i, $post, $posts_lang, true, false))}
|
|
<a href="/articles/" class="blog-list-expand">
|
|
{$ctx->lang('view_all_articles')}
|
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.47 4.217a.75.75 0 0 0 0 1.06L12.185 10 7.469 14.72a.75.75 0 1 0 1.062 1.06l5.245-5.25a.75.75 0 0 0 0-1.061L8.531 4.218a.75.75 0 0 0-1.061-.001z" fill="currentColor"/></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
}
|
|
|
|
function articles($ctx, array $posts, PostLanguage $selected_lang): string {
|
|
if (empty($posts))
|
|
return $ctx->articles_empty($selected_lang);
|
|
|
|
$expl = $ctx->lang('blog_expl_'.$selected_lang->value);
|
|
$expl = nl2br($expl);
|
|
|
|
return <<<HTML
|
|
<div class="blog-expl">{$expl}</div>
|
|
<div class="blog-list">
|
|
{$ctx->articles_posts_table($posts, $selected_lang)}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
function articles_empty($ctx, PostLanguage $selected_lang) {
|
|
return <<<HTML
|
|
<div class="empty">
|
|
{$ctx->lang('blog_no')}
|
|
{$ctx->articles_right_links($selected_lang->value)}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
function articles_posts_table($ctx, array $posts, PostLanguage $selected_lang): string {
|
|
$ctx->year = 3000;
|
|
return <<<HTML
|
|
<div class="blog-list-wrap">
|
|
{$ctx->for_each($posts,
|
|
fn($post, $i) => $ctx->articles_post_row($i, $post, $selected_lang))}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
function articles_post_row($ctx,
|
|
int $index,
|
|
Post $post,
|
|
PostLanguage $selected_lang,
|
|
bool $no_block = false,
|
|
bool $show_year = true): string {
|
|
$year = $post->getYear();
|
|
$date = $post->getDate();
|
|
$url = $post->getUrl($selected_lang);
|
|
|
|
$pt = $post->getText($selected_lang);
|
|
$title = $pt->title;
|
|
|
|
$class = ['blog-list-item', 'clearfix'];
|
|
if (!$post->visible)
|
|
$class[] = 'is-hidden';
|
|
if ($no_block)
|
|
$class[] = 'no-block';
|
|
$class = 'class="'.implode(' ', $class).'"';
|
|
|
|
$buf = $no_block ? '<div '.$class.'>' : '<a href="'.$url.'" '.$class.'>';
|
|
$buf .= '<div class="blog-list-item-date">'.$date.'</div>';
|
|
$buf .= '<div class="blog-list-item-title">'.($no_block ? '<a href="'.$url.'">' : '').$title.($no_block ? '</a>' : '').'</div>';
|
|
$buf .= $no_block ? '</div>' : '</a>';
|
|
|
|
return <<<HTML
|
|
{$ctx->if_true($show_year && $ctx->year > $year,
|
|
fn() => $ctx->articles_index_year_line($year, $index === 0, $selected_lang->value))}
|
|
{$buf}
|
|
HTML;
|
|
}
|
|
|
|
function articles_index_year_line($ctx, $year, $show_right_links, string $selected_lang): string {
|
|
$ctx->year = $year;
|
|
return <<<HTML
|
|
<div class="blog-list-title">
|
|
{$year}
|
|
|
|
{$ctx->if_true($show_right_links,
|
|
fn() => $ctx->articles_right_links($selected_lang))}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
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')],
|
|
];
|
|
if (is_admin()) {
|
|
$links[] = ['url' => '/articles/write/?lang='.$selected_lang, 'label' => 'write'];
|
|
}
|
|
|
|
return <<<HTML
|
|
<div class="blog-item-right-links">
|
|
{$ctx->for_each($links, fn($link, $index) => $ctx->articles_right_link($link['url'], $link['label'], $index))}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
function articles_right_link($ctx, $url, string $label, int $index) {
|
|
$buf = '';
|
|
if ($index > 0)
|
|
$buf .= ' <span class="blog-links-separator">|</span> ';
|
|
$buf .= !$url ? $label : '<a href="'.$url.'">'.$label.'</a>';
|
|
return $buf;
|
|
}
|
|
|
|
|
|
// any page
|
|
// --------
|
|
|
|
function page($ctx, $page_url, $short_name, $unsafe_html, $bc) {
|
|
$html = <<<HTML
|
|
<div class="page">
|
|
{$ctx->if_true($bc, fn() => $ctx->bc($bc))}
|
|
{$ctx->if_admin($ctx->page_admin_links, $page_url, $short_name)}
|
|
<div class="blog-post-text">{$unsafe_html}</div>
|
|
</div>
|
|
HTML;
|
|
|
|
return [$html, js_markdownThemeChangeListener()];
|
|
}
|
|
|
|
function page_admin_links($ctx, $url, $short_name) {
|
|
return <<<HTML
|
|
<div class="page-edit-links">
|
|
<a href="{$url}edit/">{$ctx->lang('edit')}</a>
|
|
<a href="{$url}delete/?token={$ctx->csrf('delpage'.$short_name)}" onclick="return confirm('{$ctx->lang('pages_page_delete_confirmation')}')">{$ctx->lang('delete')}</a>
|
|
</div>
|
|
HTML;
|
|
|
|
}
|
|
|
|
|
|
// post page
|
|
// ---------
|
|
|
|
function post($ctx, $id, $title, $unsafe_html, $unsafe_toc_html, $date, $visible, $url, string $lang, $other_langs, string $source_url) {
|
|
$html = <<<HTML
|
|
<div class="blog-post-wrap2">
|
|
<div class="blog-post-wrap1">
|
|
<div class="blog-post">
|
|
{$ctx->bc([
|
|
['url' => '/articles/?lang='.$lang, 'text' => $ctx->lang('articles')]
|
|
])}
|
|
<div class="blog-post-title">
|
|
<h1>{$title}</h1>
|
|
<div class="blog-post-date">
|
|
{$ctx->if_not($visible, $ctx->lang('blog_post_hidden').' |')}
|
|
{$date}
|
|
{$ctx->if_true($other_langs, fn() => $ctx->post_other_langs($url, $other_langs))}
|
|
{$ctx->if_true($source_url, fn() => ' | <a href="'.$source_url.'">Source at kiwi arXiv</a>')}
|
|
{$ctx->if_admin($ctx->post_admin_links, $url, $id, $lang)}
|
|
</div>
|
|
</div>
|
|
<div class="blog-post-text">{$unsafe_html}</div>
|
|
</div>
|
|
{$ctx->if_true($unsafe_toc_html, $ctx->postToc, $unsafe_toc_html)}
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
return [$html, js_markdownThemeChangeListener()];
|
|
}
|
|
|
|
function post_other_langs($ctx, $url, $other_langs) {
|
|
$buf = '';
|
|
foreach ($other_langs as $lang) {
|
|
$buf .= ' | <a href="'.$url.($lang != 'en' ? '?lang='.$lang : '').'">'.$ctx->lang('blog_read_in_'.$lang).'</a>';
|
|
}
|
|
return $buf;
|
|
}
|
|
|
|
function postToc($ctx, $unsafe_toc_html) {
|
|
return <<<HTML
|
|
<div class="blog-post-toc">
|
|
<div class="blog-post-toc-wrap">
|
|
<div class="blog-post-toc-inner-wrap">
|
|
<div class="blog-post-toc-title">{$ctx->lang('toc')}</div>
|
|
{$unsafe_toc_html}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
}
|
|
|
|
function post_admin_links($ctx, $url, $id, string $lang) {
|
|
return <<<HTML
|
|
| <a href="{$url}edit/?lang={$lang}">{$ctx->lang('edit')}</a>
|
|
| <a href="{$url}delete/?token={$ctx->csrf('delpost'.$id)}" onclick="return confirm('{$ctx->lang('blog_post_delete_confirmation')}')">{$ctx->lang('delete')}</a>
|
|
HTML;
|
|
}
|
|
|
|
function js_markdownThemeChangeListener() {
|
|
return <<<JS
|
|
ThemeSwitcher.addOnChangeListener(function(isDark) {
|
|
var nodes = document.querySelectorAll('.md-image-wrap');
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
var node = nodes[i];
|
|
var alpha = parseInt(node.getAttribute('data-alpha'), 10);
|
|
if (!alpha)
|
|
continue;
|
|
var div = node.querySelector('a > div');
|
|
if (!div) {
|
|
console.warn('could not found a>div on this node:', node);
|
|
continue;
|
|
}
|
|
var style = div.getAttribute('style');
|
|
if (isDark) {
|
|
style = style.replace(/(a[\d]+x[\d]+)\.jpg/, '$1_dark.jpg');
|
|
} else {
|
|
style = style.replace(/(a[\d]+x[\d]+)_dark\.jpg/, '$1.jpg');
|
|
}
|
|
div.setAttribute('style', style);
|
|
}
|
|
});
|
|
JS;
|
|
}
|