Merge pull request #149 from Oloodi/56-uiuxmobile-update-visual-design-of-client-and-staff-mobile-applications-links

feat: add staff app figma and preview to the lauchpad
This commit is contained in:
Oloodi Admin
2025-12-01 11:42:12 -05:00
committed by GitHub
17 changed files with 472 additions and 288 deletions

View File

@@ -0,0 +1,145 @@
[
{
"title": "Applications",
"iconColorClass": "bg-primary-100",
"iconPath": "assets/images/icon-applications.svg",
"links": [
{
"title": "Control Tower",
"url": "https://krow-workforce-dev.web.app",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-blue-100 hover:from-blue-100 hover:to-blue-200",
"iconClass": "w-2 h-2 bg-blue-500 rounded-full",
"textHoverClass": "group-hover:text-blue-700"
},
{
"title": "Control Tower",
"url": "https://krow-workforce-staging.web.app",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-amber-100 hover:from-amber-100 hover:to-amber-200",
"iconClass": "w-2 h-2 bg-amber-500 rounded-full",
"textHoverClass": "group-hover:text-amber-700"
}
]
},
{
"title": "Legacy Mobile Apps",
"iconColorClass": "bg-green-100",
"iconPath": "assets/images/icon-legacy-mobile-apps.svg",
"links": [
{
"title": "Google Play Store",
"url": "https://play.google.com/store/apps/dev?id=9163719228191263405&hl=en",
"badge": "Live",
"badgeColorClass": "bg-green-500",
"containerClass": "bg-gradient-to-r from-green-50 to-emerald-100 hover:from-green-100 hover:to-emerald-200",
"iconPath": "assets/images/icon-google-play.svg",
"textHoverClass": "group-hover:text-green-700"
},
{
"title": "Apple App Store",
"url": "https://apps.apple.com/us/developer/thinkloops-llc/id1719034287",
"badge": "Live",
"badgeColorClass": "bg-gray-700",
"containerClass": "bg-gradient-to-r from-gray-50 to-gray-100 hover:from-gray-100 hover:to-gray-200",
"iconPath": "assets/images/icon-apple-app-store.svg",
"textHoverClass": "group-hover:text-gray-700"
}
]
},
{
"title": "Cloud Infrastructure",
"iconColorClass": "bg-purple-100",
"iconPath": "assets/images/icon-cloud-infrastructure.svg",
"links": [
{
"title": "Firebase Console",
"url": "https://console.firebase.google.com/project/krow-workforce-dev/overview",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-indigo-100 hover:from-blue-100 hover:to-indigo-200",
"iconPath": "assets/images/icon-firebase-console.svg",
"textHoverClass": "group-hover:text-indigo-700"
},
{
"title": "Firebase Console",
"url": "https://console.firebase.google.com/project/krow-workforce-staging/overview",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-orange-100 hover:from-amber-100 hover:to-orange-200",
"iconPath": "assets/images/icon-firebase-console.svg",
"textHoverClass": "group-hover:text-orange-700"
},
{
"title": "Google Cloud",
"url": "https://console.cloud.google.com/welcome/new?project=krow-workforce-dev",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-cyan-100 hover:from-blue-100 hover:to-cyan-200",
"iconPath": "assets/images/icon-google-cloud.svg",
"textHoverClass": "group-hover:text-cyan-700"
},
{
"title": "Google Cloud",
"url": "https://console.cloud.google.com/welcome/new?project=krow-workforce-staging",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-yellow-100 hover:from-amber-100 hover:to-yellow-200",
"iconPath": "assets/images/icon-google-cloud.svg",
"textHoverClass": "group-hover:text-yellow-700"
}
]
},
{
"title": "Design",
"iconColorClass": "bg-pink-100",
"iconPath": "assets/images/icon-design.svg",
"links": [
{
"title": "Staff App Figma File",
"url": "https://www.figma.com/design/HfNpoYOpkfUu2lgDMp4xQK/KROW-Staff-App-Revamp?node-id=0-1&t=4TLUeCIWf7I1TTGQ-1",
"badge": "Design",
"badgeColorClass": "bg-pink-500",
"containerClass": "bg-gradient-to-r from-pink-50 to-rose-100 hover:from-pink-100 hover:to-rose-200",
"iconPath": "assets/images/icon-figma.svg",
"textHoverClass": "group-hover:text-pink-700"
},
{
"title": "Staff App Preview",
"url": "https://9000-firebase-studio-1764098159606.cluster-oe5pskshnfducslpwllk6difqk.cloudworkstations.dev/",
"badge": "Preview",
"badgeColorClass": "bg-purple-500",
"containerClass": "bg-gradient-to-r from-purple-50 to-fuchsia-100 hover:from-purple-100 hover:to-fuchsia-200",
"iconPath": "assets/images/icon-preview.svg",
"textHoverClass": "group-hover:text-purple-700"
}
]
},
{
"title": "Resources",
"iconColorClass": "bg-indigo-100",
"iconPath": "assets/images/icon-resources.svg",
"links": [
{
"title": "GitHub Repository",
"subtitle": "View source code",
"url": "https://github.com/Oloodi/krow-workforce",
"containerClass": "bg-gradient-to-r from-gray-50 to-slate-100 hover:from-gray-100 hover:to-slate-200",
"iconPath": "assets/images/icon-github.svg",
"textHoverClass": "group-hover:text-gray-700",
"arrowIcon": true
},
{
"title": "Team Communication",
"subtitle": "Google Chat",
"url": "https://chat.google.com/",
"containerClass": "bg-gradient-to-r from-green-50 to-teal-100 hover:from-green-100 hover:to-teal-200",
"iconPath": "assets/images/icon-chat.svg",
"textHoverClass": "group-hover:text-teal-700",
"arrowIcon": true
}
]
}
]

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-gray-700" fill="currentColor" viewBox="0 0 24 24">
<path
d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@@ -0,0 +1 @@
<svg class="w-6 h-6 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"></path></svg>

