mirror of
git://f0xx.org/android_cast
synced 2026-07-29 03:38:52 +03:00
Shared platform footer template for hub and all PHP consoles.
Centralize copyright in examples/platform/footer.config.php, render via footer.php in crashes/builder/login layouts, and serve hub through index.php. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,9 +16,13 @@ Browser → apps.f0xx.org (Gentoo FE, TLS)
|
|||||||
|
|
||||||
On FE, hub and (if you fix it) crashes should both target **`http://artc0.intra.raptor.org:80`**, same as `location /`.
|
On FE, hub and (if you fix it) crashes should both target **`http://artc0.intra.raptor.org:80`**, same as `location /`.
|
||||||
|
|
||||||
## 1. `index.html` + hub assets
|
## 1. Hub entry (`index.php`) + assets
|
||||||
|
|
||||||
|
Landing uses **`index.php`** (shared footer from `examples/platform/footer.config.php`). Copy **`index.html`** only as a redirect fallback.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cp .../android_cast/examples/app_hub/index.php \
|
||||||
|
.../htdocs/apps/app/androidcast_project/index.php
|
||||||
cp .../android_cast/examples/app_hub/index.html \
|
cp .../android_cast/examples/app_hub/index.html \
|
||||||
.../htdocs/apps/app/androidcast_project/index.html
|
.../htdocs/apps/app/androidcast_project/index.html
|
||||||
cp .../android_cast/examples/app_hub/hub.css \
|
cp .../android_cast/examples/app_hub/hub.css \
|
||||||
@@ -68,7 +72,7 @@ Use prefix location for the hub (not `alias` to a single file):
|
|||||||
```nginx
|
```nginx
|
||||||
location /app/androidcast_project/ {
|
location /app/androidcast_project/ {
|
||||||
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
||||||
index index.html;
|
index index.php index.html;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1093
examples/app_hub/index.php
Normal file
1093
examples/app_hub/index.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
$examplesRoot = dirname(__DIR__, 3);
|
$examplesRoot = dirname(__DIR__, 3);
|
||||||
require_once $examplesRoot . '/platform/shared_session.php';
|
require_once $examplesRoot . '/platform/shared_session.php';
|
||||||
|
require_once $examplesRoot . '/platform/footer.php';
|
||||||
|
|
||||||
$crashSrc = $examplesRoot . '/crash_reporter/backend/src';
|
$crashSrc = $examplesRoot . '/crash_reporter/backend/src';
|
||||||
$configPath = __DIR__ . '/../config/config.php';
|
$configPath = __DIR__ . '/../config/config.php';
|
||||||
|
|||||||
@@ -53,6 +53,6 @@ $links = cfg('links', []);
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<footer class="bottom-bar">(c) Anton Afanaasyeu, <?= (int) date('Y') ?></footer>
|
<?php platform_render_footer(); ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -21,5 +21,6 @@ $ab = assets_base();
|
|||||||
<label><span>Password</span><input name="password" type="password" autocomplete="current-password" required></label>
|
<label><span>Password</span><input name="password" type="password" autocomplete="current-password" required></label>
|
||||||
<button type="submit">Sign in</button>
|
<button type="submit">Sign in</button>
|
||||||
</form>
|
</form>
|
||||||
|
<?php platform_render_footer(); ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -9,9 +9,21 @@ server {
|
|||||||
return 301 /app/androidcast_project/;
|
return 301 /app/androidcast_project/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/index.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/index.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/ {
|
||||||
|
rewrite ^ /app/androidcast_project/index.php last;
|
||||||
|
}
|
||||||
|
|
||||||
location /app/androidcast_project/ {
|
location /app/androidcast_project/ {
|
||||||
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
||||||
index index.html;
|
index index.php index.html;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location = /app/androidcast_project/crashes {
|
location = /app/androidcast_project/crashes {
|
||||||
|
|||||||
@@ -13,10 +13,22 @@
|
|||||||
return 301 /app/androidcast_project/;
|
return 301 /app/androidcast_project/;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Hub — live vhost is listen 80 on BE (see nginx.apps-port80.fragment). Not :8089.
|
# Hub — see nginx.apps-port80.fragment (index.php + shared footer).
|
||||||
|
location = /app/androidcast_project/index.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/index.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/ {
|
||||||
|
rewrite ^ /app/androidcast_project/index.php last;
|
||||||
|
}
|
||||||
|
|
||||||
location /app/androidcast_project/ {
|
location /app/androidcast_project/ {
|
||||||
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
||||||
index index.html;
|
index index.php index.html;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /app/androidcast_project/crashes/assets/ {
|
location ^~ /app/androidcast_project/crashes/assets/ {
|
||||||
|
|||||||
@@ -30,9 +30,21 @@ server {
|
|||||||
return 301 /app/androidcast_project/;
|
return 301 /app/androidcast_project/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/index.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/index.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/index.php;
|
||||||
|
}
|
||||||
|
|
||||||
location = /app/androidcast_project/ {
|
location = /app/androidcast_project/ {
|
||||||
|
rewrite ^ /app/androidcast_project/index.php last;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /app/androidcast_project/ {
|
||||||
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
alias /var/www/localhost/htdocs/apps/app/androidcast_project/;
|
||||||
index index.html;
|
index index.php index.html;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /app/androidcast_project/crashes/assets/ {
|
location ^~ /app/androidcast_project/crashes/assets/ {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
require_once dirname(__DIR__, 3) . '/platform/shared_session.php';
|
require_once dirname(__DIR__, 3) . '/platform/shared_session.php';
|
||||||
|
require_once dirname(__DIR__, 3) . '/platform/footer.php';
|
||||||
|
|
||||||
if (!function_exists('session_start')) {
|
if (!function_exists('session_start')) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
|
|||||||
@@ -340,6 +340,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<footer class="bottom-bar" data-i18n="footer.copyright" data-year="<?= (int) date('Y') ?>">(c) Anton Afanaasyeu, <?= (int) date('Y') ?></footer>
|
<?php platform_render_footer(); ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -51,5 +51,6 @@ $bp = Auth::basePath();
|
|||||||
<p class="hint" data-i18n="login.hint_default">Default: admin / admin</p>
|
<p class="hint" data-i18n="login.hint_default">Default: admin / admin</p>
|
||||||
<p class="hint"><span data-i18n="login.register">Register</span> <span data-i18n="login.register_soon">(coming soon)</span></p>
|
<p class="hint"><span data-i18n="login.register">Register</span> <span data-i18n="login.register_soon">(coming soon)</span></p>
|
||||||
</form>
|
</form>
|
||||||
|
<?php platform_render_footer(); ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
27
examples/platform/README.md
Normal file
27
examples/platform/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Shared platform pieces
|
||||||
|
|
||||||
|
## Footer (`footer.php`)
|
||||||
|
|
||||||
|
Single copyright footer for hub, crashes, tickets, graphs, and builder consoles.
|
||||||
|
|
||||||
|
**Configure:** edit `footer.config.php` (copy from `footer.config.example.php`).
|
||||||
|
|
||||||
|
| Key | Purpose |
|
||||||
|
|-----|---------|
|
||||||
|
| `holder` | Copyright name |
|
||||||
|
| `copyright_symbol` | `(c)` or `©` |
|
||||||
|
| `show_year` | Append year |
|
||||||
|
| `year` | Fixed year, or `null` for current |
|
||||||
|
| `use_i18n` | `data-i18n` for consoles with `i18n.js` |
|
||||||
|
|
||||||
|
**In PHP views:** `<?php platform_render_footer(); ?>` (loaded via each app `bootstrap.php`).
|
||||||
|
|
||||||
|
**Hub:** `examples/app_hub/index.php` (landing nginx runs it through PHP-FPM).
|
||||||
|
|
||||||
|
**Static HTML export:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php examples/platform/scripts/render-footer-html.php
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gitea** (`/git/`) uses the upstream Gitea UI; this footer does not apply there unless you customize Gitea templates separately.
|
||||||
22
examples/platform/footer.config.example.php
Normal file
22
examples/platform/footer.config.example.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Site-wide footer (hub, crashes, tickets, graphs, builder).
|
||||||
|
* Copy to footer.config.php and edit; footer.config.php is optional (defaults apply).
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
// Visible copyright holder (also used in i18n {holder} if you customize strings).
|
||||||
|
'holder' => 'Anton Afanaasyeu',
|
||||||
|
// Prefix before the name: "(c)", "©", or "".
|
||||||
|
'copyright_symbol' => '(c)',
|
||||||
|
// Append current calendar year (or fixed year below).
|
||||||
|
'show_year' => true,
|
||||||
|
// null = (int) date('Y') at render time.
|
||||||
|
'year' => null,
|
||||||
|
// CSS class on <footer>.
|
||||||
|
'footer_class' => 'bottom-bar',
|
||||||
|
// When true, consoles with i18n.js replace text via data-i18n / data-year.
|
||||||
|
'use_i18n' => true,
|
||||||
|
'i18n_key' => 'footer.copyright',
|
||||||
|
];
|
||||||
4
examples/platform/footer.config.php
Normal file
4
examples/platform/footer.config.php
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return require __DIR__ . '/footer.config.example.php';
|
||||||
85
examples/platform/footer.php
Normal file
85
examples/platform/footer.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared footer fragment for Android Cast web consoles and hub.
|
||||||
|
*
|
||||||
|
* Configure: examples/platform/footer.config.php (see footer.config.example.php).
|
||||||
|
* Usage: <?php platform_render_footer(); ?> or platform_render_footer(['use_i18n' => false]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
function platform_footer_h(mixed $value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
function platform_footer_config(): array
|
||||||
|
{
|
||||||
|
static $loaded = null;
|
||||||
|
if ($loaded !== null) {
|
||||||
|
return $loaded;
|
||||||
|
}
|
||||||
|
$path = __DIR__ . '/footer.config.php';
|
||||||
|
if (!is_file($path)) {
|
||||||
|
$path = __DIR__ . '/footer.config.example.php';
|
||||||
|
}
|
||||||
|
$loaded = require $path;
|
||||||
|
return is_array($loaded) ? $loaded : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function platform_footer_year(array $cfg): int
|
||||||
|
{
|
||||||
|
if (array_key_exists('year', $cfg) && $cfg['year'] !== null) {
|
||||||
|
return (int) $cfg['year'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) date('Y');
|
||||||
|
}
|
||||||
|
|
||||||
|
function platform_footer_plain_text(array $cfg, int $year): string
|
||||||
|
{
|
||||||
|
$symbol = trim((string) ($cfg['copyright_symbol'] ?? '(c)'));
|
||||||
|
$holder = trim((string) ($cfg['holder'] ?? ''));
|
||||||
|
$showYear = (bool) ($cfg['show_year'] ?? true);
|
||||||
|
$parts = [];
|
||||||
|
if ($symbol !== '') {
|
||||||
|
$parts[] = $symbol;
|
||||||
|
}
|
||||||
|
if ($holder !== '') {
|
||||||
|
$parts[] = $holder;
|
||||||
|
}
|
||||||
|
$line = implode(' ', $parts);
|
||||||
|
if ($showYear && $line !== '') {
|
||||||
|
return $line . ', ' . $year;
|
||||||
|
}
|
||||||
|
if ($showYear && $line === '') {
|
||||||
|
return (string) $year;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array{use_i18n?: bool, extra_class?: string} $opts
|
||||||
|
*/
|
||||||
|
function platform_render_footer(array $opts = []): void
|
||||||
|
{
|
||||||
|
$cfg = platform_footer_config();
|
||||||
|
$year = platform_footer_year($cfg);
|
||||||
|
$text = platform_footer_plain_text($cfg, $year);
|
||||||
|
$class = (string) ($opts['extra_class'] ?? ($cfg['footer_class'] ?? 'bottom-bar'));
|
||||||
|
$useI18n = $opts['use_i18n'] ?? (bool) ($cfg['use_i18n'] ?? true);
|
||||||
|
$i18nKey = (string) ($cfg['i18n_key'] ?? 'footer.copyright');
|
||||||
|
|
||||||
|
if ($useI18n && $i18nKey !== '') {
|
||||||
|
echo '<footer class="' . platform_footer_h($class) . '"'
|
||||||
|
. ' data-i18n="' . platform_footer_h($i18nKey) . '"'
|
||||||
|
. ' data-year="' . $year . '">'
|
||||||
|
. platform_footer_h($text)
|
||||||
|
. '</footer>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<footer class="' . platform_footer_h($class) . '">' . platform_footer_h($text) . '</footer>';
|
||||||
|
}
|
||||||
16
examples/platform/scripts/render-footer-html.php
Normal file
16
examples/platform/scripts/render-footer-html.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a static footer.html from footer.config.php (for docs or static-only hosts).
|
||||||
|
*
|
||||||
|
* php examples/platform/scripts/render-footer-html.php > /path/to/footer.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/footer.php';
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
platform_render_footer(['use_i18n' => false]);
|
||||||
|
$footer = ob_get_clean();
|
||||||
|
|
||||||
|
echo $footer . "\n";
|
||||||
@@ -44,9 +44,20 @@ server {
|
|||||||
add_header Cache-Control "public, max-age=60";
|
add_header Cache-Control "public, max-age=60";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/index.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /workspace/examples/app_hub/index.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/index.php;
|
||||||
|
fastcgi_pass crash-php:9000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/ {
|
||||||
|
rewrite ^ /app/androidcast_project/index.php last;
|
||||||
|
}
|
||||||
|
|
||||||
location /app/androidcast_project/ {
|
location /app/androidcast_project/ {
|
||||||
alias /workspace/examples/app_hub/;
|
alias /workspace/examples/app_hub/;
|
||||||
index index.html;
|
index index.php index.html;
|
||||||
try_files $uri $uri/ /app/androidcast_project/index.html;
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user