views/partials/layout_end.php
1 </div><!-- /.wrap -->
2 </main>
3
4 <?php $stats = forum_stats(); ?>
5 <footer class="site-footer">
6 <div class="footer-inner">
7 <div class="footer-stats">
8 <span title="Topics">๐ฌ <strong><?= number_format($stats['topics']) ?></strong> topics</span>
9 <span class="fs-div">ยท</span>
10 <span title="Posts">๐ <strong><?= number_format($stats['posts']) ?></strong> posts</span>
11 <span class="fs-div">ยท</span>
12 <span title="Members">๐ฅ <strong><?= number_format($stats['users']) ?></strong> members</span>
13 <span class="fs-div">ยท</span>
14 <span title="Online now">๐ข <strong><?= $stats['online'] ?></strong> online</span>
15 <?php if ($stats['newest']): ?>
16 <span class="fs-div">ยท</span>
17 <span>Newest: <a href="<?= u('users/profile.php?u='.urlencode($stats['newest']['username'])) ?>">@<?= e($stats['newest']['username']) ?></a></span>
18 <?php endif; ?>
19 </div>
20 <div class="footer-right">
21 <span><?= e(cfg('site_name','Nexus Forum')) ?></span>
22 <?php if ($USER && is_admin()): ?>
23 <a href="<?= u('admin/') ?>">Admin</a>
24 <?php endif; ?>
25 </div>
26 </div>
27 </footer>
28
29 <script>
30 var NX = {
31 base: '<?= BASE ?>',
32 csrf: '<?= csrf() ?>',
33 maxUploadMb: <?= (int)(cfg('max_upload_mb', '5')) ?>,
34 user: <?= $USER ? json_encode(['id'=>(int)$USER['id'],'name'=>$USER['username'],'role'=>$USER['role']]) : 'null' ?>
35 };
36 </script>
37 <!-- Prism.js syntax tokenizer โ loaded lazily only when a code block with a language exists -->
38 <!-- We use our own token color theme from main.css, NOT Prism's default theme CSS -->
39 <script>
40 (function(){
41 if (!document.querySelector('.code-block-wrap pre.code-block code[class]')) return;
42 // Load Prism core + autoloader (no theme CSS โ we provide our own via main.css)
43 var s = document.createElement('script');
44 s.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js';
45 s.onload = function() {
46 var a = document.createElement('script');
47 a.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js';
48 a.onload = function() {
49 // Autoloader path for language components
50 if (Prism.plugins && Prism.plugins.autoloader) {
51 Prism.plugins.autoloader.languages_path =
52 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/';
53 }
54 Prism.highlightAll();
55 };
56 document.body.appendChild(a);
57 };
58 document.body.appendChild(s);
59 })();
60 </script>
61 <script src="<?= asset('js/app.js') ?>"></script>
62
63 <script>
64 /* โโ Dark mode โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
65 (function(){
66 var stored = localStorage.getItem('nexus-theme');
67 var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme:dark)').matches;
68 var dark = stored ? stored === 'dark' : prefersDark;
69 if (dark) document.documentElement.setAttribute('data-theme','dark');
70 updateThemeIcons(dark);
71 })();
72
73 function toggleTheme(){
74 var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
75 var newDark = !isDark;
76 if (newDark) {
77 document.documentElement.setAttribute('data-theme','dark');
78 localStorage.setItem('nexus-theme','dark');
79 } else {
80 document.documentElement.removeAttribute('data-theme');
81 localStorage.setItem('nexus-theme','light');
82 }
83 updateThemeIcons(newDark);
84 }
85
86 function updateThemeIcons(dark){
87 var light = document.querySelector('.theme-icon-light');
88 var moon = document.querySelector('.theme-icon-dark');
89 if (light) light.style.display = dark ? 'none' : '';
90 if (moon) moon.style.display = dark ? '' : 'none';
91 }
92 </script>
93
94 </body>
95 </html>