$config['domain'], 'devMode' => $config['is_dev'], 'cookieHost' => $config['cookie_host'], ]); return << {$title} {$ctx->renderMeta($meta)} {$ctx->renderStatic($static, $theme)} if_true($opts['full_width'], ' class="full-width"')}> {$ctx->renderHeader($theme, renderLogo($ctx, $opts['logo_path_map'], $opts['logo_link_map']))}
{$unsafe_body}
{$ctx->renderScript($js, $unsafe_lang, $opts['dynlogo_enabled'])} HTML; } function renderScript($ctx, $unsafe_js, $unsafe_lang, $enable_dynlogo) { global $config; $styles = json_encode($ctx->styleNames); if ($config['is_dev']) $versions = '{}'; else { $versions = []; foreach ($config['static'] as $name => $v) { list($type, $bname) = getStaticNameParts($name); $versions[$type][$bname] = $v; } $versions = json_encode($versions); } return << StaticManager.init({$styles}, {$versions}); {$ctx->if_true($unsafe_js, '(function(){'.$unsafe_js.'})();')} {$ctx->if_true($unsafe_lang, 'extend(__lang, '.$unsafe_lang.');')} {$ctx->if_true($enable_dynlogo, 'DynamicLogo.init();')} ThemeSwitcher.init(); HTML; } function renderMeta($ctx, $meta) { if (empty($meta)) return ''; return implode('', array_map(function(array $item): string { $s = ' $v) $s .= ' '.htmlescape($k).'="'.htmlescape($v).'"'; $s .= '>'; return $s; }, $meta)); } function renderStatic($ctx, $static, $theme) { global $config; $html = []; $dark = $theme == 'dark'; $ctx->styleNames = []; foreach ($static as $name) { // javascript if (str_starts_with($name, 'js/')) $html[] = jsLink($name); // css else if (str_starts_with($name, 'css/')) { $html[] = cssLink($name, 'light', $style_name); $ctx->styleNames[] = $style_name; if ($dark) $html[] = cssLink($name, 'dark', $style_name); else if (!$config['is_dev']) $html[] = cssPrefetchLink($style_name.'_dark'); } else logError(__FUNCTION__.': unexpected static entry: '.$name); } return implode("\n", $html); } function jsLink(string $name): string { global $config; list (, $bname) = getStaticNameParts($name); if ($config['is_dev']) { $href = '/js.php?name='.urlencode($bname).'&v='.time(); } else { $href = '/dist-js/'.$bname.'.js?'.getStaticVersion($name); } return ''; } function cssLink(string $name, string $theme, &$bname = null): string { global $config; list(, $bname) = getStaticNameParts($name); if ($config['is_dev']) { $href = '/sass.php?name='.urlencode($bname).'&theme='.$theme.'&v='.time(); } else { $version = getStaticVersion('css/'.$bname.($theme == 'dark' ? '_dark' : '').'.css'); $href = '/dist-css/'.$bname.($theme == 'dark' ? '_dark' : '').'.css?'.$version; } $id = 'style_'.$bname; if ($theme == 'dark') $id .= '_dark'; return ''; } function cssPrefetchLink(string $name): string { $url = '/dist-css/'.$name.'.css?'.getStaticVersion('css/'.$name.'.css'); return << HTML; } function getStaticNameParts(string $name): array { $dname = dirname($name); $bname = basename($name); if (($pos = strrpos($bname, '.'))) { $ext = substr($bname, $pos+1); $bname = substr($bname, 0, $pos); } else { $ext = ''; } return [$dname, $bname, $ext]; } function getStaticVersion(string $name): string { global $config; if ($config['is_dev']) return time(); if (str_starts_with($name, '/')) { logWarning(__FUNCTION__.': '.$name.' starts with /'); $name = substr($name, 1); } return $config['static'][$name] ?? 'notfound'; } function renderHeader($ctx, $theme, $unsafe_logo_html) { $items = [ ['url' => 'javascript:void(0)', 'label' => $theme, 'label_id' => 'theme-switcher-label', 'theme_switcher' => true], ['url' => '/', 'label' => 'blog'], ['url' => '/projects/', 'label' => 'projects'], ['url' => 'https://git.ch1p.io/?s=idle', 'label' => 'git'], ['url' => '/misc/', 'label' => 'misc'], ['url' => '/contacts/', 'label' => 'contacts'], ]; if (\admin::isAdmin()) $items[] = ['url' => '/admin/', 'label' => 'admin']; // here, items are rendered using for_each, so that there are no gaps (whitespaces) between tags return <<
{$ctx->for_each($items, fn($item) => $ctx->renderHeaderItem($item['url'], $item['label'], $item['label_id'] ?? null, $item['theme_switcher'] ?? false))}
HTML; } function renderHeaderItem($ctx, $url, $label, $label_id, $is_theme_switcher) { return <<if_true($is_theme_switcher, ' onclick="return ThemeSwitcher.next(event)"')}> {$ctx->if_true($is_theme_switcher, ''.$ctx->renderMoonIcon().'')} if_true($label_id, ' id="'.$label_id.'"')}>{$label} HTML; } // TODO rewrite this fcking crap function renderLogo($ctx, array $path_map = [], array $link_map = []): string { $uri = RequestDispatcher::path(); if (!admin::isAdmin()) { $prompt_sign = '$'; } else { $prompt_sign = '#'; } if ($uri == '/') { $html = '/home/'.$ctx->lang('ch1p').' '.$prompt_sign; } else { $uri_len = strlen($uri); $html = ''; $close_tags = 0; $path_parts = []; $path_links = []; $last_pos = 0; $cur_path = ''; while ($last_pos < $uri_len) { $first = $last_pos === 0; $end = false; $pos = strpos($uri, '/', $last_pos); if ($pos === false || $pos == $uri_len-1) { $pos = $uri_len-1; $end = true; } $part = substr($uri, $last_pos, $pos - $last_pos + 1); $cur_path .= $part; if ($end) { if (substr($part, -1) == '/') $part = substr($part, 0, strlen($part)-1); $cur_path = '/'; $html .= str_repeat('', $close_tags-1); $close_tags = 1; } $span_class = 'head-logo-path'; if ($first) { $span_class .= ' alwayshover'; } else if ($end) { $span_class .= ' neverhover'; } $html .= '${{'.count($path_parts).'}}'; $path_parts[] = ($first ? '~' : '').$part; $path_links[] = $cur_path; $last_pos = $pos + 1; $close_tags++; } $html .= str_repeat('', $close_tags).' '.$prompt_sign.' cd ~ '.enterIcon().'Enter'; for ($i = count($path_parts)-1, $j = 0; $i >= 0; $i--, $j++) { if (isset($path_map[$j])) { $tmp = htmlescape(strtrim($path_map[$j], 40, $trimmed)); if ($trimmed) $tmp .= '…'; $tmp_html = ''.$tmp.''; if ($j > 0) $tmp_html .= '/'; $html = str_replace_once('${{'.$i.'}}', $tmp_html, $html); } else { $html = str_replace_once('${{'.$i.'}}', $path_parts[$i], $html); } if (isset($link_map[$j])) { $html = str_replace_once('$[['.$i.']]', $link_map[$j], $html); } else { $html = str_replace_once('$[['.$i.']]', $path_links[$i], $html); } } } return $html; } function enterIcon() { return << SVG; } function renderMoonIcon($ctx) { return << SVG; }