This commit establishes the new monorepo architecture for the KROW Workforce platform. Key changes include: - Reorganized project into `frontend-web`, `mobile-apps`, `firebase`, `scripts`, and `secrets` directories. - Updated `Makefile` to support the new monorepo layout and automate Base44 export integration. - Fixed `scripts/prepare-export.js` for ES module compatibility and global component import resolution. - Created and updated `CONTRIBUTING.md` for developer onboarding. - Restructured, renamed, and translated all `docs/` files for clarity and consistency. - Implemented an interactive internal launchpad with diagram viewing capabilities. - Configured base Firebase project files (`firebase.json`, security rules). - Updated `README.md` to reflect the new project structure and documentation overview.
247 lines
11 KiB
HTML
247 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>KROW Launchpad</title>
|
|
<!-- Bootstrap CSS -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<!-- Bootstrap Icons -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
|
<!-- Custom CSS -->
|
|
<style>
|
|
body {
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.main-layout {
|
|
display: grid;
|
|
grid-template-columns: 280px 1fr;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.sidebar {
|
|
background-color: #ffffff;
|
|
border-right: 1px solid #dee2e6;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.sidebar .nav-link {
|
|
color: #495057;
|
|
font-weight: 500;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
transition: color 0.2s, background-color 0.2s;
|
|
}
|
|
|
|
.sidebar .nav-link.active,
|
|
.sidebar .nav-link:hover {
|
|
color: #0d6efd;
|
|
background-color: #e9ecef;
|
|
}
|
|
|
|
.sidebar-heading {
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
color: #6c757d;
|
|
text-transform: uppercase;
|
|
padding: 0 1rem;
|
|
margin-top: 1.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.content-area {
|
|
padding: 2rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
#diagram-viewer {
|
|
display: none; /* Hidden by default */
|
|
height: calc(100vh - 4rem); /* Full height minus padding */
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
#diagram-container {
|
|
cursor: grab;
|
|
overflow: hidden;
|
|
flex-grow: 1;
|
|
position: relative;
|
|
background-color: #ffffff;
|
|
border-radius: 0.5rem;
|
|
border: 1px solid #dee2e6;
|
|
}
|
|
#diagram-container:focus { outline: none; }
|
|
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="main-layout">
|
|
<!-- Sidebar -->
|
|
<nav class="sidebar">
|
|
<div class="d-flex justify-content-center align-items-center mb-4">
|
|
<img src="logo.svg" alt="Krow Logo" style="height: 60px;">
|
|
</div>
|
|
<div class="nav flex-column nav-pills">
|
|
<a class="nav-link active" href="#" id="nav-home" onclick="showView('home', this)">
|
|
<i class="bi bi-house-door"></i>Home
|
|
</a>
|
|
|
|
<div class="sidebar-heading">Diagrams</div>
|
|
|
|
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/high-level-overview.svg', 'Apps High-Level Overview')">
|
|
<i class="bi bi-diagram-3"></i>High-Level Overview
|
|
</a>
|
|
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/shift-lifecycle-workflow.svg', 'Core Workflow - Shift Lifecycle')">
|
|
<i class="bi bi-arrow-repeat"></i>Shift Lifecycle
|
|
</a>
|
|
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/invoice-workflow.svg', 'Invoice Workflow - Complete')">
|
|
<i class="bi bi-receipt"></i>Invoice Workflow
|
|
</a>
|
|
<a class="nav-link" href="#" onclick="showView('diagram', this, './assets/diagrams/complete-workflow.svg', 'Complete Workflow')">
|
|
<i class="bi bi-infinity"></i>Complete Workflow
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main Content Area -->
|
|
<main class="content-area">
|
|
<!-- View 1: Home Content -->
|
|
<div id="home-view">
|
|
<h2 class="mb-4">Welcome to the Project Launchpad</h2>
|
|
<div class="row">
|
|
<div class="col-lg-6">
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header"><h3>Applications</h3></div>
|
|
<div class="card-body">
|
|
<ul class="list-group list-group-flush">
|
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<a target="_blank" href="#">Control Tower (Dev)</a>
|
|
<span class="badge bg-primary rounded-pill">Dev</span>
|
|
</li>
|
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<a target="_blank" href="#">Control Tower (Staging)</a>
|
|
<span class="badge bg-warning text-dark rounded-pill">Staging</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header"><h3>Access & Resources</h3></div>
|
|
<div class="card-body">
|
|
<div class="list-group list-group-flush">
|
|
<a href="https://github.com/Oloodi/krow-workforce" target="_blank" class="list-group-item list-group-item-action">
|
|
<div class="fw-bold">GitHub Repository</div>
|
|
</a>
|
|
<a href="https://chat.google.com/" target="_blank" class="list-group-item list-group-item-action">
|
|
<div class="fw-bold">Team Communication</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- View 2: Diagram Viewer -->
|
|
<div id="diagram-viewer">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h3 id="diagram-title" class="mb-0"></h3>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-secondary" id="zoomInBtn" title="Zoom In"><i class="bi bi-zoom-in"></i></button>
|
|
<button type="button" class="btn btn-outline-secondary" id="zoomOutBtn" title="Zoom Out"><i class="bi bi-zoom-out"></i></button>
|
|
<button type="button" class="btn btn-outline-secondary" id="resetBtn" title="Reset View"><i class="bi bi-aspect-ratio"></i></button>
|
|
</div>
|
|
</div>
|
|
<div id="diagram-container" tabindex="-1">
|
|
<!-- SVG will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- JS -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/@panzoom/panzoom@4.5.1/dist/panzoom.min.js"></script>
|
|
|
|
<script>
|
|
const homeView = document.getElementById('home-view');
|
|
const diagramViewer = document.getElementById('diagram-viewer');
|
|
const diagramContainer = document.getElementById('diagram-container');
|
|
const diagramTitle = document.getElementById('diagram-title');
|
|
|
|
const zoomInBtn = document.getElementById('zoomInBtn');
|
|
const zoomOutBtn = document.getElementById('zoomOutBtn');
|
|
const resetBtn = document.getElementById('resetBtn');
|
|
|
|
let panzoomInstance = null;
|
|
|
|
function setActiveNav(activeLink) {
|
|
document.querySelectorAll('.sidebar .nav-link').forEach(link => {
|
|
link.classList.remove('active');
|
|
});
|
|
activeLink.classList.add('active');
|
|
}
|
|
|
|
async function showView(viewName, navLink, svgPath, title) {
|
|
setActiveNav(navLink);
|
|
if (panzoomInstance) panzoomInstance.destroy();
|
|
diagramContainer.innerHTML = '';
|
|
|
|
if (viewName === 'home') {
|
|
homeView.style.display = 'block';
|
|
diagramViewer.style.display = 'none';
|
|
} else if (viewName === 'diagram') {
|
|
homeView.style.display = 'none';
|
|
diagramViewer.style.display = 'flex';
|
|
diagramTitle.textContent = title;
|
|
diagramContainer.innerHTML = '<div class="d-flex justify-content-center align-items-center h-100"><div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div></div>';
|
|
|
|
try {
|
|
const response = await fetch(svgPath);
|
|
if (!response.ok) throw new Error(`Network error: ${response.status}`);
|
|
const svgContent = await response.text();
|
|
|
|
const parser = new DOMParser();
|
|
const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
|
|
const svgElement = svgDoc.querySelector('svg');
|
|
|
|
if (svgElement) {
|
|
diagramContainer.innerHTML = '';
|
|
diagramContainer.appendChild(svgElement);
|
|
panzoomInstance = Panzoom(svgElement, {
|
|
canvas: true,
|
|
maxScale: 10,
|
|
minScale: 0.3,
|
|
zoomOnDblClick: false
|
|
});
|
|
diagramContainer.addEventListener('wheel', panzoomInstance.zoomWithWheel);
|
|
diagramContainer.focus();
|
|
} else {
|
|
throw new Error('No SVG element found.');
|
|
}
|
|
} catch (error) {
|
|
diagramContainer.innerHTML = `<div class="alert alert-danger m-3">Failed to load diagram: ${error.message}</div>`;
|
|
}
|
|
}
|
|
}
|
|
|
|
zoomInBtn.addEventListener('click', () => { panzoomInstance?.zoomIn(); diagramContainer.focus(); });
|
|
zoomOutBtn.addEventListener('click', () => { panzoomInstance?.zoomOut(); diagramContainer.focus(); });
|
|
resetBtn.addEventListener('click', () => { panzoomInstance?.reset(); diagramContainer.focus(); });
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
showView('home', document.getElementById('nav-home'));
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|