Files
Keith Solomon 812e5c2f2a feature: Initial MVP
2026-04-05 16:20:39 -05:00

229 lines
9.9 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// phpcs:disable PEAR.Commenting.FileComment,PEAR.Commenting.ClassComment
/**
* Main application entrypoint.
*/
declare(strict_types=1);
require_once dirname(__DIR__) . '/bootstrap.php';
use IronKanban\Repository\ProjectRepository;
use IronKanban\Service\BoardService;
$projectRepository = new ProjectRepository();
$projects = $projectRepository->getAll();
$requestedProject = isset($_GET['project']) ? trim((string) $_GET['project']) : '';
$activeProjectId = $requestedProject !== '' ? $requestedProject : ($projects[0]->id ?? '');
$boardService = new BoardService();
$initialState = null;
if ($activeProjectId !== '') {
try {
$initialState = $boardService->getBoardState($activeProjectId);
} catch (Throwable $exception) {
$initialState = null;
}
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="<?php echo e(csrf_token()); ?>">
<title><?php echo e((string) config('app_name')); ?></title>
<link rel="stylesheet" href="/assets/app.css">
</head>
<body>
<div class="app-shell">
<aside class="sidebar">
<div>
<p class="eyebrow">Git-backed markdown kanban</p>
<h1>IronKanban</h1>
<p class="sidebar-copy">Projects stay as flat files, while the UI gives you drag-and-drop columns, quick edits, notes, and polling-based refreshes.</p>
</div>
<section class="project-list">
<div class="section-heading">
<h2>Projects</h2>
<span><?php echo count($projects); ?></span>
</div>
<?php if ($projects === []) : ?>
<div class="empty-state compact">
<p>No projects found in <code><?php echo e(project_root()); ?></code>.</p>
</div>
<?php else : ?>
<?php foreach ($projects as $project) : ?>
<a class="project-link<?php echo $project->id === $activeProjectId ? ' active' : ''; ?>" href="/?project=<?php echo rawurlencode($project->id); ?>">
<strong><?php echo e($project->title); ?></strong>
<span><?php echo e($project->id); ?></span>
</a>
<?php endforeach; ?>
<?php endif; ?>
</section>
<section class="project-root">
<div class="section-heading">
<h2>Storage</h2>
</div>
<p><code><?php echo e(project_root()); ?></code></p>
</section>
</aside>
<main class="workspace" id="app" data-project-id="<?php echo e($activeProjectId); ?>">
<?php if ($initialState === null) : ?>
<section class="hero empty-state">
<h2>No project selected</h2>
<p>Create or copy a project folder into <code><?php echo e(project_root()); ?></code> using the markdown layout from the notes.</p>
</section>
<?php else : ?>
<header class="workspace-header">
<div>
<p class="eyebrow">Project Board</p>
<h2><?php echo e((string) $initialState['project']['title']); ?></h2>
<p class="project-description"><?php echo nl2br(e((string) $initialState['project']['body'])); ?></p>
</div>
<div class="header-actions">
<button type="button" class="button ghost" data-action="new-column">New Column</button>
<button type="button" class="button primary" data-action="new-task">New Task</button>
</div>
</header>
<section class="workspace-stack">
<section class="notes-panel is-collapsible is-collapsed" id="notes-panel" data-collapsible>
<div class="notes-panel-header">
<div>
<p class="eyebrow">Project Notes</p>
<h2>Notes</h2>
</div>
<div class="notes-panel-actions">
<button type="button" class="button ghost compact" data-action="new-note">Add Note</button>
<button
type="button"
class="button ghost compact collapse-toggle"
data-action="toggle-notes"
data-target="notes-list"
aria-expanded="false"
aria-controls="notes-list"
>
Show Notes
</button>
</div>
</div>
<div id="notes-list" class="notes-list" hidden></div>
</section>
<section class="board-panel">
<div class="board-scroll">
<div class="board-columns" id="board-columns"></div>
</div>
</section>
<section class="trash-panel" id="trash-panel">
<div class="trash-panel-header">
<div>
<p class="eyebrow">Discarded Tasks</p>
<h2>Trash</h2>
</div>
<button
type="button"
class="button ghost compact collapse-toggle"
data-action="toggle-trash"
aria-expanded="false"
aria-controls="trash-columns-wrap"
>
Show Trash
</button>
</div>
<div class="trash-dropzone" id="trash-dropzone" data-column-id="trash">
<p class="trash-dropzone-title">Drop tasks here to discard them</p>
<p class="trash-dropzone-meta" id="trash-dropzone-meta">Trash is empty.</p>
</div>
<div id="trash-columns-wrap" class="trash-columns-wrap" hidden>
<div class="board-scroll">
<div class="board-columns board-columns-trash" id="trash-columns"></div>
</div>
</div>
</section>
</section>
<?php endif; ?>
</main>
</div>
<dialog id="task-dialog" class="dialog">
<form method="dialog" class="dialog-card" id="task-form">
<div class="dialog-header">
<h3 id="task-dialog-title">Task</h3>
<button type="submit" class="icon-button" aria-label="Close">×</button>
</div>
<input type="hidden" name="id">
<label>
<span>Title</span>
<input type="text" name="title" maxlength="200" required>
</label>
<label>
<span>Column</span>
<select name="column"></select>
</label>
<label>
<span>Priority</span>
<select name="priority">
<option value="low">Low</option>
<option value="normal">Normal</option>
<option value="high">High</option>
<option value="urgent">Urgent</option>
</select>
</label>
<label class="checkbox-row">
<input type="checkbox" name="completed">
<span>Completed</span>
</label>
<label class="checkbox-row">
<input type="checkbox" name="is_active" checked>
<span>Active</span>
</label>
<label>
<span>Markdown</span>
<textarea name="body" rows="12"></textarea>
</label>
<div class="dialog-actions">
<button type="button" class="button ghost" data-action="trash-task">Move To Trash</button>
<button type="submit" class="button primary">Save Task</button>
</div>
</form>
</dialog>
<dialog id="note-dialog" class="dialog">
<form method="dialog" class="dialog-card" id="note-form">
<div class="dialog-header">
<h3 id="note-dialog-title">Note</h3>
<button type="submit" class="icon-button" aria-label="Close">×</button>
</div>
<input type="hidden" name="id">
<label>
<span>Title</span>
<input type="text" name="title" maxlength="200" required>
</label>
<label>
<span>Markdown</span>
<textarea name="body" rows="14"></textarea>
</label>
<div class="dialog-actions">
<button type="submit" class="button primary">Save Note</button>
</div>
</form>
</dialog>
<script id="initial-state" type="application/json"><?php echo
$initialState !== null
? (string) json_encode(
$initialState,
JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
)
: 'null';
?></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
<script src="/assets/app.js"></script>
</body>
</html>