After

Width:  |  Height:  |  Size: 330 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@@ -0,0 +1,4 @@
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path>
</svg>

After

Width:  |  Height:  |  Size: 280 B

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" class="w-6 h-6 text-pink-600">
<path
d="M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C12.8417 22 14 22.1163 14 21C14 20.391 13.6832 19.9212 13.3686 19.4544C12.9082 18.7715 12.4523 18.0953 13 17C13.6667 15.6667 14.7778 15.6667 16.4815 15.6667C17.3334 15.6667 18.3334 15.6667 19.5 15.5C21.601 15.1999 22 13.9084 22 12Z"
stroke="currentColor" stroke-width="2"></path>
<path d="M7 15.002L7.00868 14.9996" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<circle cx="9.5" cy="8.5" r="1.5" stroke="currentColor" stroke-width="2"></circle>
<circle cx="16.5" cy="9.5" r="1.5" stroke="currentColor" stroke-width="2"></circle>
</svg>

After

Width:  |  Height:  |  Size: 819 B

View File

@@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 200 300" class="w-5 h-5">
<style>
.st0 {
fill: #0acf83
}
.st1 {
fill: #a259ff
}
.st2 {
fill: #f24e1e
}
.st3 {
fill: #ff7262
}
.st4 {
fill: #1abcfe
}
</style>
<title>Figma.logo</title>
<desc>Created using Figma</desc>
<path id="path0_fill" class="st0" d="M50 300c27.6 0 50-22.4 50-50v-50H50c-27.6 0-50 22.4-50 50s22.4 50 50 50z" />
<path id="path1_fill" class="st1" d="M0 150c0-27.6 22.4-50 50-50h50v100H50c-27.6 0-50-22.4-50-50z" />
<path id="path1_fill_1_" class="st2" d="M0 50C0 22.4 22.4 0 50 0h50v100H50C22.4 100 0 77.6 0 50z" />
<path id="path2_fill" class="st3" d="M100 0h50c27.6 0 50 22.4 50 50s-22.4 50-50 50h-50V0z" />
<path id="path3_fill" class="st4" d="M200 150c0 27.6-22.4 50-50 50s-50-22.4-50-50 22.4-50 50-50 50 22.4 50 50z" />
</svg>

After

Width:  |  Height:  |  Size: 995 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-orange-500" fill="currentColor" viewBox="0 0 24 24">
<path
d="M3.89 15.672L6.255.461A.542.542 0 017.27.288l2.543 4.771zm16.794 3.692l-2.25-14.03a.542.542 0 00-.919-.295L3.316 19.365l7.856 4.427a1.621 1.621 0 001.588 0zM14.3 7.147l-1.82-3.482a.542.542 0 00-.96 0L3.53 17.984z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-gray-900" fill="currentColor" viewBox="0 0 24 24">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 831 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path
d="M12.19 2.38a8.85 8.85 0 00-10.4 9.28l5.18-5.18a4.89 4.89 0 012.5-.72 4.89 4.89 0 011.72-.07zm7.6 2.24a8.85 8.85 0 01-7.6 14.91l4.5-4.5a4.89 4.89 0 002.45-2.55 4.89 4.89 0 00.65-7.86z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 300 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 24 24">
<path
d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 412 B

View File

@@ -0,0 +1,4 @@
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@@ -0,0 +1,6 @@
<svg class="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 436 B

View File

@@ -0,0 +1,5 @@
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
</path>
</svg>

After

Width:  |  Height:  |  Size: 440 B

View File

