Compare commits
10 Commits
7b064eb6da
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f679d0b20e | |||
| 9feccf9eaa | |||
| 14ec6b7e7a | |||
| 42a828a778 | |||
| 81c239f043 | |||
| 0d91b61bd0 | |||
| fd9a71c4d6 | |||
| 71413283c8 | |||
| a32956b4a2 | |||
| 7bf3dc6610 |
9
controllers/coming-soon.php
Normal file
9
controllers/coming-soon.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
$data = array_merge($data, [
|
||||
'title' => 'Coming Soon',
|
||||
'heading' => 'Coming Soon',
|
||||
'countdown' => true,
|
||||
'launch_date' => '2026-01-01T00:00:00'
|
||||
]);
|
||||
|
||||
view('@novacore/coming-soon', $data);
|
||||
94
sass/coming-soon/index.sass
Normal file
94
sass/coming-soon/index.sass
Normal file
@@ -0,0 +1,94 @@
|
||||
body#coming-soon
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
height: 100%
|
||||
padding: 1rem
|
||||
box-sizing: border-box
|
||||
margin: 0
|
||||
text-align: center
|
||||
color: #eee
|
||||
font-family: 'Segoe UI', Roboto, sans-serif
|
||||
background-size: cover
|
||||
background-repeat: no-repeat
|
||||
background-position: center center
|
||||
background-attachment: fixed
|
||||
|
||||
.container
|
||||
max-width: 600px
|
||||
background-color: rgba(30, 30, 30, 0.89)
|
||||
padding: 2rem
|
||||
border-radius: 8px
|
||||
box-shadow: 0 0 20px rgba(0,0,0,0.5)
|
||||
|
||||
h1
|
||||
font-size: 3rem
|
||||
margin-bottom: 1rem
|
||||
animation: pulse 1.5s infinite
|
||||
|
||||
p
|
||||
font-size: 1.2rem
|
||||
opacity: 0.85
|
||||
margin-bottom: 1.5rem
|
||||
|
||||
.countdown
|
||||
font-size: 2rem
|
||||
font-weight: bold
|
||||
margin: 1rem 0 2rem 0
|
||||
|
||||
form.newsletter
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.5rem
|
||||
margin-top: 1rem
|
||||
|
||||
input[type="email"]
|
||||
padding: 0.5rem
|
||||
font-size: 1rem
|
||||
border: 1px solid #666
|
||||
border-radius: 4px
|
||||
background: rgba(255,255,255,0.05)
|
||||
color: #eee
|
||||
|
||||
button
|
||||
padding: 0.5rem
|
||||
font-size: 1rem
|
||||
border: 1px solid #1e90ff
|
||||
border-radius: 4px
|
||||
background: #1e90ff
|
||||
color: #fff
|
||||
cursor: pointer
|
||||
transition: background 0.2s
|
||||
|
||||
&:hover
|
||||
background: #1565c0
|
||||
|
||||
.social-icons
|
||||
margin-top: 2rem
|
||||
display: flex
|
||||
justify-content: center
|
||||
gap: 1rem
|
||||
|
||||
a
|
||||
display: inline-flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 40px
|
||||
height: 40px
|
||||
font-size: 1.5rem
|
||||
color: #eee
|
||||
text-decoration: none
|
||||
transition: color 0.2s
|
||||
|
||||
&:hover
|
||||
color: #1e90ff
|
||||
|
||||
i
|
||||
font-style: normal
|
||||
|
||||
|
||||
@keyframes pulse
|
||||
0%, 100%
|
||||
opacity: 0.8
|
||||
50%
|
||||
opacity: 1
|
||||
@@ -3,3 +3,4 @@
|
||||
@use 'base' as *
|
||||
@use 'framework' as *
|
||||
@use 'controlPanel' as *
|
||||
@use 'coming-soon' as *
|
||||
@@ -10,6 +10,8 @@ $config = [
|
||||
'base_url' => 'http://localhost:8000',
|
||||
'secure_key' => '', //64 alphanumeric characters
|
||||
'logfile' => '/logs/novaconium.log',
|
||||
'loglevel' => 'ERROR', // 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'NONE'
|
||||
'loglevel' => 'ERROR', // 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'NONE',
|
||||
'matomo_url' => 'matomo.4lt.ca',
|
||||
'matomo_id' => '0',
|
||||
'fonts' => 'https://fonts.googleapis.com/css2?family=VT323:wght@400&family=Fira+Code:wght@400;500&display=swap&family=Material+Icons:wght@400;500&display=swap'
|
||||
];
|
||||
|
||||
28
skeleton/novaconium/App/controllers/humans.php
Normal file
28
skeleton/novaconium/App/controllers/humans.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
header('Cache-Control: public, max-age=604800');
|
||||
|
||||
echo <<<TXT
|
||||
/*
|
||||
* This humans.txt was generated by the framework.
|
||||
* You may edit or remove it without affecting your site.
|
||||
*/
|
||||
|
||||
/* FRAMEWORK */
|
||||
Built With: Novaconium PHP
|
||||
repo: https://git.4lt.ca/4lt/novaconium
|
||||
Human: Nick Yeoman
|
||||
url: https://www.nickyeoman.com/
|
||||
Occupation: Linux Systems Administrator / Software Framework Author
|
||||
Location: Canada
|
||||
|
||||
/* SITE */
|
||||
Built with: Novaconium PHP
|
||||
Runs on: CORXN Container
|
||||
Optimized for: Humans
|
||||
|
||||
/* META */
|
||||
There are four lights.
|
||||
TXT;
|
||||
33
skeleton/novaconium/App/controllers/page.php
Normal file
33
skeleton/novaconium/App/controllers/page.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
$slug = $router->parameters['slug'];
|
||||
$query=<<<EOSQL
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
heading,
|
||||
description,
|
||||
keywords,
|
||||
author,
|
||||
body,
|
||||
created,
|
||||
updated
|
||||
FROM pages
|
||||
WHERE slug = '$slug'
|
||||
EOSQL;
|
||||
|
||||
//$db->debugGetRow($query);
|
||||
$data = $db->getRow($query);
|
||||
if(!$data) {
|
||||
http_response_code('404');
|
||||
header("Content-Type: text/html");
|
||||
view('404');
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = array_merge($data, [
|
||||
'menuActive' => 'blog',
|
||||
'pageid' => 'page',
|
||||
'permissionsGroup' => $session->get('group')
|
||||
]);
|
||||
|
||||
view('page', $data);
|
||||
18
skeleton/novaconium/App/controllers/robots.php
Normal file
18
skeleton/novaconium/App/controllers/robots.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Send proper headers
|
||||
header('Content-Type: text/plain; charset=UTF-8');
|
||||
header('Cache-Control: public, max-age=604800');
|
||||
|
||||
// Use $config['base_url'] as-is
|
||||
$baseUrl = $config['base_url'];
|
||||
|
||||
echo <<<TXT
|
||||
# robots.txt for sites powered by Novaconium framework
|
||||
|
||||
User-agent: *
|
||||
Disallow: /novaconium/
|
||||
|
||||
Sitemap: {$baseUrl}/sitemap.xml
|
||||
TXT;
|
||||
@@ -2,5 +2,14 @@
|
||||
$routes = [
|
||||
'/' => [
|
||||
'get' => 'index'
|
||||
],
|
||||
'/robots.txt' => [
|
||||
'get' => 'robots'
|
||||
],
|
||||
'/humans.txt' => [
|
||||
'get' => 'humans'
|
||||
],
|
||||
'/page/{slug}' => [
|
||||
'get' => 'page'
|
||||
]
|
||||
];
|
||||
11
skeleton/novaconium/App/views/page.html.twig
Normal file
11
skeleton/novaconium/App/views/page.html.twig
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends '@novaconium/master.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
<div class="page-meta">
|
||||
{% if updated is not empty %}
|
||||
<span class="page-updated">Last Updated: {{ updated | date("M\\. jS Y \\a\\t g:ia") }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ body | raw}}
|
||||
{% endblock %}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,16 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Novaconium Framework Entry Point
|
||||
*
|
||||
* This is the main entry point for the Novaconium framework.
|
||||
* It sets up the environment, loads necessary components,
|
||||
* and runs the application.
|
||||
*
|
||||
* @package Novaconium
|
||||
* @author Nick Yeoman <dev@4lt.ca>
|
||||
*/
|
||||
|
||||
|
||||
// Enable error reporting for development environments
|
||||
// error_reporting(E_ALL);
|
||||
// ini_set('display_errors', 1);
|
||||
|
||||
185
skeleton/novaconium/public/js/tabs.js
Normal file
185
skeleton/novaconium/public/js/tabs.js
Normal file
@@ -0,0 +1,185 @@
|
||||
// /js/tabs.js
|
||||
|
||||
// Tab switching
|
||||
function switchTab(tabId, button) {
|
||||
const contents = document.querySelectorAll('.tab-content');
|
||||
contents.forEach(content => content.classList.remove('active'));
|
||||
|
||||
const buttons = document.querySelectorAll('.tab-button');
|
||||
buttons.forEach(b => b.classList.remove('active'));
|
||||
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
button.classList.add('active');
|
||||
|
||||
if (tabId === 'content6') {
|
||||
setTimeout(initTags, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Tags Init (with custom dropdown autocomplete)
|
||||
let tagsListeners = [];
|
||||
|
||||
function initTags() {
|
||||
const tagsInput = document.getElementById('tags-input');
|
||||
const tagsField = document.getElementById('tags');
|
||||
const hiddenTags = document.getElementById('tags_json');
|
||||
const dropdown = document.getElementById('tags-dropdown');
|
||||
|
||||
if (!tagsInput || !tagsField || !hiddenTags || !dropdown) {
|
||||
console.warn('Tags elements missing');
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove old listeners
|
||||
tagsListeners.forEach(ls => ls());
|
||||
tagsListeners = [];
|
||||
|
||||
let tags = [];
|
||||
let existingTags = [];
|
||||
try {
|
||||
tags = JSON.parse(tagsInput.dataset.tags || '[]');
|
||||
existingTags = JSON.parse(tagsInput.dataset.existingTags || '[]');
|
||||
} catch (e) {
|
||||
console.warn('JSON error:', e);
|
||||
}
|
||||
|
||||
let selectedIndex = -1;
|
||||
|
||||
function renderTags() {
|
||||
tagsInput.innerHTML = '';
|
||||
tags.forEach((tag, index) => {
|
||||
const chip = document.createElement('span');
|
||||
chip.className = 'tag-chip';
|
||||
chip.innerHTML = `${tag} <button type="button" class="tag-remove">×</button>`;
|
||||
chip.querySelector('.tag-remove').onclick = () => {
|
||||
tags.splice(index, 1);
|
||||
renderTags();
|
||||
hiddenTags.value = JSON.stringify(tags);
|
||||
};
|
||||
tagsInput.appendChild(chip);
|
||||
});
|
||||
tagsInput.appendChild(tagsField);
|
||||
tagsInput.appendChild(dropdown);
|
||||
hiddenTags.value = JSON.stringify(tags);
|
||||
}
|
||||
|
||||
function updateDropdown() {
|
||||
const value = tagsField.value.toLowerCase().trim();
|
||||
dropdown.innerHTML = '';
|
||||
dropdown.setAttribute('aria-expanded', value ? 'true' : 'false');
|
||||
selectedIndex = -1;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
const matches = existingTags
|
||||
.filter(tag => tag.toLowerCase().startsWith(value) && !tags.includes(tag.toLowerCase()))
|
||||
.slice(0, 10);
|
||||
|
||||
matches.forEach((tag, index) => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = tag;
|
||||
li.setAttribute('role', 'option');
|
||||
li.onclick = () => selectTag(tag);
|
||||
li.onmouseover = () => { selectedIndex = index; updateHighlight(); };
|
||||
dropdown.appendChild(li);
|
||||
});
|
||||
|
||||
if (matches.length) dropdown.parentElement.classList.add('has-dropdown');
|
||||
else dropdown.parentElement.classList.remove('has-dropdown');
|
||||
}
|
||||
|
||||
function updateHighlight() {
|
||||
dropdown.querySelectorAll('li').forEach((li, index) => {
|
||||
li.classList.toggle('selected', index === selectedIndex);
|
||||
});
|
||||
}
|
||||
|
||||
function selectTag(tag) {
|
||||
addTag(tag, true);
|
||||
tagsField.value = '';
|
||||
dropdown.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
function addTag(inputValue, refocus = false) {
|
||||
const tag = inputValue.trim().toLowerCase().replace(/[^\w-]/g, '');
|
||||
if (tag && tag.length > 0 && tag.length <= 50 && !tags.includes(tag)) {
|
||||
tags.push(tag);
|
||||
renderTags();
|
||||
if (refocus) tagsField.focus();
|
||||
}
|
||||
tagsField.value = '';
|
||||
updateDropdown();
|
||||
}
|
||||
|
||||
const keydownListener = (e) => {
|
||||
if (dropdown.getAttribute('aria-expanded') === 'true') {
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.min(selectedIndex + 1, dropdown.querySelectorAll('li').length - 1);
|
||||
updateHighlight();
|
||||
dropdown.querySelector(`li:nth-child(${selectedIndex + 1})`)?.scrollIntoView({ block: 'nearest' });
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = Math.max(selectedIndex - 1, 0);
|
||||
updateHighlight();
|
||||
dropdown.querySelector(`li:nth-child(${selectedIndex + 1})`)?.scrollIntoView({ block: 'nearest' });
|
||||
} else if ((e.key === 'Enter' || e.key === 'Tab') && selectedIndex >= 0) {
|
||||
e.preventDefault();
|
||||
const selected = dropdown.querySelector(`li:nth-child(${selectedIndex + 1})`)?.textContent;
|
||||
if (selected) selectTag(selected);
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
tagsField.blur();
|
||||
}
|
||||
}
|
||||
|
||||
if (!dropdown.getAttribute('aria-expanded') === 'true' || selectedIndex < 0) {
|
||||
if (e.key === 'Enter' || e.key === ',') {
|
||||
e.preventDefault();
|
||||
addTag(tagsField.value, true);
|
||||
} else if (e.key === 'Tab') {
|
||||
e.preventDefault();
|
||||
if (tagsField.value.trim()) addTag(tagsField.value, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tagsField.addEventListener('keydown', keydownListener);
|
||||
tagsListeners.push(() => tagsField.removeEventListener('keydown', keydownListener));
|
||||
|
||||
const inputListener = () => updateDropdown();
|
||||
tagsField.addEventListener('input', inputListener);
|
||||
tagsListeners.push(() => tagsField.removeEventListener('input', inputListener));
|
||||
|
||||
const blurListener = () => {
|
||||
setTimeout(() => dropdown.setAttribute('aria-expanded', 'false'), 150);
|
||||
if (tagsField.value.trim()) addTag(tagsField.value);
|
||||
};
|
||||
tagsField.addEventListener('blur', blurListener);
|
||||
tagsListeners.push(() => tagsField.removeEventListener('blur', blurListener));
|
||||
|
||||
renderTags();
|
||||
}
|
||||
|
||||
// Init on load and observe tab changes
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const tagsTab = document.getElementById('content6');
|
||||
if (tagsTab?.classList.contains('active')) {
|
||||
initTags();
|
||||
}
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
||||
const target = mutation.target;
|
||||
if (target.id === 'content6' && target.classList.contains('active')) {
|
||||
initTags();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(document.body, { subtree: true, attributes: true });
|
||||
});
|
||||
|
||||
// Export switchTab for external use if needed
|
||||
window.switchTab = switchTab;
|
||||
@@ -75,7 +75,7 @@ class Router {
|
||||
|
||||
foreach ($this->routes as $key => $value) {
|
||||
// Check if key contains a curly bracket, if not continue. We already checked above.
|
||||
if (!strpos($key, '{')) continue;
|
||||
if (strpos($key, '{') === false) continue;
|
||||
|
||||
// Remove everything after the curly bracket, from key
|
||||
$keyPath = substr($key, 0, strpos($key, '{'));
|
||||
|
||||
@@ -17,6 +17,8 @@ $log = new Logger(\BASEPATH . $config['logfile'], $config['loglevel']);
|
||||
// --- Twig Data Array ---
|
||||
$data = [];
|
||||
$data['fonts'] = $config['fonts'] ?? [];
|
||||
$data['matomo_url'] = $config['matomo_url'] ?? '';
|
||||
$data['matomo_id'] = $config['matomo_id'] ?? '0';
|
||||
|
||||
// --- Session ---
|
||||
use Novaconium\Session;
|
||||
|
||||
71
twig/coming-soon/index.html.twig
Normal file
71
twig/coming-soon/index.html.twig
Normal file
@@ -0,0 +1,71 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ title | default('Coming Soon') }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/css/novaconium.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
body {
|
||||
background: url("{{ bg_image | default('https://w.wallhaven.cc/full/5y/wallhaven-5yymk9.jpg') }}") no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body id="coming-soon">
|
||||
<div class="container">
|
||||
<h1>{{ heading | default('Coming Soon') }}</h1>
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
{% if countdown %}
|
||||
<div class="countdown" id="countdown"></div>
|
||||
{% endif %}
|
||||
|
||||
{# TODO: listmonk #}
|
||||
<form class="newsletter" action="#" method="post">
|
||||
<label for="email">Subscribe to our newsletter:</label>
|
||||
<input type="email" id="email" name="email" placeholder="Your email address" required>
|
||||
<button type="submit">Subscribe</button>
|
||||
</form>
|
||||
|
||||
{# Social media icons using Font Awesome #}
|
||||
<div class="social-icons">
|
||||
{% block social %}{% endblock %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if countdown %}
|
||||
<script>
|
||||
{% if countdown %}
|
||||
{% set default_launch = "now"|date_modify("+30 days")|date("Y-m-d\TH:i:s") %}
|
||||
const launchDate = new Date('{{ launch_date | default(default_launch) }}').getTime();
|
||||
const countdownEl = document.getElementById('countdown');
|
||||
|
||||
function updateCountdown() {
|
||||
const now = new Date().getTime();
|
||||
const distance = launchDate - now;
|
||||
|
||||
if (distance <= 0) {
|
||||
countdownEl.innerText = 'Launched!';
|
||||
return;
|
||||
}
|
||||
|
||||
const days = Math.floor(distance / (1000*60*60*24));
|
||||
const hours = Math.floor((distance % (1000*60*60*24)) / (1000*60*60));
|
||||
const mins = Math.floor((distance % (1000*60*60)) / (1000*60));
|
||||
const secs = Math.floor((distance % (1000*60)) / 1000);
|
||||
|
||||
countdownEl.innerText = `${days}d ${hours}h ${mins}m ${secs}s`;
|
||||
}
|
||||
|
||||
updateCountdown();
|
||||
setInterval(updateCountdown, 1000);
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
<html class="no-js" lang="en">
|
||||
|
||||
<head>
|
||||
{% include ['@override/head.html.twig', '@novaconium/head.html.twig'] %}
|
||||
{% include ['@novaconium/cp/head.html.twig'] %}
|
||||
</head>
|
||||
|
||||
<body id="{{ pageid | default('pageid') }}" class="{{ pageclass | default('pageclass') }}" >
|
||||
@@ -28,12 +28,12 @@
|
||||
<div class="copyright">© {{ 'now' | date('Y') }} Novaconium</div>
|
||||
</footer>
|
||||
|
||||
{% include '@novaconium/javascript/page-edit.html.twig' %}
|
||||
|
||||
{% if editor == 'ace' %}
|
||||
{% include '@novaconium/javascript/page-edit.html.twig' %}
|
||||
{% include '@novaconium/javascript/ace.html.twig' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if debug is not empty %}
|
||||
<div id="debug">
|
||||
<h2>Debugging Information</h2>
|
||||
|
||||
60
twig/cp/head.html.twig
Normal file
60
twig/cp/head.html.twig
Normal file
@@ -0,0 +1,60 @@
|
||||
{# =============================================================================
|
||||
<HEAD>
|
||||
=============================================================================
|
||||
#}
|
||||
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>{{ title | default('Welcome To Novaconium') }}</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{# SEO & METADATA #}
|
||||
<meta name="generator" content="Novaconium" />
|
||||
<meta name="description" content="{{ description | default('No description given') }}">
|
||||
<meta name="keywords" content="{{ keywords | default('website') }}">
|
||||
<meta name="author" content="{{ author | default('anonymous') }}">
|
||||
|
||||
{# DARK MODE & THEME HINTS #}
|
||||
<meta name="color-scheme" content="dark">
|
||||
<meta name="theme-color" content="#000000">
|
||||
|
||||
{# OPEN GRAPH (OG) FOR SOCIAL SHARING #}
|
||||
<meta property="og:title" content="{{ title | default('Welcome') }}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ app_url | default(request.scheme ~ '://' ~ request.host) }}">
|
||||
<meta property="og:image" content="{{ og_image | default('/icon.png') }}">
|
||||
|
||||
{# PWA & FAVICONS #}
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="apple-touch-icon" href="/icon.png">
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
|
||||
{# GOOGLE FONTS (CDN VIA PRECONNECT) #}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="{{ fonts | default('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=Roboto+Mono&family=Source+Code+Pro&family=Lato&family=Poppins&family=Material+Icons&family=Material+Icons+Outlined&family=VT323:wght@400&family=Fira+Code:wght@400;500&display=swap') }}"
|
||||
rel="stylesheet"
|
||||
>
|
||||
|
||||
{% if editor == 'ace' %}
|
||||
<!-- ACE Editor -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ace.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/mode-html.min.js"></script> {# HTML syntax #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/theme-tomorrow_night.min.js"></script> {# Dark theme #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ext-language_tools.min.js"></script> {# Autocomplete #}
|
||||
<!-- END ACE Editor -->
|
||||
{% endif %}
|
||||
|
||||
{# highlight.js #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<script>hljs.highlightAll();</script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/ir-black.min.css">
|
||||
|
||||
<script src="/js/tabs.js"></script>
|
||||
|
||||
{# STYLESHEET #}
|
||||
<link rel="stylesheet" href="/css/novaconium.css">
|
||||
@@ -1,11 +1,5 @@
|
||||
<!--
|
||||
What goes very last on the page.
|
||||
right before the /body
|
||||
like javascript
|
||||
or analytics
|
||||
such as javascript
|
||||
-->
|
||||
{% include '@novaconium/javascript/page-edit.html.twig' %}
|
||||
|
||||
{% if editor == 'ace' %}
|
||||
{% include '@novaconium/javascript/ace.html.twig' %}
|
||||
{% endif %}
|
||||
|
||||
@@ -39,22 +39,7 @@
|
||||
>
|
||||
|
||||
{# STYLESHEET #}
|
||||
{% if pageclass == "novaconium" %}
|
||||
<link rel="stylesheet" href="/css/novaconium.css">
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if editor == 'ace' %}
|
||||
<!-- ACE Editor -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ace.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/mode-html.min.js"></script> {# HTML syntax #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/theme-tomorrow_night.min.js"></script> {# Dark theme #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.35.2/ext-language_tools.min.js"></script> {# Autocomplete #}
|
||||
<!-- END ACE Editor -->
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
|
||||
{# highlight.js #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
|
||||
@@ -60,4 +60,32 @@
|
||||
{% endif %}
|
||||
|
||||
{% include ['@override/foot.html.twig', '@novaconium/foot.html.twig'] %}
|
||||
{% if matomo_id > 0 %}
|
||||
<!-- Matomo -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
|
||||
{% if is_404 %}
|
||||
_paq.push([
|
||||
'setDocumentTitle',
|
||||
'404 / Not Found - ' + document.location.pathname
|
||||
]);
|
||||
{% endif %}
|
||||
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
|
||||
(function() {
|
||||
var u = "//{{ matomo_url|trim('/') }}/";
|
||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
||||
_paq.push(['setSiteId', {{ matomo_id }}]);
|
||||
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
||||
g.async = true;
|
||||
g.src = u + 'matomo.js';
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
</script>
|
||||
<!-- End Matomo Code -->
|
||||
{% endif %}
|
||||
|
||||
</body></html>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% set is_404 = status_code is defined and status_code == 404 %}
|
||||
{% extends '@novaconium/master.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
32
views/coming-soon.html.twig
Normal file
32
views/coming-soon.html.twig
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends '@novaconium/coming-soon/index.html.twig' %}
|
||||
|
||||
{% set bg_image = "https://i.4lt.ca/4lt/waterBubbles.webp" %}
|
||||
{% set default_launch = "now"|date_modify("+30 days")|date("Y-m-d\TH:i:s") %}
|
||||
|
||||
{% block content %}
|
||||
<p>Our website is under construction. We’re working hard to bring you a better experience.</p>
|
||||
<p>Stay tuned for updates!</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block social %}
|
||||
<a href="mailto:you@example.com" title="Email">
|
||||
<i class="fa-solid fa-envelope"></i>
|
||||
</a>
|
||||
|
||||
<a href="tel:+1234567890" title="Phone">
|
||||
<i class="fa-solid fa-phone"></i>
|
||||
</a>
|
||||
|
||||
<a href="#" title="Twitter">
|
||||
<i class="fab fa-twitter"></i>
|
||||
</a>
|
||||
|
||||
<a href="#" title="Facebook">
|
||||
<i class="fab fa-facebook-f"></i>
|
||||
</a>
|
||||
|
||||
<a href="#" title="Instagram">
|
||||
<i class="fab fa-instagram"></i>
|
||||
</a>
|
||||
|
||||
{% endblock %}
|
||||
@@ -14,3 +14,16 @@
|
||||
<div id="body-editor" class="ace-editor"></div> {# Ace mounts here #}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="draft">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="draft"
|
||||
name="draft"
|
||||
value="1"
|
||||
{% if rows.draft|default(false) %}checked{% endif %}
|
||||
>
|
||||
Save as draft
|
||||
</label>
|
||||
</div>
|
||||
Reference in New Issue
Block a user