Compare commits
2 commits
e106ee4c4c
...
f3b60adb21
Author | SHA1 | Date | |
---|---|---|---|
f3b60adb21 | |||
315f7e9896 |
7 changed files with 305 additions and 2 deletions
18
.gitignore
vendored
18
.gitignore
vendored
|
@ -14,6 +14,9 @@ Icon
|
|||
# ---------------
|
||||
|
||||
.lock
|
||||
#Remove the next two line for real project repositories
|
||||
composer.lock
|
||||
package-lock.json
|
||||
|
||||
# Editors
|
||||
# (sensitive workspace files)
|
||||
|
@ -49,3 +52,18 @@ Icon
|
|||
|
||||
/site/config/.license
|
||||
|
||||
# Vendor
|
||||
# ---------------
|
||||
|
||||
/vendor
|
||||
/node_modules
|
||||
|
||||
# Content
|
||||
# ---------------
|
||||
|
||||
/content
|
||||
|
||||
# Compiled files
|
||||
# ---------------
|
||||
|
||||
/public/css
|
|
@ -6,7 +6,7 @@
|
|||
"kirby",
|
||||
"cms",
|
||||
"starterkit",
|
||||
"tailwindcss
|
||||
"tailwindcss"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
|
@ -23,7 +23,8 @@
|
|||
},
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
|
||||
"getkirby/cms": "^5.0"
|
||||
"getkirby/cms": "^5.0",
|
||||
"ext-pcntl": "*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
|
18
package.json
Normal file
18
package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "kirby-moin",
|
||||
"version": "1.0.0",
|
||||
"description": "Watch and build tailwindcss",
|
||||
"scripts": {
|
||||
"watch": "npx @tailwindcss/cli -i ./src/css/tailwind.css -o ./public/css/app.css --content './site/**/*.php' -w",
|
||||
"build": "npx @tailwindcss/cli -i ./src/css/tailwind.css -o ./public/css/app.css --content './site/**/*.php' -m"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@deichrakete.space/deichrakete/kirby-moin.git"
|
||||
},
|
||||
"author": "Stephan Plöhn",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4.1.12"
|
||||
}
|
||||
}
|
208
site/commands/serve.php
Normal file
208
site/commands/serve.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'description' => 'Run Kirby dev server and Tailwind watcher',
|
||||
'command' => static function ($cli): void {
|
||||
$cwd = getcwd();
|
||||
|
||||
// Resolve paths
|
||||
$router = $cwd . '/vendor/getkirby/cms/router.php';
|
||||
$docroot = $cli->arg('docroot') ?? 'public';
|
||||
$docrootPath = $cwd . '/' . $docroot;
|
||||
|
||||
// Basic checks
|
||||
if (!is_file($router)) {
|
||||
$cli->error('Kirby router not found. Make sure dependencies are installed: vendor/getkirby/cms/router.php');
|
||||
return;
|
||||
}
|
||||
if (!is_dir($docrootPath)) {
|
||||
$cli->error("Document root not found: {$docrootPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper function to check if a port is available
|
||||
$isPortAvailable = function (string $host, int $port): bool {
|
||||
$socket = @fsockopen($host, $port, $errno, $errstr, 1);
|
||||
if ($socket) {
|
||||
fclose($socket);
|
||||
return false; // Port is occupied
|
||||
}
|
||||
return true; // Port is available
|
||||
};
|
||||
|
||||
$host = 'localhost';
|
||||
$startPort = 8000;
|
||||
$maxPort = 8100;
|
||||
$port = $startPort;
|
||||
|
||||
while ($port <= $maxPort) {
|
||||
if ($isPortAvailable($host, $port)) {
|
||||
break;
|
||||
}
|
||||
$port++;
|
||||
}
|
||||
|
||||
if ($port > $maxPort) {
|
||||
$cli->error("No available ports found between {$startPort} and {$maxPort}");
|
||||
return;
|
||||
}
|
||||
|
||||
$cli->info("Using port {$port} for PHP dev server");
|
||||
|
||||
$phpCmd = sprintf(
|
||||
'php -S %s:%s -t %s %s',
|
||||
escapeshellarg($host),
|
||||
escapeshellarg($port),
|
||||
escapeshellarg($docrootPath),
|
||||
escapeshellarg($router)
|
||||
);
|
||||
|
||||
$npmCmd = 'npm run watch';
|
||||
|
||||
$cli->info("Starting PHP dev server on http://{$host}:{$port} (docroot: {$docroot})");
|
||||
|
||||
// Helper to start a process with pipes
|
||||
$start = static function (string $cmd) use ($cwd) {
|
||||
$descriptorSpec = [
|
||||
0 => ['pipe', 'r'], // stdin
|
||||
1 => ['pipe', 'w'], // stdout
|
||||
2 => ['pipe', 'w'], // stderr
|
||||
];
|
||||
|
||||
$proc = proc_open($cmd, $descriptorSpec, $pipes, $cwd);
|
||||
|
||||
if (!is_resource($proc)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Non-blocking I/O
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
|
||||
return [
|
||||
'proc' => $proc,
|
||||
'pipes' => $pipes,
|
||||
'cmd' => $cmd,
|
||||
];
|
||||
};
|
||||
|
||||
$processes = [];
|
||||
|
||||
$phpProc = $start($phpCmd);
|
||||
if ($phpProc === null) {
|
||||
$cli->error('Failed to start PHP dev server.');
|
||||
return;
|
||||
}
|
||||
$processes['php'] = $phpProc;
|
||||
|
||||
$npmProc = $start($npmCmd);
|
||||
if ($npmProc === null) {
|
||||
$cli->warning('Could not start npm watcher. Is Node/npm installed and in your PATH?');
|
||||
} else {
|
||||
$processes['npm'] = $npmProc;
|
||||
}
|
||||
|
||||
// Graceful termination
|
||||
$terminateAll = static function () use (&$processes, $cli): void {
|
||||
$cli->line("");
|
||||
foreach ($processes as $name => $p) {
|
||||
// Check if the resource is still valid before calling proc_get_status
|
||||
if (is_resource($p['proc'])) {
|
||||
$status = proc_get_status($p['proc']);
|
||||
if ($status && $status['running']) {
|
||||
$cli->line("Stopping {$name}...");
|
||||
// Try graceful terminate
|
||||
@proc_terminate($p['proc']);
|
||||
}
|
||||
}
|
||||
|
||||
// Close pipes regardless of process status
|
||||
foreach ($p['pipes'] as $pipe) {
|
||||
if (is_resource($pipe)) {
|
||||
@fclose($pipe);
|
||||
}
|
||||
}
|
||||
|
||||
// Final close if the resource is still valid
|
||||
if (is_resource($p['proc'])) {
|
||||
@proc_close($p['proc']);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Ctrl+C if pcntl is available
|
||||
if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) {
|
||||
pcntl_async_signals(true);
|
||||
pcntl_signal(SIGINT, static function () use ($terminateAll) {
|
||||
$terminateAll();
|
||||
// Exit cleanly after terminating children
|
||||
exit(130);
|
||||
});
|
||||
// Optional: also handle SIGTERM
|
||||
pcntl_signal(SIGTERM, static function () use ($terminateAll) {
|
||||
$terminateAll();
|
||||
exit(143);
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure cleanup on normal shutdown
|
||||
register_shutdown_function($terminateAll);
|
||||
|
||||
// Stream outputs until all children exit
|
||||
$prefixColor = [
|
||||
'php' => fn($s) => "\033[1;34m🐘 [php]\033[0m $s",
|
||||
'npm' => fn($s) => "\033[1;32m [npm]\033[0m $s",
|
||||
];
|
||||
|
||||
while (true) {
|
||||
$running = false;
|
||||
|
||||
foreach ($processes as $name => $p) {
|
||||
// Check if the resource is still valid
|
||||
if (!is_resource($p['proc'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = proc_get_status($p['proc']);
|
||||
if (!$status) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$running = $running || $status['running'];
|
||||
|
||||
// Read stdout
|
||||
if (is_resource($p['pipes'][1])) {
|
||||
$out = @stream_get_contents($p['pipes'][1]);
|
||||
if ($out !== false && $out !== '') {
|
||||
foreach (preg_split('/\R/', rtrim($out)) as $line) {
|
||||
if ($line !== '') {
|
||||
$cli->line(($prefixColor[$name])($line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read stderr
|
||||
if (is_resource($p['pipes'][2])) {
|
||||
$err = @stream_get_contents($p['pipes'][2]);
|
||||
if ($err !== false && $err !== '') {
|
||||
foreach (preg_split('/\R/', rtrim($err)) as $line) {
|
||||
if ($line !== '') {
|
||||
$cli->error(($prefixColor[$name])($line));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$running) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Small sleep to avoid busy-waiting
|
||||
usleep(50_000);
|
||||
}
|
||||
|
||||
$cli->success('All processes exited.');
|
||||
}
|
||||
];
|
44
site/snippets/layouts/main.php
Normal file
44
site/snippets/layouts/main.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* @var Site $site
|
||||
* @var Page $page
|
||||
* @var Slot $slot
|
||||
* @var Slots $slots
|
||||
*/
|
||||
|
||||
use Kirby\Cms\Page;
|
||||
use Kirby\Cms\Site;
|
||||
use Kirby\Template\Slot;
|
||||
use Kirby\Template\Slots;
|
||||
|
||||
?>
|
||||
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>
|
||||
<?= $page->title() ?> | <?= $site->title() ?>
|
||||
</title>
|
||||
<?= css('css/app.css') ?>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>
|
||||
<a href="<?= $site->url() ?>">
|
||||
<?= $site->title() ?>
|
||||
</a>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<?= $slot ?>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
by <?= $site->title() ?>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* @var Page $page
|
||||
*/
|
||||
|
||||
use Kirby\Cms\Page;
|
||||
|
||||
?>
|
||||
|
||||
<?php snippet('layouts/main', slots: true) ?>
|
||||
|
||||
<?php slot() ?>
|
||||
<h1><?= $page->title() ?></h1>
|
||||
<?php endslot();
|
1
src/css/tailwind.css
Normal file
1
src/css/tailwind.css
Normal file
|
@ -0,0 +1 @@
|
|||
@import "tailwindcss";
|
Loading…
Add table
Add a link
Reference in a new issue