@@ -0,0 +1,88 @@
async function loadLinks() {
const container = document.getElementById('links-container');
if (!container) return;
try {
const response = await fetch('./assets/data/links.json');
if (!response.ok) {
throw new Error(`Failed to load links: ${response.status}`);
}
const groups = await response.json();
// Helper function to fetch SVG content
const fetchSvg = async (path) => {
if (!path) return '';
try {
const res = await fetch(path);
if (!res.ok) return '';
return await res.text();
} catch (e) {
console.error(`Failed to load SVG: ${path}`, e);
return '';
}
};
// Process groups and fetch SVGs in parallel
const groupsWithSvgs = await Promise.all(groups.map(async (group) => {
const groupIconSvg = await fetchSvg(group.iconPath);
const linksWithSvgs = await Promise.all(group.links.map(async (link) => {
const linkIconSvg = link.iconPath ? await fetchSvg(link.iconPath) : '';
return { ...link, iconSvg: linkIconSvg };
}));
return { ...group, iconSvg: groupIconSvg, links: linksWithSvgs };
}));
container.innerHTML = groupsWithSvgs.map(group => `
<!-- ${group.title} Card -->
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 ${group.iconColorClass} rounded-lg flex items-center justify-center">
${group.iconSvg}
</div>
<h3 class="text-xl font-bold text-gray-900">${group.title}</h3>
</div>
<div class="space-y-3">
${group.links.map(link => `
<a href="${link.url}" target="_blank"
class="flex items-center justify-between p-4 ${link.containerClass} rounded-xl transition-all group">
<div class="flex items-center space-x-3">
${link.iconClass ? `<div class="${link.iconClass}"></div>` : link.iconSvg}
${link.subtitle ? `
<div>
<div class="font-medium text-gray-900 ${link.textHoverClass}">${link.title}</div>
<div class="text-xs text-gray-500">${link.subtitle}</div>
</div>
` : `
<span class="font-medium text-gray-900 ${link.textHoverClass}">${link.title}</span>
`}
</div>
${link.badge ? `
<span class="px-3 py-1 ${link.badgeColorClass} text-white text-xs font-semibold rounded-full">${link.badge}</span>
` : ''}
${link.arrowIcon ? `
<svg class="w-5 h-5 text-gray-400 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
` : ''}
</a>
`).join('')}
</div>
</div>
`).join('');
} catch (error) {
console.error('Error loading links:', error);
container.innerHTML = `
<div class="col-span-full p-4 bg-red-50 text-red-600 rounded-xl border border-red-200">
Failed to load application links. Please try refreshing the page.
</div>
`;
}
}
// Load links when the DOM is loaded
document.addEventListener('DOMContentLoaded', loadLinks);

View File

@@ -6,16 +6,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KROW Launchpad</title> <title>KROW Launchpad</title>
<link rel="icon" type="image/x-icon" href="favicon.svg"> <link rel="icon" type="image/x-icon" href="favicon.svg">
<!-- Tailwind CSS --> <!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<!-- Mermaid --> <!-- Mermaid -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.1/mermaid.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.1/mermaid.min.js"></script>
<!-- Marked.js for Markdown parsing --> <!-- Marked.js for Markdown parsing -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- Custom Tailwind Config --> <!-- Custom Tailwind Config -->
<script> <script>
tailwind.config = { tailwind.config = {
@@ -39,57 +39,60 @@
} }
} }
</script> </script>
<style> <style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
* { * {
font-family: 'Inter', sans-serif; font-family: 'Inter', sans-serif;
} }
.gradient-bg { .gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
} }
.card-hover { .card-hover {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
} }
.card-hover:hover { .card-hover:hover {
transform: translateY(-4px); transform: translateY(-4px);
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
} }
.nav-item { .nav-item {
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.nav-item:hover { .nav-item:hover {
transform: translateX(4px); transform: translateX(4px);
} }
.badge-pulse { .badge-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
} }
@keyframes pulse { @keyframes pulse {
0%, 100% {
0%,
100% {
opacity: 1; opacity: 1;
} }
50% { 50% {
opacity: .7; opacity: .7;
} }
} }
.scrollbar-hide::-webkit-scrollbar { .scrollbar-hide::-webkit-scrollbar {
display: none; display: none;
} }
.scrollbar-hide { .scrollbar-hide {
-ms-overflow-style: none; -ms-overflow-style: none;
scrollbar-width: none; scrollbar-width: none;
} }
#diagram-container:active { #diagram-container:active {
cursor: grabbing; cursor: grabbing;
} }
@@ -102,59 +105,73 @@
width: 100%; width: 100%;
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
font-size: 0.875rem; font-size: 0.875rem;
color: #4b5563; /* text-gray-600 */ color: #4b5563;
/* text-gray-600 */
text-align: left; text-align: left;
background-color: #f9fafb; /* bg-gray-50 */ background-color: #f9fafb;
border-radius: 0.5rem; /* rounded-lg */ /* bg-gray-50 */
border-radius: 0.5rem;
/* rounded-lg */
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
} }
.accordion-button:hover { .accordion-button:hover {
background-color: #f3f4f6; /* bg-gray-100 */ background-color: #f3f4f6;
/* bg-gray-100 */
} }
.accordion-button .chevron { .accordion-button .chevron {
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
.accordion-button[aria-expanded="true"] .chevron { .accordion-button[aria-expanded="true"] .chevron {
transform: rotate(90deg); transform: rotate(90deg);
} }
.accordion-panel { .accordion-panel {
overflow: hidden; overflow: hidden;
transition: max-height 0.3s ease-out; transition: max-height 0.3s ease-out;
max-height: 0; max-height: 0;
} }
/* Modal styles */ /* Modal styles */
.modal-overlay { .modal-overlay {
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
animation: fadeIn 0.2s ease-out; animation: fadeIn 0.2s ease-out;
} }
@keyframes fadeIn { @keyframes fadeIn {
from { opacity: 0; } from {
to { opacity: 1; } opacity: 0;
}
to {
opacity: 1;
}
} }
.modal-content { .modal-content {
animation: slideUp 0.3s ease-out; animation: slideUp 0.3s ease-out;
} }
@keyframes slideUp { @keyframes slideUp {
from { from {
opacity: 0; opacity: 0;
transform: translateY(20px); transform: translateY(20px);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
} }
} }
/* Markdown styling */ /* Markdown styling */
.markdown-content { .markdown-content {
line-height: 1.7; line-height: 1.7;
color: #374151; color: #374151;
} }
.markdown-content h1 { .markdown-content h1 {
font-size: 2em; font-size: 2em;
font-weight: 700; font-weight: 700;
@@ -164,11 +181,11 @@
border-bottom: 2px solid #e5e7eb; border-bottom: 2px solid #e5e7eb;
color: #111827; color: #111827;
} }
.markdown-content h1:first-child { .markdown-content h1:first-child {
margin-top: 0; margin-top: 0;
} }
.markdown-content h2 { .markdown-content h2 {
font-size: 1.5em; font-size: 1.5em;
font-weight: 600; font-weight: 600;
@@ -178,7 +195,7 @@
border-bottom: 1px solid #e5e7eb; border-bottom: 1px solid #e5e7eb;
color: #111827; color: #111827;
} }
.markdown-content h3 { .markdown-content h3 {
font-size: 1.25em; font-size: 1.25em;
font-weight: 600; font-weight: 600;
@@ -186,7 +203,7 @@
margin-bottom: 0.5em; margin-bottom: 0.5em;
color: #111827; color: #111827;
} }
.markdown-content h4 { .markdown-content h4 {
font-size: 1.1em; font-size: 1.1em;
font-weight: 600; font-weight: 600;
@@ -194,28 +211,29 @@
margin-bottom: 0.5em; margin-bottom: 0.5em;
color: #111827; color: #111827;
} }
.markdown-content p { .markdown-content p {
margin-bottom: 1em; margin-bottom: 1em;
} }
.markdown-content ul, .markdown-content ol { .markdown-content ul,
.markdown-content ol {
margin-bottom: 1em; margin-bottom: 1em;
padding-left: 2em; padding-left: 2em;
} }
.markdown-content ul { .markdown-content ul {
list-style-type: disc; list-style-type: disc;
} }
.markdown-content ol { .markdown-content ol {
list-style-type: decimal; list-style-type: decimal;
} }
.markdown-content li { .markdown-content li {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
.markdown-content code { .markdown-content code {
background-color: #f3f4f6; background-color: #f3f4f6;
padding: 0.2em 0.4em; padding: 0.2em 0.4em;
@@ -224,7 +242,7 @@
font-family: 'Courier New', monospace; font-family: 'Courier New', monospace;
color: #dc2626; color: #dc2626;
} }
.markdown-content pre { .markdown-content pre {
background-color: #1f2937; background-color: #1f2937;
color: #f9fafb; color: #f9fafb;
@@ -233,13 +251,13 @@
overflow-x: auto; overflow-x: auto;
margin-bottom: 1em; margin-bottom: 1em;
} }
.markdown-content pre code { .markdown-content pre code {
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
color: inherit; color: inherit;
} }
.markdown-content blockquote { .markdown-content blockquote {
border-left: 4px solid #3b82f6; border-left: 4px solid #3b82f6;
padding-left: 1em; padding-left: 1em;
@@ -247,40 +265,41 @@
color: #6b7280; color: #6b7280;
font-style: italic; font-style: italic;
} }
.markdown-content a { .markdown-content a {
color: #3b82f6; color: #3b82f6;
text-decoration: underline; text-decoration: underline;
} }
.markdown-content a:hover { .markdown-content a:hover {
color: #2563eb; color: #2563eb;
} }
.markdown-content table { .markdown-content table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
margin-bottom: 1em; margin-bottom: 1em;
} }
.markdown-content th, .markdown-content td { .markdown-content th,
.markdown-content td {
border: 1px solid #e5e7eb; border: 1px solid #e5e7eb;
padding: 0.5em; padding: 0.5em;
text-align: left; text-align: left;
} }
.markdown-content th { .markdown-content th {
background-color: #f9fafb; background-color: #f9fafb;
font-weight: 600; font-weight: 600;
} }
.markdown-content img { .markdown-content img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
border-radius: 0.5em; border-radius: 0.5em;
margin: 1em 0; margin: 1em 0;
} }
.markdown-content hr { .markdown-content hr {
border: none; border: none;
border-top: 2px solid #e5e7eb; border-top: 2px solid #e5e7eb;
@@ -291,7 +310,7 @@
<body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen"> <body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen">
<div class="flex h-screen overflow-hidden"> <div class="flex h-screen overflow-hidden">
<!-- Sidebar --> <!-- Sidebar -->
<aside class="w-72 bg-white shadow-xl flex flex-col border-r border-gray-200"> <aside class="w-72 bg-white shadow-xl flex flex-col border-r border-gray-200">
<!-- Logo Section --> <!-- Logo Section -->
@@ -306,24 +325,26 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Navigation --> <!-- Navigation -->
<nav class="flex-1 overflow-y-auto scrollbar-hide p-4" id="sidebar-nav"> <nav class="flex-1 overflow-y-auto scrollbar-hide p-4" id="sidebar-nav">
<a href="#" id="nav-home" onclick="showView('home', this)" <a href="#" id="nav-home" onclick="showView('home', this)"
class="nav-item flex items-center space-x-3 px-4 py-3 rounded-xl text-gray-700 bg-primary-50 border border-primary-200 font-medium mb-2"> class="nav-item flex items-center space-x-3 px-4 py-3 rounded-xl text-gray-700 bg-primary-50 border border-primary-200 font-medium mb-2">
<svg class="w-5 h-5 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6">
</path>
</svg> </svg>
<span>Home</span> <span>Home</span>
</a> </a>
<!-- Dynamic diagrams section - ALL diagrams loaded here --> <!-- Dynamic diagrams section - ALL diagrams loaded here -->
<div id="dynamic-diagrams-section"></div> <div id="dynamic-diagrams-section"></div>
<!-- Documentation section --> <!-- Documentation section -->
<div id="documentation-section"></div> <div id="documentation-section"></div>
</nav> </nav>
<!-- Footer --> <!-- Footer -->
<div class="p-4 border-t border-gray-200 bg-gray-50"> <div class="p-4 border-t border-gray-200 bg-gray-50">
<div class="flex items-center space-x-2 text-xs text-gray-500"> <div class="flex items-center space-x-2 text-xs text-gray-500">
@@ -332,10 +353,10 @@
</div> </div>
</div> </div>
</aside> </aside>
<!-- Main Content Area --> <!-- Main Content Area -->
<main class="flex-1 overflow-y-auto"> <main class="flex-1 overflow-y-auto">
<!-- Home View --> <!-- Home View -->
<div id="home-view" class="p-8"> <div id="home-view" class="p-8">
<!-- Header --> <!-- Header -->
@@ -343,226 +364,67 @@
<h2 class="text-3xl font-bold text-gray-900 mb-2">Welcome to KROW Launchpad</h2> <h2 class="text-3xl font-bold text-gray-900 mb-2">Welcome to KROW Launchpad</h2>
<p class="text-gray-600">Your central hub for workforce management infrastructure</p> <p class="text-gray-600">Your central hub for workforce management infrastructure</p>
</div> </div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6"> <div id="links-container" class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Links will be loaded dynamically -->
<!-- Applications Card --> <div class="col-span-full flex justify-center p-12">
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100"> <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div>
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 bg-primary-100 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"></path>
</svg>
</div>
<h3 class="text-xl font-bold text-gray-900">Applications</h3>
</div>
<div class="space-y-3">
<a href="https://krow-workforce-dev.web.app" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-blue-50 to-blue-100 rounded-xl hover:from-blue-100 hover:to-blue-200 transition-all group">
<div class="flex items-center space-x-3">
<div class="w-2 h-2 bg-blue-500 rounded-full"></div>
<span class="font-medium text-gray-900 group-hover:text-blue-700">Control Tower</span>
</div>
<span class="px-3 py-1 bg-blue-500 text-white text-xs font-semibold rounded-full">Dev</span>
</a>
<a href="https://krow-workforce-staging.web.app" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-amber-50 to-amber-100 rounded-xl hover:from-amber-100 hover:to-amber-200 transition-all group">
<div class="flex items-center space-x-3">
<div class="w-2 h-2 bg-amber-500 rounded-full"></div>
<span class="font-medium text-gray-900 group-hover:text-amber-700">Control Tower</span>
</div>
<span class="px-3 py-1 bg-amber-500 text-white text-xs font-semibold rounded-full">Staging</span>
</a>
</div>
</div> </div>
<!-- Legacy Mobile Apps Card -->
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
</div>
<h3 class="text-xl font-bold text-gray-900">Legacy Mobile Apps</h3>
</div>
<div class="space-y-3">
<a href="https://play.google.com/store/apps/dev?id=9163719228191263405&hl=en" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-green-50 to-emerald-100 rounded-xl hover:from-green-100 hover:to-emerald-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-green-700">Google Play Store</span>
</div>
<span class="px-3 py-1 bg-green-500 text-white text-xs font-semibold rounded-full">Live</span>
</a>
<a href="https://apps.apple.com/us/developer/thinkloops-llc/id1719034287" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-gray-50 to-gray-100 rounded-xl hover:from-gray-100 hover:to-gray-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-gray-700" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-gray-700">Apple App Store</span>
</div>
<span class="px-3 py-1 bg-gray-700 text-white text-xs font-semibold rounded-full">Live</span>
</a>
</div>
</div>
<!-- Cloud Consoles Card -->
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path>
</svg>
</div>
<h3 class="text-xl font-bold text-gray-900">Cloud Infrastructure</h3>
</div>
<div class="space-y-3">
<a href="https://console.firebase.google.com/project/krow-workforce-dev/overview" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-blue-50 to-indigo-100 rounded-xl hover:from-blue-100 hover:to-indigo-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-orange-500" fill="currentColor" viewBox="0 0 24 24">
<path d="M3.89 15.672L6.255.461A.542.542 0 017.27.288l2.543 4.771zm16.794 3.692l-2.25-14.03a.542.542 0 00-.919-.295L3.316 19.365l7.856 4.427a1.621 1.621 0 001.588 0zM14.3 7.147l-1.82-3.482a.542.542 0 00-.96 0L3.53 17.984z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-indigo-700">Firebase Console</span>
</div>
<span class="px-3 py-1 bg-blue-500 text-white text-xs font-semibold rounded-full">Dev</span>
</a>
<a href="https://console.firebase.google.com/project/krow-workforce-staging/overview" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-amber-50 to-orange-100 rounded-xl hover:from-amber-100 hover:to-orange-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-orange-500" fill="currentColor" viewBox="0 0 24 24">
<path d="M3.89 15.672L6.255.461A.542.542 0 017.27.288l2.543 4.771zm16.794 3.692l-2.25-14.03a.542.542 0 00-.919-.295L3.316 19.365l7.856 4.427a1.621 1.621 0 001.588 0zM14.3 7.147l-1.82-3.482a.542.542 0 00-.96 0L3.53 17.984z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-orange-700">Firebase Console</span>
</div>
<span class="px-3 py-1 bg-amber-500 text-white text-xs font-semibold rounded-full">Staging</span>
</a>
<a href="https://console.cloud.google.com/welcome/new?project=krow-workforce-dev" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-blue-50 to-cyan-100 rounded-xl hover:from-blue-100 hover:to-cyan-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M12.19 2.38a8.85 8.85 0 00-10.4 9.28l5.18-5.18a4.89 4.89 0 012.5-.72 4.89 4.89 0 011.72-.07zm7.6 2.24a8.85 8.85 0 01-7.6 14.91l4.5-4.5a4.89 4.89 0 002.45-2.55 4.89 4.89 0 00.65-7.86z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-cyan-700">Google Cloud</span>
</div>
<span class="px-3 py-1 bg-blue-500 text-white text-xs font-semibold rounded-full">Dev</span>
</a>
<a href="https://console.cloud.google.com/welcome/new?project=krow-workforce-staging" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-amber-50 to-yellow-100 rounded-xl hover:from-amber-100 hover:to-yellow-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M12.19 2.38a8.85 8.85 0 00-10.4 9.28l5.18-5.18a4.89 4.89 0 012.5-.72 4.89 4.89 0 011.72-.07zm7.6 2.24a8.85 8.85 0 01-7.6 14.91l4.5-4.5a4.89 4.89 0 002.45-2.55 4.89 4.89 0 00.65-7.86z"></path>
</svg>
<span class="font-medium text-gray-900 group-hover:text-yellow-700">Google Cloud</span>
</div>
<span class="px-3 py-1 bg-amber-500 text-white text-xs font-semibold rounded-full">Staging</span>
</a>
</div>
</div>
<!-- Access & Resources Card -->
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center">
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path>
</svg>
</div>
<h3 class="text-xl font-bold text-gray-900">Resources</h3>
</div>
<div class="space-y-3">
<a href="https://github.com/Oloodi/krow-workforce" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-gray-50 to-slate-100 rounded-xl hover:from-gray-100 hover:to-slate-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-gray-900" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path>
</svg>
<div>
<div class="font-medium text-gray-900 group-hover:text-gray-700">GitHub Repository</div>
<div class="text-xs text-gray-500">View source code</div>
</div>
</div>
<svg class="w-5 h-5 text-gray-400 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</a>
<a href="https://chat.google.com/" target="_blank"
class="flex items-center justify-between p-4 bg-gradient-to-r from-green-50 to-teal-100 rounded-xl hover:from-green-100 hover:to-teal-200 transition-all group">
<div class="flex items-center space-x-3">
<svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
<div>
<div class="font-medium text-gray-900 group-hover:text-teal-700">Team Communication</div>
<div class="text-xs text-gray-500">Google Chat</div>
</div>
</div>
<svg class="w-5 h-5 text-gray-400 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</a>
</div>
</div>
</div> </div>
</div> </div>
<!-- Diagram Viewer --> <!-- Diagram Viewer -->
<div id="diagram-viewer" class="hidden h-full flex flex-col p-8"> <div id="diagram-viewer" class="hidden h-full flex flex-col p-8">
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h3 id="diagram-title" class="text-2xl font-bold text-gray-900"></h3> <h3 id="diagram-title" class="text-2xl font-bold text-gray-900"></h3>
<div class="flex items-center space-x-2 bg-white rounded-xl shadow-lg p-2 border border-gray-200"> <div class="flex items-center space-x-2 bg-white rounded-xl shadow-lg p-2 border border-gray-200">
<button id="zoomInBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors" title="Zoom In"> <button id="zoomInBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Zoom In">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v6m3-3H7"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v6m3-3H7"></path>
</svg> </svg>
</button> </button>
<button id="zoomOutBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors" title="Zoom Out"> <button id="zoomOutBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Zoom Out">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM13 10H7"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM13 10H7"></path>
</svg> </svg>
</button> </button>
<button id="resetBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors" title="Reset View"> <button id="resetBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Reset View">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
</path>
</svg> </svg>
</button> </button>
</div> </div>
</div> </div>
<div id="diagram-container" tabindex="-1" <div id="diagram-container" tabindex="-1"
class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-hidden cursor-grab flex items-center justify-center p-8"> class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-hidden cursor-grab flex items-center justify-center p-8">
<!-- SVG will be loaded here --> <!-- SVG will be loaded here -->
</div> </div>
</div> </div>
<!-- Document Viewer --> <!-- Document Viewer -->
<div id="document-viewer" class="hidden h-full flex flex-col p-8"> <div id="document-viewer" class="hidden h-full flex flex-col p-8">
<div class="mb-6"> <div class="mb-6">
<h3 id="document-title" class="text-2xl font-bold text-gray-900"></h3> <h3 id="document-title" class="text-2xl font-bold text-gray-900"></h3>
</div> </div>
<div id="document-container" <div id="document-container"
class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-y-auto p-8 markdown-content"> class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-y-auto p-8 markdown-content">
<!-- Document content will be loaded here --> <!-- Document content will be loaded here -->
</div> </div>
</div> </div>
</main> </main>
</div> </div>
<!-- Links Loader -->
<script src="assets/js/links-loader.js"></script>
<!-- Panzoom --> <!-- Panzoom -->
<script src="https://cdn.jsdelivr.net/npm/@panzoom/panzoom@4.5.1/dist/panzoom.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@panzoom/panzoom@4.5.1/dist/panzoom.min.js"></script>
@@ -584,7 +446,7 @@
let currentScale = 1; let currentScale = 1;
// Initialize Mermaid // Initialize Mermaid
mermaid.initialize({ mermaid.initialize({
startOnLoad: false, startOnLoad: false,
theme: 'default', theme: 'default',
flowchart: { flowchart: {
@@ -597,7 +459,7 @@
// Build hierarchical structure from paths // Build hierarchical structure from paths
function buildHierarchy(items, pathPrefix) { function buildHierarchy(items, pathPrefix) {
const hierarchy = { _root: { _items: [], _children: {} } }; const hierarchy = { _root: { _items: [], _children: {} } };
items.forEach(item => { items.forEach(item => {
let relativePath = item.path; let relativePath = item.path;
if (relativePath.startsWith('./')) { if (relativePath.startsWith('./')) {
@@ -609,7 +471,7 @@
const parts = relativePath.split('/'); const parts = relativePath.split('/');
const relevantParts = parts.slice(0, -1); // remove filename const relevantParts = parts.slice(0, -1); // remove filename
let current = hierarchy._root; let current = hierarchy._root;
relevantParts.forEach(part => { relevantParts.forEach(part => {
if (!current._children[part]) { if (!current._children[part]) {
@@ -638,7 +500,7 @@
const panel = document.createElement('div'); const panel = document.createElement('div');
panel.className = 'accordion-panel pl-4 pt-1'; panel.className = 'accordion-panel pl-4 pt-1';
if (items) { if (items) {
items.forEach(item => createLinkFunction(item, panel, 1)); items.forEach(item => createLinkFunction(item, panel, 1));
} }
@@ -693,7 +555,7 @@
const link = document.createElement('a'); const link = document.createElement('a');
link.href = '#'; link.href = '#';
link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' + link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' +
(level > 0 ? ' ' : ''); (level > 0 ? ' ' : '');
link.onclick = (e) => { link.onclick = (e) => {
e.preventDefault(); e.preventDefault();
showView('document', link, doc.path, doc.title); showView('document', link, doc.path, doc.title);
@@ -711,17 +573,17 @@
function createDiagramLink(diagram, parentElement, level) { function createDiagramLink(diagram, parentElement, level) {
const link = document.createElement('a'); const link = document.createElement('a');
link.href = '#'; link.href = '#';
link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' + link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' +
(level > 0 ? ' ' : ''); (level > 0 ? ' ' : '');
link.onclick = (e) => { link.onclick = (e) => {
e.preventDefault(); e.preventDefault();
showView('diagram', link, diagram.path, diagram.title, diagram.type); showView('diagram', link, diagram.path, diagram.title, diagram.type);
}; };
const iconSvg = `<svg class="w-5 h-5 text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"> const iconSvg = `<svg class="w-5 h-5 text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4l2 2h4a2 2 0 012 2v12a2 2 0 01-2 2h-4l-2-2H7z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4l2 2h4a2 2 0 012 2v12a2 2 0 01-2 2h-4l-2-2H7z"></path>
</svg>`; </svg>`;
link.innerHTML = `${iconSvg}<span class="truncate">${diagram.title}</span>`; link.innerHTML = `${iconSvg}<span class="truncate">${diagram.title}</span>`;
parentElement.appendChild(link); parentElement.appendChild(link);
} }
@@ -729,16 +591,16 @@
// Load all diagrams from config // Load all diagrams from config
async function loadAllDiagrams() { async function loadAllDiagrams() {
const dynamicSection = document.getElementById('dynamic-diagrams-section'); const dynamicSection = document.getElementById('dynamic-diagrams-section');
try { try {
const response = await fetch('./assets/diagrams/diagrams-config.json'); const response = await fetch('./assets/diagrams/diagrams-config.json');
if (!response.ok) { if (!response.ok) {
throw new Error(`Failed to load diagrams config: ${response.status}`); throw new Error(`Failed to load diagrams config: ${response.status}`);
} }
const text = await response.text(); const text = await response.text();
allDiagrams = JSON.parse(text); allDiagrams = JSON.parse(text);
if (allDiagrams && allDiagrams.length > 0) { if (allDiagrams && allDiagrams.length > 0) {
const hierarchy = buildHierarchy(allDiagrams, 'assets/diagrams/'); const hierarchy = buildHierarchy(allDiagrams, 'assets/diagrams/');
createAccordionNavigation(hierarchy, dynamicSection, createDiagramLink, 'Diagrams'); createAccordionNavigation(hierarchy, dynamicSection, createDiagramLink, 'Diagrams');
@@ -755,20 +617,20 @@
dynamicSection.appendChild(errorDiv); dynamicSection.appendChild(errorDiv);
} }
} }
// Load all documentation from config // Load all documentation from config
async function loadAllDocuments() { async function loadAllDocuments() {
const documentationSection = document.getElementById('documentation-section'); const documentationSection = document.getElementById('documentation-section');
try { try {
const response = await fetch('./assets/documents/documents-config.json'); const response = await fetch('./assets/documents/documents-config.json');
if (!response.ok) { if (!response.ok) {
throw new Error(`Failed to load documents config: ${response.status}`); throw new Error(`Failed to load documents config: ${response.status}`);
} }
const text = await response.text(); const text = await response.text();
allDocuments = JSON.parse(text); allDocuments = JSON.parse(text);
if (allDocuments && allDocuments.length > 0) { if (allDocuments && allDocuments.length > 0) {
const hierarchy = buildHierarchy(allDocuments, 'assets/documents/'); const hierarchy = buildHierarchy(allDocuments, 'assets/documents/');
createAccordionNavigation(hierarchy, documentationSection, createDocumentLink, 'Documentation'); createAccordionNavigation(hierarchy, documentationSection, createDocumentLink, 'Documentation');
@@ -826,7 +688,7 @@
const response = await fetch(filePath); const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`); if (!response.ok) throw new Error(`Network error: ${response.status}`);
const svgContent = await response.text(); const svgContent = await response.text();
const parser = new DOMParser(); const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgContent, "image/svg+xml"); const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
const svgElement = svgDoc.querySelector('svg'); const svgElement = svgDoc.querySelector('svg');
@@ -834,9 +696,9 @@
if (svgElement) { if (svgElement) {
diagramContainer.innerHTML = ''; diagramContainer.innerHTML = '';
diagramContainer.appendChild(svgElement); diagramContainer.appendChild(svgElement);
panzoomInstance = Panzoom(svgElement, { panzoomInstance = Panzoom(svgElement, {
canvas: true, canvas: true,
maxScale: 10, maxScale: 10,
minScale: 0.3, minScale: 0.3,
startScale: 1 startScale: 1
}); });
@@ -849,19 +711,19 @@
const response = await fetch(filePath); const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`); if (!response.ok) throw new Error(`Network error: ${response.status}`);
const mermaidCode = await response.text(); const mermaidCode = await response.text();
const { svg } = await mermaid.render('mermaidDiagram_' + Date.now(), mermaidCode); const { svg } = await mermaid.render('mermaidDiagram_' + Date.now(), mermaidCode);
diagramContainer.innerHTML = svg; diagramContainer.innerHTML = svg;
const svgElement = diagramContainer.querySelector('svg'); const svgElement = diagramContainer.querySelector('svg');
if (svgElement) { if (svgElement) {
svgElement.style.maxWidth = 'none'; svgElement.style.maxWidth = 'none';
svgElement.style.height = 'auto'; svgElement.style.height = 'auto';
panzoomInstance = Panzoom(svgElement, { panzoomInstance = Panzoom(svgElement, {
canvas: true, canvas: true,
maxScale: 10, maxScale: 10,
minScale: 0.3, minScale: 0.3,
startScale: 1 startScale: 1
}); });
@@ -901,7 +763,7 @@
if (!response.ok) { if (!response.ok) {
throw new Error(`Failed to load document: ${response.status}`); throw new Error(`Failed to load document: ${response.status}`);
} }
const markdownText = await response.text(); const markdownText = await response.text();
const htmlContent = marked.parse(markdownText); const htmlContent = marked.parse(markdownText);
documentContainer.innerHTML = htmlContent; documentContainer.innerHTML = htmlContent;
@@ -922,24 +784,24 @@
} }
} }
zoomInBtn.addEventListener('click', () => { zoomInBtn.addEventListener('click', () => {
if (panzoomInstance) { if (panzoomInstance) {
panzoomInstance.zoomIn(); panzoomInstance.zoomIn();
diagramContainer.focus(); diagramContainer.focus();
} }
}); });
zoomOutBtn.addEventListener('click', () => { zoomOutBtn.addEventListener('click', () => {
if (panzoomInstance) { if (panzoomInstance) {
panzoomInstance.zoomOut(); panzoomInstance.zoomOut();
diagramContainer.focus(); diagramContainer.focus();
} }
}); });
resetBtn.addEventListener('click', () => { resetBtn.addEventListener('click', () => {
if (panzoomInstance) { if (panzoomInstance) {
panzoomInstance.reset(); panzoomInstance.reset();
diagramContainer.focus(); diagramContainer.focus();
} }
}); });

View File

@@ -2,7 +2,7 @@ name: krow
description: "A new Flutter project." description: "A new Flutter project."
publish_to: 'none' publish_to: 'none'
version: 1.0.28+111 version: 1.0.28+112
environment: environment:
sdk: ^3.8.0 sdk: ^3.8.0