mirror of
https://github.com/lukaszraczylo/beat-delivery-methodology.git
synced 2026-06-09 23:04:13 +00:00
Add page deployment
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
name: Deploy BEAT Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: public/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ./public
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
working-directory: ./public
|
||||
run: npm run build
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./public/dist
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -0,0 +1,2 @@
|
||||
public/dist
|
||||
public/node_modules
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="scroll-smooth">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BEAT - Balanced. Empowered. Async. Teams.</title>
|
||||
<meta name="description" content="The BEAT Manifesto - A software delivery methodology built for how developers actually work. Deep work, async communication, individual autonomy, sustainable pace." />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<script>
|
||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+2284
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "beat-methodology",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.21",
|
||||
"vue-router": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"postcss": "^8.4.35",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"vite": "^5.1.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<defs>
|
||||
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3b82f6"/>
|
||||
<stop offset="50%" style="stop-color:#8b5cf6"/>
|
||||
<stop offset="100%" style="stop-color:#06b6d4"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="100" height="100" rx="20" fill="url(#grad)"/>
|
||||
<text x="50" y="68" font-family="Arial, sans-serif" font-size="50" font-weight="bold" fill="white" text-anchor="middle">B</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 532 B |
@@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import NavBar from '@/components/layout/NavBar.vue'
|
||||
import Footer from '@/components/layout/Footer.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<NavBar />
|
||||
<main class="flex-1">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="fade" mode="out-in">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.glass {
|
||||
@apply bg-white/70 dark:bg-gray-800/70 backdrop-blur-lg border border-white/20 dark:border-gray-700/50;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
@apply bg-gradient-to-r from-blue-600 via-purple-600 to-cyan-600 dark:from-blue-400 dark:via-purple-400 dark:to-cyan-400 bg-clip-text text-transparent;
|
||||
}
|
||||
|
||||
.shadow-modern {
|
||||
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.dark .shadow-modern {
|
||||
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-6 py-3 rounded-lg font-medium transition-all duration-300 shadow-lg hover:shadow-xl hover:scale-105;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply glass hover:shadow-lg text-gray-900 dark:text-gray-100 px-6 py-3 rounded-lg font-medium transition-all duration-300 hover:scale-105;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@apply text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
@apply text-lg text-gray-600 dark:text-gray-300;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply glass p-6 rounded-xl transition-all duration-300 hover:shadow-lg;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
@apply text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium transition-colors duration-200;
|
||||
}
|
||||
|
||||
.icon-box {
|
||||
@apply w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 transition-transform duration-300 group-hover:scale-110;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.animate-delay-100 {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
.animate-delay-200 {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
.animate-delay-300 {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
.animate-delay-1000 {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
.animate-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<script setup>
|
||||
const currentYear = new Date().getFullYear()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="bg-gray-50 dark:bg-gray-800/50 border-t border-gray-200 dark:border-gray-700 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-12">
|
||||
<div class="grid md:grid-cols-3 gap-8">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center">
|
||||
<span class="text-white font-bold text-lg">B</span>
|
||||
</div>
|
||||
<span class="text-xl font-bold gradient-text">BEAT</span>
|
||||
</div>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
|
||||
<strong>B</strong>alanced. <strong>E</strong>mpowered. <strong>A</strong>sync. <strong>T</strong>eams.
|
||||
</p>
|
||||
<p class="text-gray-500 dark:text-gray-500 text-sm mt-2">
|
||||
Built for how developers actually work.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4">Quick Links</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li>
|
||||
<RouterLink to="/values" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Core Values
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/principles" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
12 Principles
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/framework" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Framework
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to="/reference" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Quick Reference
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4">Created By</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm mb-3">
|
||||
The BEAT Manifesto was created by <strong>Lukasz Raczylo</strong>.
|
||||
</p>
|
||||
<div class="flex space-x-3">
|
||||
<a
|
||||
href="https://github.com/lukaszraczylo"
|
||||
target="_blank"
|
||||
class="text-gray-500 hover:text-gray-900 dark:hover:text-gray-100 transition-colors"
|
||||
aria-label="GitHub"
|
||||
>
|
||||
<i class="fab fa-github text-xl"></i>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/in/raczylo/"
|
||||
target="_blank"
|
||||
class="text-gray-500 hover:text-blue-600 transition-colors"
|
||||
aria-label="LinkedIn"
|
||||
>
|
||||
<i class="fab fa-linkedin text-xl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 pt-8 border-t border-gray-200 dark:border-gray-700">
|
||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
|
||||
<p class="text-gray-500 dark:text-gray-500 text-sm">
|
||||
© {{ currentYear }} BEAT Manifesto by Lukasz Raczylo. Open for use and adaptation.
|
||||
</p>
|
||||
<p class="text-gray-400 dark:text-gray-600 text-xs">
|
||||
Attribution appreciated. Improvement welcomed. Dogma discouraged.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
@@ -0,0 +1,98 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
import ThemeToggle from './ThemeToggle.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const mobileMenuOpen = ref(false)
|
||||
|
||||
const navItems = [
|
||||
{ path: '/', label: 'Home' },
|
||||
{ path: '/values', label: 'Values' },
|
||||
{ path: '/principles', label: 'Principles' },
|
||||
{ path: '/framework', label: 'Framework' },
|
||||
{ path: '/practices', label: 'Practices' },
|
||||
{ path: '/onboarding', label: 'Onboarding' },
|
||||
{ path: '/anti-patterns', label: 'Anti-Patterns' },
|
||||
{ path: '/reference', label: 'Reference' }
|
||||
]
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
mobileMenuOpen.value = !mobileMenuOpen.value
|
||||
}
|
||||
|
||||
const closeMobileMenu = () => {
|
||||
mobileMenuOpen.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="fixed w-full glass shadow-modern z-50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="flex justify-between h-16 items-center">
|
||||
<RouterLink to="/" class="flex items-center hover:opacity-80 transition-opacity duration-300 gap-2">
|
||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center">
|
||||
<span class="text-white font-bold text-lg">B</span>
|
||||
</div>
|
||||
<span class="text-xl font-bold gradient-text hidden sm:inline">BEAT</span>
|
||||
</RouterLink>
|
||||
|
||||
<div class="hidden lg:flex space-x-4 xl:space-x-6">
|
||||
<RouterLink
|
||||
v-for="item in navItems"
|
||||
:key="item.path"
|
||||
:to="item.path"
|
||||
class="nav-link text-sm"
|
||||
:class="{ 'text-blue-600 dark:text-blue-400': route.path === item.path }"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<ThemeToggle />
|
||||
<a
|
||||
href="https://github.com/lukaszraczylo"
|
||||
target="_blank"
|
||||
class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 min-w-[44px] min-h-[44px] flex items-center justify-center transition-colors duration-200"
|
||||
aria-label="View author on GitHub"
|
||||
>
|
||||
<i class="fab fa-github text-xl"></i>
|
||||
</a>
|
||||
<button
|
||||
@click="toggleMobileMenu"
|
||||
class="lg:hidden text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 min-w-[44px] min-h-[44px] flex items-center justify-center"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<i v-if="!mobileMenuOpen" class="fas fa-bars text-xl"></i>
|
||||
<i v-else class="fas fa-times text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<transition
|
||||
enter-active-class="transition duration-200 ease-out"
|
||||
enter-from-class="opacity-0 -translate-y-2"
|
||||
enter-to-class="opacity-100 translate-y-0"
|
||||
leave-active-class="transition duration-150 ease-in"
|
||||
leave-from-class="opacity-100 translate-y-0"
|
||||
leave-to-class="opacity-0 -translate-y-2"
|
||||
>
|
||||
<div v-if="mobileMenuOpen" class="lg:hidden border-t border-gray-200 dark:border-gray-700">
|
||||
<div class="px-4 py-3 space-y-1 bg-white dark:bg-gray-800">
|
||||
<RouterLink
|
||||
v-for="item in navItems"
|
||||
:key="item.path"
|
||||
:to="item.path"
|
||||
@click="closeMobileMenu"
|
||||
class="block px-3 py-3 text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-700 rounded font-medium"
|
||||
:class="{ 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20': route.path === item.path }"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</nav>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
const isDark = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
isDark.value = document.documentElement.classList.contains('dark')
|
||||
})
|
||||
|
||||
const toggleTheme = () => {
|
||||
isDark.value = !isDark.value
|
||||
if (isDark.value) {
|
||||
document.documentElement.classList.add('dark')
|
||||
localStorage.theme = 'dark'
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
localStorage.theme = 'light'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
@click="toggleTheme"
|
||||
class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 min-w-[44px] min-h-[44px] flex items-center justify-center transition-colors duration-200"
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<i v-if="isDark" class="fas fa-sun text-xl"></i>
|
||||
<i v-else class="fas fa-moon text-xl"></i>
|
||||
</button>
|
||||
</template>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
variant: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: (value) => ['default', 'blue', 'purple', 'green', 'amber', 'red', 'cyan'].includes(value)
|
||||
}
|
||||
})
|
||||
|
||||
const variantClasses = {
|
||||
default: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300',
|
||||
blue: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
||||
purple: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
|
||||
green: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300',
|
||||
amber: 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300',
|
||||
red: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300',
|
||||
cyan: 'bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium"
|
||||
:class="variantClasses[variant]"
|
||||
>
|
||||
<slot></slot>
|
||||
</span>
|
||||
</template>
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
hover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
gradient: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="glass p-6 rounded-xl transition-all duration-300"
|
||||
:class="{ 'hover:shadow-lg hover:-translate-y-1': hover }"
|
||||
>
|
||||
<div v-if="gradient" class="flex items-start gap-4">
|
||||
<div
|
||||
class="icon-box"
|
||||
:class="gradient"
|
||||
>
|
||||
<slot name="icon"></slot>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<slot v-else></slot>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,41 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const copied = ref(false)
|
||||
const codeRef = ref(null)
|
||||
|
||||
const copyCode = async () => {
|
||||
if (codeRef.value) {
|
||||
const text = codeRef.value.innerText
|
||||
await navigator.clipboard.writeText(text)
|
||||
copied.value = true
|
||||
setTimeout(() => {
|
||||
copied.value = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rounded-xl overflow-hidden bg-gray-900 dark:bg-gray-950">
|
||||
<div v-if="title" class="flex items-center justify-between px-4 py-2 bg-gray-800 dark:bg-gray-900 border-b border-gray-700">
|
||||
<span class="text-gray-400 text-sm font-medium">{{ title }}</span>
|
||||
<button
|
||||
@click="copyCode"
|
||||
class="text-gray-400 hover:text-white transition-colors p-1"
|
||||
aria-label="Copy code"
|
||||
>
|
||||
<i v-if="copied" class="fas fa-check text-green-400"></i>
|
||||
<i v-else class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
<pre class="p-4 overflow-x-auto"><code ref="codeRef" class="text-sm text-gray-100 font-mono"><slot></slot></code></pre>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
icon: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
gradient: {
|
||||
type: String,
|
||||
default: 'from-blue-500 to-blue-600'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
|
||||
<div class="flex items-start gap-4">
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300"
|
||||
:class="gradient"
|
||||
>
|
||||
<i :class="icon" class="text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">{{ title }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ description }}</p>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
headers: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
rows: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="glass rounded-xl overflow-hidden">
|
||||
<div v-if="title" class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100">{{ title }}</h3>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="bg-gray-50 dark:bg-gray-800/50">
|
||||
<th
|
||||
v-for="header in headers"
|
||||
:key="header"
|
||||
class="px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider"
|
||||
>
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<tr
|
||||
v-for="(row, index) in rows"
|
||||
:key="index"
|
||||
class="hover:bg-gray-50 dark:hover:bg-gray-800/30 transition-colors"
|
||||
>
|
||||
<td
|
||||
v-for="(cell, cellIndex) in row"
|
||||
:key="cellIndex"
|
||||
class="px-6 py-4 text-sm text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
<span v-html="cell"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,397 @@
|
||||
export const coreValues = [
|
||||
{ valueMore: 'Deep work', over: 'Constant availability', icon: 'fas fa-brain' },
|
||||
{ valueMore: 'Asynchronous communication', over: 'Synchronous meetings', icon: 'fas fa-comments' },
|
||||
{ valueMore: 'Written documentation', over: 'Verbal agreements', icon: 'fas fa-file-alt' },
|
||||
{ valueMore: 'Individual autonomy', over: 'Prescribed processes', icon: 'fas fa-user-check' },
|
||||
{ valueMore: 'Sustainable pace', over: 'Heroic effort', icon: 'fas fa-heart' },
|
||||
{ valueMore: 'Small experiments', over: 'Perfect plans', icon: 'fas fa-flask' }
|
||||
]
|
||||
|
||||
export const teamValues = [
|
||||
{
|
||||
name: 'Trust',
|
||||
icon: 'fas fa-handshake',
|
||||
gradient: 'from-blue-500 to-blue-600',
|
||||
description: 'We assume competence and good intent. We give autonomy because we trust it will be used well. We share information openly because we trust it will be handled responsibly.'
|
||||
},
|
||||
{
|
||||
name: 'Courage',
|
||||
icon: 'fas fa-shield-alt',
|
||||
gradient: 'from-purple-500 to-purple-600',
|
||||
description: 'We speak up when something is wrong. We admit when we don\'t know. We challenge decisions respectfully. We try new approaches even when they might fail.'
|
||||
},
|
||||
{
|
||||
name: 'Candor',
|
||||
icon: 'fas fa-comments',
|
||||
gradient: 'from-cyan-500 to-cyan-600',
|
||||
description: 'We give honest feedback, kindly delivered. We say what we mean in writing. We surface problems early rather than hiding them. We disagree openly, then commit.'
|
||||
},
|
||||
{
|
||||
name: 'Ownership',
|
||||
icon: 'fas fa-flag',
|
||||
gradient: 'from-green-500 to-green-600',
|
||||
description: 'We take responsibility for our work and its impact. We don\'t wait to be told. We fix what we find broken. We see things through to done.'
|
||||
},
|
||||
{
|
||||
name: 'Calm',
|
||||
icon: 'fas fa-spa',
|
||||
gradient: 'from-amber-500 to-amber-600',
|
||||
description: 'We do not create urgency where none exists. We respond thoughtfully, not reactively. We protect each other\'s focus. We choose sustainable over heroic.'
|
||||
}
|
||||
]
|
||||
|
||||
export const principles = {
|
||||
focus: [
|
||||
{
|
||||
number: 1,
|
||||
title: 'Protect the focus state above all else',
|
||||
description: 'The uninterrupted mind produces the best work. We maintain sacred blocks of four hours daily where no meetings, messages, or interruptions are permitted. The maker chooses when this time occurs.'
|
||||
},
|
||||
{
|
||||
number: 2,
|
||||
title: 'Interruptions are not free',
|
||||
description: 'Research shows 52 minutes to reach deep focus, 23 minutes to recover from interruption. Every "quick question" costs more than it appears. Default to async. Wait for the open window.'
|
||||
},
|
||||
{
|
||||
number: 3,
|
||||
title: 'Presence does not equal productivity',
|
||||
description: 'We do not measure hours worked or time online. We measure outcomes delivered. A maker in focus for four hours outproduces a maker in meetings for eight.'
|
||||
}
|
||||
],
|
||||
communication: [
|
||||
{
|
||||
number: 4,
|
||||
title: 'Writing is thinking made visible',
|
||||
description: 'We write by default. Decisions not documented did not happen. Written words can be searched, referenced, and shared across time zones. They outlive the meeting that never was.'
|
||||
},
|
||||
{
|
||||
number: 5,
|
||||
title: 'Synchronous time is expensive. Spend it wisely',
|
||||
description: 'Meetings cost everyone present, simultaneously. We limit them to two hours per week, one hour maximum each. If it can be written, write it. If it must be discussed, write first, then discuss the delta.'
|
||||
},
|
||||
{
|
||||
number: 6,
|
||||
title: 'Response time is not reaction time',
|
||||
description: 'Async means responding when working, not responding immediately. We expect responses within 24 working hours. Urgent means phone call. Everything else waits.'
|
||||
}
|
||||
],
|
||||
autonomy: [
|
||||
{
|
||||
number: 7,
|
||||
title: 'Trust makers to make',
|
||||
description: 'Those who build the thing decide how to build it. They choose their tools, their approach, their schedule, their collaborators. We provide goals and constraints, not instructions.'
|
||||
},
|
||||
{
|
||||
number: 8,
|
||||
title: 'Pull, don\'t push',
|
||||
description: 'Work is not assigned. Work is pulled by those with capacity and interest. Makers select from a prioritized stack. They may skip with reason. They may propose alternatives.'
|
||||
},
|
||||
{
|
||||
number: 9,
|
||||
title: 'The maker\'s "no" is valid',
|
||||
description: 'Makers may refuse work that is unethical, impossible, or poorly conceived. They may challenge priorities. They may push back on requirements. This is not insubordination—it is ownership.'
|
||||
}
|
||||
],
|
||||
sustainability: [
|
||||
{
|
||||
number: 10,
|
||||
title: 'Sustainable pace is not optional',
|
||||
description: 'Overtime is a red flag, not a badge of honor. When deadlines conflict with capacity, we cut scope. We never cut rest. Burnout destroys teams. Recovery is productive. We plan at 80% and leave slack for life.'
|
||||
},
|
||||
{
|
||||
number: 11,
|
||||
title: 'The team\'s health is the Enabler\'s responsibility',
|
||||
description: 'Someone must watch for warning signs: maxed WIP, skipped check-ins, overtime patterns, withdrawal. Someone must shield the team from organizational noise. Someone must say "no" to protect "yes."'
|
||||
},
|
||||
{
|
||||
number: 12,
|
||||
title: 'Exploration time is not a reward. It is a requirement',
|
||||
description: 'Twenty percent of time belongs to the maker for learning, tooling, experiments, and interests. No justification required. No approval needed. This is how we stay sharp. This is how we find better ways.'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const roles = [
|
||||
{
|
||||
name: 'The Maker',
|
||||
icon: 'fas fa-hammer',
|
||||
gradient: 'from-blue-500 to-blue-600',
|
||||
description: 'Builds things. They have full autonomy over implementation. They pull work, propose solutions, review code, and surface blockers. They choose what, how, when, where, and with whom.'
|
||||
},
|
||||
{
|
||||
name: 'The Enabler',
|
||||
icon: 'fas fa-hands-helping',
|
||||
gradient: 'from-purple-500 to-purple-600',
|
||||
description: 'Removes obstacles. They maintain the priority stack, shield from interruptions, monitor wellbeing, and facilitate decisions. They do not dictate—they enable.'
|
||||
},
|
||||
{
|
||||
name: 'The Connector',
|
||||
icon: 'fas fa-project-diagram',
|
||||
gradient: 'from-cyan-500 to-cyan-600',
|
||||
description: 'Maintains knowledge flow. They keep documentation current, ensure context flows between makers, and onboard new members. This role is optional and may rotate.'
|
||||
}
|
||||
]
|
||||
|
||||
export const priorityBuckets = [
|
||||
{
|
||||
name: 'NOW',
|
||||
color: 'red',
|
||||
description: 'Critical, blocking, time-sensitive. Maximum five items.'
|
||||
},
|
||||
{
|
||||
name: 'NEXT',
|
||||
color: 'amber',
|
||||
description: 'High value for this beat. An ordered stack. Pull from top.'
|
||||
},
|
||||
{
|
||||
name: 'LATER',
|
||||
color: 'blue',
|
||||
description: 'Valuable but not urgent. The backlog.'
|
||||
},
|
||||
{
|
||||
name: 'ICEBOX',
|
||||
color: 'gray',
|
||||
description: 'Someday, or needs more thought. Revisit quarterly.'
|
||||
}
|
||||
]
|
||||
|
||||
export const ceremonies = [
|
||||
{
|
||||
name: 'Beat Start',
|
||||
duration: '30 min',
|
||||
purpose: 'Goals, priorities'
|
||||
},
|
||||
{
|
||||
name: 'Beat Close',
|
||||
duration: '30 min',
|
||||
purpose: 'Reflection, health check'
|
||||
},
|
||||
{
|
||||
name: 'Ad-hoc Help',
|
||||
duration: '≤25 min',
|
||||
purpose: 'Unblocking'
|
||||
},
|
||||
{
|
||||
name: 'Brainstorm',
|
||||
duration: '≤1 hr',
|
||||
purpose: 'Creative solving, with 10-minute exit window'
|
||||
}
|
||||
]
|
||||
|
||||
export const constraints = [
|
||||
{ constraint: 'Sacred block', limit: '4 hours daily' },
|
||||
{ constraint: 'Meetings per week', limit: '≤2 hours total' },
|
||||
{ constraint: 'Meeting duration', limit: '≤1 hour each' },
|
||||
{ constraint: 'WIP per maker', limit: '3 items' },
|
||||
{ constraint: 'Planning capacity', limit: '80%' },
|
||||
{ constraint: 'Exploration time', limit: '20% (1 day/beat)' },
|
||||
{ constraint: 'NOW items', limit: 'Max 3-5' },
|
||||
{ constraint: 'Review response', limit: '4 hours' },
|
||||
{ constraint: 'Auto-proceed', limit: '24 hours' }
|
||||
]
|
||||
|
||||
export const definitionOfDone = {
|
||||
code: [
|
||||
'Code works as intended',
|
||||
'Tests pass (existing and new where appropriate)',
|
||||
'Code reviewed by at least one other maker',
|
||||
'Merged to main branch',
|
||||
'Deployable (or deployed, depending on team practice)',
|
||||
'No known defects introduced'
|
||||
],
|
||||
nonCode: [
|
||||
'Meets the stated "done when" condition',
|
||||
'Reviewed by relevant party if needed',
|
||||
'Documented where others can find it'
|
||||
]
|
||||
}
|
||||
|
||||
export const antiPatterns = {
|
||||
process: [
|
||||
{
|
||||
pattern: 'Async theater',
|
||||
looksLike: 'Writing decisions but ignoring comments',
|
||||
fix: 'Genuine engagement or revert to sync'
|
||||
},
|
||||
{
|
||||
pattern: 'Sacred block erosion',
|
||||
looksLike: '"Quick calls" during focus time',
|
||||
fix: 'Enabler enforces boundaries'
|
||||
},
|
||||
{
|
||||
pattern: 'Check-in decay',
|
||||
looksLike: 'Updates become sporadic, then stop',
|
||||
fix: 'Address in retro, understand why'
|
||||
},
|
||||
{
|
||||
pattern: 'Permanent NOW',
|
||||
looksLike: 'Everything is urgent, always',
|
||||
fix: 'If everything is NOW, nothing is'
|
||||
},
|
||||
{
|
||||
pattern: 'Grooming creep',
|
||||
looksLike: 'Meetings sneak back in disguised',
|
||||
fix: 'Ask: could this be async?'
|
||||
},
|
||||
{
|
||||
pattern: 'Document graveyard',
|
||||
looksLike: 'Docs written but never maintained',
|
||||
fix: 'Connector role, or delete stale docs'
|
||||
}
|
||||
],
|
||||
people: [
|
||||
{
|
||||
pattern: 'Hero culture',
|
||||
looksLike: 'Same person handles all crises',
|
||||
fix: 'Rotate, distribute, investigate cause'
|
||||
},
|
||||
{
|
||||
pattern: 'Silent struggle',
|
||||
looksLike: 'Maker stuck for days, says nothing',
|
||||
fix: 'Normalize asking for help early'
|
||||
},
|
||||
{
|
||||
pattern: 'Autonomy hoarding',
|
||||
looksLike: 'One maker claims all interesting work',
|
||||
fix: 'Discuss in retro, Enabler balances'
|
||||
},
|
||||
{
|
||||
pattern: 'Review blocking',
|
||||
looksLike: 'PRs languish waiting for "the" reviewer',
|
||||
fix: 'Anyone can review, auto-proceed rule'
|
||||
},
|
||||
{
|
||||
pattern: 'Passive Enabler',
|
||||
looksLike: 'Enabler doesn\'t shield or prioritize',
|
||||
fix: 'Role clarity, or rotate role'
|
||||
}
|
||||
],
|
||||
organizational: [
|
||||
{
|
||||
pattern: 'Management override',
|
||||
looksLike: 'Exec demands meeting during sacred block',
|
||||
fix: 'Enabler pushes back, escalates pattern'
|
||||
},
|
||||
{
|
||||
pattern: 'Stealth deadlines',
|
||||
looksLike: 'Surprise "we promised client by Friday"',
|
||||
fix: 'Surface commitments before making them'
|
||||
},
|
||||
{
|
||||
pattern: 'Metric theater',
|
||||
looksLike: 'Tracking velocity, points, hours',
|
||||
fix: 'Stop. Measure outcomes, not activity.'
|
||||
},
|
||||
{
|
||||
pattern: 'BEAT in name only',
|
||||
looksLike: 'Ceremonies adopted, principles ignored',
|
||||
fix: 'Re-read manifesto, recommit or don\'t claim BEAT'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const onboarding = {
|
||||
weekOne: {
|
||||
title: 'Week One: Observe',
|
||||
items: [
|
||||
'Read this manifesto',
|
||||
'Shadow async check-ins and board activity',
|
||||
'Observe one Beat Start and/or Beat Close',
|
||||
'Get access to tools, repos, docs',
|
||||
'Meet team members 1:1 (async or sync, their preference)'
|
||||
]
|
||||
},
|
||||
weekTwo: {
|
||||
title: 'Week Two: Participate',
|
||||
items: [
|
||||
'Pull first small task (S-sized)',
|
||||
'Post first daily check-in',
|
||||
'Submit first PR, experience review process',
|
||||
'Ask questions freely—in channel, not DMs (so others learn too)'
|
||||
]
|
||||
},
|
||||
weekThree: {
|
||||
title: 'Week Three: Contribute',
|
||||
items: [
|
||||
'Pull regular work items',
|
||||
'Participate in Beat Close',
|
||||
'Start taking ad-hoc help requests',
|
||||
'Begin exploration time'
|
||||
]
|
||||
},
|
||||
firstMonth: {
|
||||
title: 'First Month Expectations',
|
||||
items: [
|
||||
'Understand the board and priority buckets',
|
||||
'Know how to post check-ins and flag blockers',
|
||||
'Completed several work items end-to-end',
|
||||
'Experienced one full beat cycle',
|
||||
'Identified sacred block timing that works'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const incidentProtocol = [
|
||||
{ step: '1. Alert', description: 'Post immediately in dedicated incident channel. Phone/page if needed.' },
|
||||
{ step: '2. Acknowledge', description: 'Someone claims ownership within 15 minutes.' },
|
||||
{ step: '3. Communicate', description: 'Brief status updates every 30 minutes until resolved.' },
|
||||
{ step: '4. Fix', description: 'Stabilize first, perfect later. Rollback is a valid fix.' },
|
||||
{ step: '5. Document', description: 'Async post-mortem within 48 hours. No blame. Root cause and prevention.' }
|
||||
]
|
||||
|
||||
export const technicalPractices = [
|
||||
{
|
||||
name: 'Continuous Integration',
|
||||
description: 'Merge frequently. Keep main deployable. Automated tests run on every push.'
|
||||
},
|
||||
{
|
||||
name: 'Small Pull Requests',
|
||||
description: 'Easier to review, faster to merge, lower risk. Aim for PRs reviewable in under 30 minutes.'
|
||||
},
|
||||
{
|
||||
name: 'Feature Flags',
|
||||
description: 'Merge incomplete work safely. Decouple deployment from release. Enable experimentation.'
|
||||
},
|
||||
{
|
||||
name: 'Automated Testing',
|
||||
description: 'Tests enable confidence. Confidence enables speed. Coverage targets are team-decided.'
|
||||
},
|
||||
{
|
||||
name: 'Refactoring as You Go',
|
||||
description: 'Leave code better than you found it. Small improvements compound. No permission needed.'
|
||||
},
|
||||
{
|
||||
name: 'Trunk-Based Development',
|
||||
description: 'Short-lived branches. Merge daily. Avoid long-running feature branches.'
|
||||
}
|
||||
]
|
||||
|
||||
export const whereItFits = {
|
||||
worksFor: [
|
||||
'Remote-first or distributed teams',
|
||||
'Senior and mid-level developers',
|
||||
'Product companies',
|
||||
'Teams of 3-8 people',
|
||||
'High-trust environments',
|
||||
'Async-native cultures'
|
||||
],
|
||||
fitsPoorly: [
|
||||
'Junior-heavy teams needing close guidance',
|
||||
'Regulated industries requiring ceremony',
|
||||
'Agency work with constant client sync',
|
||||
'Organizations unwilling to protect focus time'
|
||||
],
|
||||
canAdapt: [
|
||||
'Incident response (see Incidents section)',
|
||||
'Mixed seniority (extra onboarding support)',
|
||||
'Larger teams (multiple BEAT teams with coordination layer)'
|
||||
]
|
||||
}
|
||||
|
||||
export const researchStats = [
|
||||
{ stat: '52 minutes', description: 'to reach deep focus' },
|
||||
{ stat: '23 minutes', description: 'to recover from interruption' },
|
||||
{ stat: '14%', description: 'productive output with 2+ meetings/day' },
|
||||
{ stat: '4 hours', description: 'peak cognitive work capacity daily' },
|
||||
{ stat: '72%', description: 'of meetings are ineffective' }
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import './assets/styles/main.css'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
@@ -0,0 +1,58 @@
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: () => import('@/views/HomeView.vue')
|
||||
},
|
||||
{
|
||||
path: '/values',
|
||||
name: 'Values',
|
||||
component: () => import('@/views/ValuesView.vue')
|
||||
},
|
||||
{
|
||||
path: '/principles',
|
||||
name: 'Principles',
|
||||
component: () => import('@/views/PrinciplesView.vue')
|
||||
},
|
||||
{
|
||||
path: '/framework',
|
||||
name: 'Framework',
|
||||
component: () => import('@/views/FrameworkView.vue')
|
||||
},
|
||||
{
|
||||
path: '/practices',
|
||||
name: 'Practices',
|
||||
component: () => import('@/views/PracticesView.vue')
|
||||
},
|
||||
{
|
||||
path: '/onboarding',
|
||||
name: 'Onboarding',
|
||||
component: () => import('@/views/OnboardingView.vue')
|
||||
},
|
||||
{
|
||||
path: '/anti-patterns',
|
||||
name: 'AntiPatterns',
|
||||
component: () => import('@/views/AntiPatternsView.vue')
|
||||
},
|
||||
{
|
||||
path: '/reference',
|
||||
name: 'Reference',
|
||||
component: () => import('@/views/ReferenceView.vue')
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
if (savedPosition) {
|
||||
return savedPosition
|
||||
} else {
|
||||
return { top: 0 }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,193 @@
|
||||
<script setup>
|
||||
import TableCard from '@/components/ui/TableCard.vue'
|
||||
import { antiPatterns, whereItFits } from '@/data/manifesto'
|
||||
|
||||
const processHeaders = ['Anti-Pattern', 'What It Looks Like', 'The Fix']
|
||||
const processRows = antiPatterns.process.map(p => [
|
||||
`<strong class="text-red-600 dark:text-red-400">${p.pattern}</strong>`,
|
||||
p.looksLike,
|
||||
p.fix
|
||||
])
|
||||
|
||||
const peopleHeaders = ['Anti-Pattern', 'What It Looks Like', 'The Fix']
|
||||
const peopleRows = antiPatterns.people.map(p => [
|
||||
`<strong class="text-amber-600 dark:text-amber-400">${p.pattern}</strong>`,
|
||||
p.looksLike,
|
||||
p.fix
|
||||
])
|
||||
|
||||
const orgHeaders = ['Anti-Pattern', 'What It Looks Like', 'The Fix']
|
||||
const orgRows = antiPatterns.organizational.map(p => [
|
||||
`<strong class="text-purple-600 dark:text-purple-400">${p.pattern}</strong>`,
|
||||
p.looksLike,
|
||||
p.fix
|
||||
])
|
||||
|
||||
const warningSigns = [
|
||||
'Burnout despite 80% planning',
|
||||
'Decisions taking too long async',
|
||||
'Quality declining',
|
||||
'Team feeling disconnected',
|
||||
'Makers disengaged from beat goals'
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-red-50 via-orange-50 to-amber-50 dark:from-gray-900 dark:via-red-900/10 dark:to-orange-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-red-300 dark:bg-red-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-orange-300 dark:bg-orange-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-red-500 to-orange-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-exclamation-triangle text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">Anti-Patterns</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
Common ways teams fail at BEAT—and how to fix them.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Process Anti-Patterns -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="flex items-center gap-4 mb-8">
|
||||
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-red-500 to-red-600 flex items-center justify-center">
|
||||
<i class="fas fa-cogs text-white"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Process Anti-Patterns</h2>
|
||||
</div>
|
||||
<TableCard :headers="processHeaders" :rows="processRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- People Anti-Patterns -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="flex items-center gap-4 mb-8">
|
||||
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center">
|
||||
<i class="fas fa-users text-white"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">People Anti-Patterns</h2>
|
||||
</div>
|
||||
<TableCard :headers="peopleHeaders" :rows="peopleRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Organizational Anti-Patterns -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="flex items-center gap-4 mb-8">
|
||||
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-purple-500 to-purple-600 flex items-center justify-center">
|
||||
<i class="fas fa-building text-white"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Organizational Anti-Patterns</h2>
|
||||
</div>
|
||||
<TableCard :headers="orgHeaders" :rows="orgRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Warning Signs -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">When BEAT Isn't Working</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Signs the methodology isn't serving the team:</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
|
||||
<div
|
||||
v-for="sign in warningSigns"
|
||||
:key="sign"
|
||||
class="glass p-4 rounded-xl border-l-4 border-red-500"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<i class="fas fa-exclamation-circle text-red-500"></i>
|
||||
<span class="text-gray-700 dark:text-gray-300 text-sm">{{ sign }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="w-10 h-10 rounded-lg bg-blue-500 flex items-center justify-center flex-shrink-0">
|
||||
<i class="fas fa-lightbulb text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold text-blue-800 dark:text-blue-200 mb-2">Response</h4>
|
||||
<p class="text-blue-700 dark:text-blue-300 text-sm">
|
||||
Discuss in Beat Close. Adapt the framework. BEAT is a tool, not a religion. If it's not working, change it or choose something else.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Where BEAT Fits -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Where BEAT Fits</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Know your context. Adapt accordingly.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<div class="glass p-6 rounded-xl border-t-4 border-green-500">
|
||||
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
|
||||
<i class="fas fa-check-circle text-green-500"></i>
|
||||
Works Best For
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="item in whereItFits.worksFor"
|
||||
:key="item"
|
||||
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
|
||||
>
|
||||
<i class="fas fa-check text-green-500 text-xs"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl border-t-4 border-red-500">
|
||||
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
|
||||
<i class="fas fa-times-circle text-red-500"></i>
|
||||
Fits Poorly For
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="item in whereItFits.fitsPoorly"
|
||||
:key="item"
|
||||
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
|
||||
>
|
||||
<i class="fas fa-times text-red-500 text-xs"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl border-t-4 border-amber-500">
|
||||
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
|
||||
<i class="fas fa-sliders-h text-amber-500"></i>
|
||||
Can Adapt For
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="item in whereItFits.canAdapt"
|
||||
:key="item"
|
||||
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
|
||||
>
|
||||
<i class="fas fa-adjust text-amber-500 text-xs"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,217 @@
|
||||
<script setup>
|
||||
import CodeBlock from '@/components/ui/CodeBlock.vue'
|
||||
import { roles, priorityBuckets, ceremonies, constraints } from '@/data/manifesto'
|
||||
|
||||
const workItems = [
|
||||
{ name: 'Tasks', time: 'hours', description: 'A one-liner. No ceremony needed.' },
|
||||
{ name: 'Work Items', time: 'days', description: 'Title, context, done condition. Three lines.' },
|
||||
{ name: 'Projects', time: 'week+', description: 'Half-page doc with breakdown. No more.' }
|
||||
]
|
||||
|
||||
const bucketColors = {
|
||||
red: 'from-red-500 to-red-600 border-red-500',
|
||||
amber: 'from-amber-500 to-amber-600 border-amber-500',
|
||||
blue: 'from-blue-500 to-blue-600 border-blue-500',
|
||||
gray: 'from-gray-500 to-gray-600 border-gray-500'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-purple-50 via-indigo-50 to-blue-50 dark:from-gray-900 dark:via-purple-900/10 dark:to-indigo-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-indigo-300 dark:bg-indigo-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-purple-500 to-indigo-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-sitemap text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">The Framework</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
The principles guide us. The framework implements them.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Roles -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">We recognize three roles, loosely held.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="role in roles"
|
||||
:key="role.name"
|
||||
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl bg-gradient-to-br flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300"
|
||||
:class="role.gradient"
|
||||
>
|
||||
<i :class="role.icon" class="text-white text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">{{ role.name }}</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">{{ role.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Beats -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Beats</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
We work in beats—flexible iterations of one to two weeks.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="glass p-8 rounded-2xl">
|
||||
<div class="grid md:grid-cols-3 gap-8">
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fas fa-play text-white"></i>
|
||||
</div>
|
||||
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Start</h4>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">Review priorities and pull initial work</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fas fa-cogs text-white"></i>
|
||||
</div>
|
||||
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">During Beat</h4>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">Check in async daily, work autonomously</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-green-500 to-emerald-500 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fas fa-flag-checkered text-white"></i>
|
||||
</div>
|
||||
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Close</h4>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">Reflect: what worked, what didn't, what to improve</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
|
||||
<p class="text-sm text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
Beats have <strong>goals</strong>, not commitments. We aim; we do not promise. There is no sprint pressure, no velocity tracking, no burndown theater.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Work Items -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Work Items</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Documentation effort scales with task size.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="item in workItems"
|
||||
:key="item.name"
|
||||
class="glass p-6 rounded-xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-3">
|
||||
<span class="text-2xl font-bold gradient-text">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="inline-block px-3 py-1 rounded-full bg-gray-100 dark:bg-gray-700 text-sm text-gray-600 dark:text-gray-400 mb-3">
|
||||
{{ item.time }}
|
||||
</div>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ item.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center">
|
||||
<p class="text-gray-500 dark:text-gray-500 text-sm">
|
||||
We size with <strong>S/M/L</strong>, not story points. We do not groom. We do not point. We do not track velocity.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Prioritization -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Prioritization Buckets</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">We use four buckets to organize work.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div
|
||||
v-for="bucket in priorityBuckets"
|
||||
:key="bucket.name"
|
||||
class="glass p-5 rounded-xl border-l-4 hover:shadow-lg transition-all duration-300"
|
||||
:class="bucketColors[bucket.color]"
|
||||
>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-2">{{ bucket.name }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ bucket.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The Board -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Board</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">A simple kanban with priority built in.</p>
|
||||
</div>
|
||||
|
||||
<CodeBlock title="Board Flow">ICE → LATER → NEXT → IN PROGRESS → DONE</CodeBlock>
|
||||
|
||||
<div class="mt-8 grid sm:grid-cols-3 gap-4">
|
||||
<div class="glass p-4 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="fas fa-user text-blue-500"></i>
|
||||
<span class="font-semibold text-gray-900 dark:text-gray-100">WIP Limit</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">3 items per maker</p>
|
||||
</div>
|
||||
<div class="glass p-4 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="fas fa-sort-amount-up text-purple-500"></i>
|
||||
<span class="font-semibold text-gray-900 dark:text-gray-100">NEXT is Ordered</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">Pull from top</p>
|
||||
</div>
|
||||
<div class="glass p-4 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="fas fa-clock text-amber-500"></i>
|
||||
<span class="font-semibold text-gray-900 dark:text-gray-100">Stale Items</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">Return to backlog after 5 days</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Constraints -->
|
||||
<section class="py-16 bg-gradient-to-br from-purple-600 via-indigo-600 to-blue-600">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-white text-center mb-8">The Numbers</h2>
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
v-for="item in constraints"
|
||||
:key="item.constraint"
|
||||
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
|
||||
>
|
||||
<div class="text-white/70 text-sm mb-1">{{ item.constraint }}</div>
|
||||
<div class="text-white text-xl font-bold">{{ item.limit }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,208 @@
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
import IconCard from '@/components/ui/IconCard.vue'
|
||||
import { researchStats } from '@/data/manifesto'
|
||||
|
||||
const navCards = [
|
||||
{ path: '/values', title: 'Values', description: 'Core & team values that guide everything', icon: 'fas fa-heart', gradient: 'from-red-500 to-pink-500' },
|
||||
{ path: '/principles', title: 'Principles', description: 'The 12 principles of BEAT', icon: 'fas fa-compass', gradient: 'from-blue-500 to-cyan-500' },
|
||||
{ path: '/framework', title: 'Framework', description: 'Roles, beats, and the board', icon: 'fas fa-sitemap', gradient: 'from-purple-500 to-indigo-500' },
|
||||
{ path: '/practices', title: 'Practices', description: 'Meetings, collaboration, incidents', icon: 'fas fa-cogs', gradient: 'from-green-500 to-emerald-500' },
|
||||
{ path: '/onboarding', title: 'Onboarding', description: 'Getting started with BEAT', icon: 'fas fa-user-plus', gradient: 'from-amber-500 to-orange-500' },
|
||||
{ path: '/reference', title: 'Reference', description: 'Quick lookup tables', icon: 'fas fa-book', gradient: 'from-cyan-500 to-blue-500' }
|
||||
]
|
||||
|
||||
const keyNumbers = [
|
||||
{ value: '4hrs', label: 'Sacred Focus Block', icon: 'fas fa-brain' },
|
||||
{ value: '2hrs', label: 'Max Meetings/Week', icon: 'fas fa-calendar' },
|
||||
{ value: '80%', label: 'Planning Capacity', icon: 'fas fa-battery-three-quarters' },
|
||||
{ value: '20%', label: 'Exploration Time', icon: 'fas fa-flask' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero Section -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-16 sm:pb-24 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-cyan-50 dark:from-gray-900 dark:via-blue-900/20 dark:to-purple-900/20 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
<div class="absolute -bottom-8 left-20 w-72 h-72 bg-cyan-300 dark:bg-cyan-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-2000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center">
|
||||
<div class="mb-6 sm:mb-8 flex justify-center animate-fade-in-up">
|
||||
<div class="w-24 h-24 sm:w-32 sm:h-32 rounded-2xl bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600 flex items-center justify-center shadow-xl animate-float">
|
||||
<span class="text-white text-4xl sm:text-5xl font-bold">B</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-gray-900 dark:text-gray-100 mb-4 sm:mb-6 leading-tight animate-fade-in-up animate-delay-100">
|
||||
The <span class="gradient-text">BEAT</span> Manifesto
|
||||
</h1>
|
||||
|
||||
<p class="text-xl sm:text-2xl md:text-3xl text-gray-700 dark:text-gray-200 mb-4 animate-fade-in-up animate-delay-200 font-medium">
|
||||
<span class="text-blue-600 dark:text-blue-400">B</span>alanced.
|
||||
<span class="text-purple-600 dark:text-purple-400">E</span>mpowered.
|
||||
<span class="text-cyan-600 dark:text-cyan-400">A</span>sync.
|
||||
<span class="text-pink-600 dark:text-pink-400">T</span>eams.
|
||||
</p>
|
||||
|
||||
<p class="text-base sm:text-lg text-gray-600 dark:text-gray-400 mb-8 max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
|
||||
A software delivery methodology built for how developers actually work.
|
||||
<br class="hidden sm:block" />
|
||||
Created by <strong>Lukasz Raczylo</strong>.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center animate-fade-in-up animate-delay-300">
|
||||
<RouterLink to="/values" class="btn-primary">
|
||||
<i class="fas fa-book-open mr-2"></i>
|
||||
Start Reading
|
||||
</RouterLink>
|
||||
<RouterLink to="/reference" class="btn-secondary">
|
||||
<i class="fas fa-list mr-2"></i>
|
||||
Quick Reference
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Key Numbers -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6">
|
||||
<div
|
||||
v-for="item in keyNumbers"
|
||||
:key="item.label"
|
||||
class="glass p-6 rounded-xl text-center group hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center mx-auto mb-3 group-hover:scale-110 transition-transform duration-300">
|
||||
<i :class="item.icon" class="text-white"></i>
|
||||
</div>
|
||||
<div class="text-3xl sm:text-4xl font-bold gradient-text mb-1">{{ item.value }}</div>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Introduction -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6">
|
||||
<div class="glass p-8 sm:p-12 rounded-2xl">
|
||||
<p class="text-lg sm:text-xl text-gray-700 dark:text-gray-300 leading-relaxed mb-6">
|
||||
We are uncovering better ways of building software by doing it and helping others do it.
|
||||
</p>
|
||||
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-8">
|
||||
BEAT emerges from research on how developers actually work. We built it for these realities, not against them.
|
||||
</p>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
v-for="stat in researchStats"
|
||||
:key="stat.stat"
|
||||
class="flex items-center gap-3 p-3 rounded-lg bg-white/50 dark:bg-gray-700/50"
|
||||
>
|
||||
<span class="text-xl font-bold text-blue-600 dark:text-blue-400">{{ stat.stat }}</span>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">{{ stat.description }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Navigation Cards -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="section-title">Explore the Manifesto</h2>
|
||||
<p class="section-subtitle">Deep dive into each aspect of BEAT</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<RouterLink
|
||||
v-for="card in navCards"
|
||||
:key="card.path"
|
||||
:to="card.path"
|
||||
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300 hover:-translate-y-1"
|
||||
>
|
||||
<div class="flex items-start gap-4">
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300"
|
||||
:class="card.gradient"
|
||||
>
|
||||
<i :class="card.icon" class="text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
|
||||
{{ card.title }}
|
||||
<i class="fas fa-arrow-right ml-2 text-sm opacity-0 group-hover:opacity-100 transition-opacity"></i>
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ card.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Commitment Section -->
|
||||
<section class="py-16 bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-8">The BEAT Commitment</h2>
|
||||
<div class="grid sm:grid-cols-2 gap-4 text-left">
|
||||
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<i class="fas fa-shield-alt text-white"></i>
|
||||
<span class="text-white font-semibold">Protecting focus</span>
|
||||
</div>
|
||||
<p class="text-white/80 text-sm">We will not interrupt sacred time. We will wait.</p>
|
||||
</div>
|
||||
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<i class="fas fa-pen text-white"></i>
|
||||
<span class="text-white font-semibold">Defaulting to async</span>
|
||||
</div>
|
||||
<p class="text-white/80 text-sm">We will write first, meet only when writing fails.</p>
|
||||
</div>
|
||||
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<i class="fas fa-handshake text-white"></i>
|
||||
<span class="text-white font-semibold">Trusting makers</span>
|
||||
</div>
|
||||
<p class="text-white/80 text-sm">We will provide goals, not instructions. Constraints, not control.</p>
|
||||
</div>
|
||||
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<i class="fas fa-heart text-white"></i>
|
||||
<span class="text-white font-semibold">Sustaining pace</span>
|
||||
</div>
|
||||
<p class="text-white/80 text-sm">We will cut scope before we cut rest. We will plan for humans.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Summary -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="glass p-8 rounded-2xl">
|
||||
<div class="font-mono text-lg sm:text-xl text-gray-700 dark:text-gray-300 space-y-2">
|
||||
<p>We protect focus.</p>
|
||||
<p>We write things down.</p>
|
||||
<p>We trust each other.</p>
|
||||
<p>We work sustainably.</p>
|
||||
<p>We ship and learn.</p>
|
||||
</div>
|
||||
<p class="mt-6 text-gray-500 dark:text-gray-500 italic">
|
||||
BEAT: Built for how developers actually work.
|
||||
</p>
|
||||
<p class="mt-4 text-sm text-gray-400 dark:text-gray-600">
|
||||
BEAT v1.0 by Lukasz Raczylo
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,163 @@
|
||||
<script setup>
|
||||
import { onboarding } from '@/data/manifesto'
|
||||
|
||||
const weeks = [
|
||||
{ ...onboarding.weekOne, icon: 'fas fa-eye', gradient: 'from-blue-500 to-cyan-500' },
|
||||
{ ...onboarding.weekTwo, icon: 'fas fa-hand-pointer', gradient: 'from-purple-500 to-pink-500' },
|
||||
{ ...onboarding.weekThree, icon: 'fas fa-rocket', gradient: 'from-green-500 to-emerald-500' }
|
||||
]
|
||||
|
||||
const whatWeDont = [
|
||||
'Throw new members into complex work immediately',
|
||||
'Expect full productivity in week one',
|
||||
'Leave people to figure it out alone',
|
||||
'Assign mandatory onboarding buddies for months'
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-amber-50 via-orange-50 to-red-50 dark:from-gray-900 dark:via-amber-900/10 dark:to-orange-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-amber-300 dark:bg-amber-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-orange-300 dark:bg-orange-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-user-plus text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">Onboarding to BEAT</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
When someone new joins a BEAT team, here's how to get them up to speed.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Weekly Timeline -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="space-y-8">
|
||||
<div
|
||||
v-for="(week, index) in weeks"
|
||||
:key="week.title"
|
||||
class="glass p-6 sm:p-8 rounded-2xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-start gap-6">
|
||||
<div
|
||||
class="w-16 h-16 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0"
|
||||
:class="week.gradient"
|
||||
>
|
||||
<i :class="week.icon" class="text-white text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ week.title }}</h3>
|
||||
<ul class="space-y-3">
|
||||
<li
|
||||
v-for="item in week.items"
|
||||
:key="item"
|
||||
class="flex items-start gap-3 text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
<i class="fas fa-check-circle text-green-500 mt-1"></i>
|
||||
<span>{{ item }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- First Month -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ onboarding.firstMonth.title }}</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">By the end of the first month, new members should:</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
v-for="(item, index) in onboarding.firstMonth.items"
|
||||
:key="item"
|
||||
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white text-sm font-bold">{{ index + 1 }}</span>
|
||||
</div>
|
||||
<p class="text-gray-700 dark:text-gray-300 text-sm">{{ item }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Connector's Responsibility -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="grid md:grid-cols-2 gap-8">
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center">
|
||||
<i class="fas fa-project-diagram text-white"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">Connector's Responsibility</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-4 text-sm">
|
||||
The Connector (or Enabler if no Connector) ensures:
|
||||
</p>
|
||||
<ul class="space-y-3">
|
||||
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<i class="fas fa-check text-cyan-500 mt-1"></i>
|
||||
Documentation is current and findable
|
||||
</li>
|
||||
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<i class="fas fa-check text-cyan-500 mt-1"></i>
|
||||
New member has a "buddy" for questions (informal, not mandatory pairing)
|
||||
</li>
|
||||
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<i class="fas fa-check text-cyan-500 mt-1"></i>
|
||||
First tasks are well-scoped and achievable
|
||||
</li>
|
||||
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<i class="fas fa-check text-cyan-500 mt-1"></i>
|
||||
Overwhelm is caught early
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl border-l-4 border-red-500">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-red-500 to-pink-500 flex items-center justify-center">
|
||||
<i class="fas fa-times text-white"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">What We Don't Do</h3>
|
||||
</div>
|
||||
<ul class="space-y-3">
|
||||
<li
|
||||
v-for="item in whatWeDont"
|
||||
:key="item"
|
||||
class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
<i class="fas fa-times text-red-500 mt-1"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Summary -->
|
||||
<section class="py-16 bg-gradient-to-br from-amber-500 via-orange-500 to-red-500">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-white mb-4">The Goal</h2>
|
||||
<p class="text-white/90 text-lg">
|
||||
Onboarding should feel like a gradual ramp, not a firehose or an abandonment.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,302 @@
|
||||
<script setup>
|
||||
import CodeBlock from '@/components/ui/CodeBlock.vue'
|
||||
import { ceremonies, incidentProtocol, technicalPractices, definitionOfDone } from '@/data/manifesto'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-green-50 via-emerald-50 to-cyan-50 dark:from-gray-900 dark:via-green-900/10 dark:to-emerald-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-green-300 dark:bg-green-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-emerald-300 dark:bg-emerald-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-green-500 to-emerald-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-cogs text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">Practices</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
How we work day-to-day: meetings, collaboration, incidents, and technical practices.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Meetings -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Meetings</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Hard limits protect our time.</p>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-2xl mb-8">
|
||||
<div class="grid sm:grid-cols-3 gap-6 text-center">
|
||||
<div>
|
||||
<div class="text-3xl font-bold gradient-text mb-2">2 hours</div>
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">per week total</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-3xl font-bold gradient-text mb-2">1 hour</div>
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">maximum per meeting</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-3xl font-bold gradient-text mb-2">Agenda</div>
|
||||
<div class="text-gray-600 dark:text-gray-400 text-sm">required or cancelled</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div
|
||||
v-for="ceremony in ceremonies"
|
||||
:key="ceremony.name"
|
||||
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">{{ ceremony.name }}</h3>
|
||||
<div class="text-sm text-blue-600 dark:text-blue-400 mb-2">{{ ceremony.duration }}</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ ceremony.purpose }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 p-4 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
|
||||
<p class="text-sm text-amber-800 dark:text-amber-200">
|
||||
<i class="fas fa-lightbulb mr-2"></i>
|
||||
If a topic needs more than one hour: write first, comment async, meet on the delta. Never extend.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Daily Check-in -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Daily Check-in</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Replace standups with written updates.</p>
|
||||
</div>
|
||||
|
||||
<div class="max-w-xl mx-auto">
|
||||
<CodeBlock title="Check-in Template">Working on: [current task]
|
||||
Blocked by: [nothing / specific issue]</CodeBlock>
|
||||
|
||||
<div class="mt-6 grid sm:grid-cols-3 gap-4">
|
||||
<div class="glass p-4 rounded-lg text-center">
|
||||
<i class="fas fa-clock text-blue-500 text-xl mb-2"></i>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">Post once daily</div>
|
||||
</div>
|
||||
<div class="glass p-4 rounded-lg text-center">
|
||||
<i class="fas fa-stopwatch text-purple-500 text-xl mb-2"></i>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">Two minutes</div>
|
||||
</div>
|
||||
<div class="glass p-4 rounded-lg text-center">
|
||||
<i class="fas fa-users-slash text-green-500 text-xl mb-2"></i>
|
||||
<div class="text-sm text-gray-600 dark:text-gray-400">No gathering required</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Collaboration -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Collaboration</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Default mode is solo deep work.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-8">
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
|
||||
<i class="fas fa-hand-holding-heart text-blue-500 mr-2"></i>
|
||||
Ad-hoc Help
|
||||
</h3>
|
||||
<ol class="space-y-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<li class="flex items-start gap-3">
|
||||
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">1</span>
|
||||
Post when stuck
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">2</span>
|
||||
Someone responds when available
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">3</span>
|
||||
Sync briefly if needed
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">4</span>
|
||||
Return to solo work
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
|
||||
<i class="fas fa-users text-purple-500 mr-2"></i>
|
||||
Multi-Maker Work
|
||||
</h3>
|
||||
<ul class="space-y-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
<li class="flex items-start gap-3">
|
||||
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
|
||||
<span><strong>Break vertically.</strong> Each maker owns an end-to-end slice.</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
|
||||
<span><strong>Define interfaces first.</strong> Work in parallel against contracts.</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
|
||||
<span><strong>Coordinate via doc.</strong> One feature doc as source of truth.</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
|
||||
<span><strong>Sync only when stuck.</strong> Document outcome. Return to async.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 p-4 rounded-lg bg-gray-100 dark:bg-gray-800">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 text-center">
|
||||
We do not schedule pairing. We do not mandate walkthroughs. We do not assign buddies. Collaboration is initiated by those who need it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Definition of Done -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Definition of Done</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Work is not done until it meets these criteria.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-8">
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
|
||||
<i class="fas fa-code text-blue-500 mr-2"></i>
|
||||
For Code
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="item in definitionOfDone.code"
|
||||
:key="item"
|
||||
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
<i class="fas fa-check text-green-500"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
|
||||
<i class="fas fa-file-alt text-purple-500 mr-2"></i>
|
||||
For Non-Code
|
||||
</h3>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
v-for="item in definitionOfDone.nonCode"
|
||||
:key="item"
|
||||
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
<i class="fas fa-check text-green-500"></i>
|
||||
{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
|
||||
<p class="text-sm text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
The team owns this definition. Adjust it as needed. But once agreed, honor it. "Done" means done—not "done but..." or "done except..."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Incidents -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incidents & Emergencies</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">When production breaks, normal rules suspend temporarily.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-8 mb-8">
|
||||
<div class="glass p-6 rounded-xl border-l-4 border-red-500">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">What Qualifies</h3>
|
||||
<ul class="space-y-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
<li class="flex items-center gap-2">
|
||||
<i class="fas fa-exclamation-triangle text-red-500"></i>
|
||||
Users cannot complete critical actions
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<i class="fas fa-exclamation-triangle text-red-500"></i>
|
||||
Data integrity is at risk
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<i class="fas fa-exclamation-triangle text-red-500"></i>
|
||||
Security vulnerability being exploited
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<i class="fas fa-exclamation-triangle text-red-500"></i>
|
||||
Significant revenue or reputation impact
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">Incident Protocol</h3>
|
||||
<ol class="space-y-3">
|
||||
<li
|
||||
v-for="step in incidentProtocol"
|
||||
:key="step.step"
|
||||
class="flex items-start gap-3"
|
||||
>
|
||||
<span class="font-bold text-blue-600 dark:text-blue-400 text-sm">{{ step.step }}</span>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">{{ step.description }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
|
||||
<p class="text-sm text-amber-800 dark:text-amber-200">
|
||||
<i class="fas fa-lightbulb mr-2"></i>
|
||||
This is not normal work. Incidents should be rare. If they're frequent, that's a systemic problem to solve—not a reason to abandon sustainable pace.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Technical Practices -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Technical Practices</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">Optional practices that align well with BEAT principles.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
v-for="practice in technicalPractices"
|
||||
:key="practice.name"
|
||||
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">{{ practice.name }}</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">{{ practice.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-8 text-center text-sm text-gray-500 dark:text-gray-500">
|
||||
These are not mandated. They are offered as practices that support focus, speed, and quality. Adopt what serves you. Discard what doesn't.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,100 @@
|
||||
<script setup>
|
||||
import { principles } from '@/data/manifesto'
|
||||
|
||||
const categories = [
|
||||
{ key: 'focus', title: 'On Focus', icon: 'fas fa-bullseye', gradient: 'from-blue-500 to-cyan-500', color: 'blue' },
|
||||
{ key: 'communication', title: 'On Communication', icon: 'fas fa-comments', gradient: 'from-purple-500 to-pink-500', color: 'purple' },
|
||||
{ key: 'autonomy', title: 'On Autonomy', icon: 'fas fa-user-shield', gradient: 'from-green-500 to-emerald-500', color: 'green' },
|
||||
{ key: 'sustainability', title: 'On Sustainability', icon: 'fas fa-leaf', gradient: 'from-amber-500 to-orange-500', color: 'amber' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-green-50 dark:from-gray-900 dark:via-blue-900/10 dark:to-purple-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-compass text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">The Twelve Principles</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
Guiding principles organized into four categories: Focus, Communication, Autonomy, and Sustainability.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Principles by Category -->
|
||||
<section
|
||||
v-for="category in categories"
|
||||
:key="category.key"
|
||||
class="py-16 transition-colors duration-300"
|
||||
:class="categories.indexOf(category) % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800/50'"
|
||||
>
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="flex items-center gap-4 mb-8">
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center"
|
||||
:class="category.gradient"
|
||||
>
|
||||
<i :class="category.icon" class="text-white"></i>
|
||||
</div>
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">{{ category.title }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div
|
||||
v-for="principle in principles[category.key]"
|
||||
:key="principle.number"
|
||||
class="glass p-6 sm:p-8 rounded-xl hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-start gap-4">
|
||||
<div
|
||||
class="w-10 h-10 rounded-full bg-gradient-to-br flex items-center justify-center flex-shrink-0"
|
||||
:class="category.gradient"
|
||||
>
|
||||
<span class="text-white font-bold">{{ principle.number }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">
|
||||
{{ principle.title }}
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
{{ principle.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Summary -->
|
||||
<section class="py-16 bg-gradient-to-br from-blue-600 via-purple-600 to-green-600">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-white mb-6">Principles in Summary</h2>
|
||||
<div class="grid sm:grid-cols-2 gap-4 text-left">
|
||||
<div
|
||||
v-for="category in categories"
|
||||
:key="category.key"
|
||||
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
|
||||
>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i :class="category.icon" class="text-white"></i>
|
||||
<span class="text-white font-semibold">{{ category.title }}</span>
|
||||
</div>
|
||||
<ul class="text-white/80 text-sm space-y-1">
|
||||
<li v-for="p in principles[category.key]" :key="p.number">
|
||||
{{ p.number }}. {{ p.title.split('.')[0] }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,164 @@
|
||||
<script setup>
|
||||
import TableCard from '@/components/ui/TableCard.vue'
|
||||
import CodeBlock from '@/components/ui/CodeBlock.vue'
|
||||
import { coreValues, teamValues, constraints, priorityBuckets, roles, ceremonies, definitionOfDone, incidentProtocol } from '@/data/manifesto'
|
||||
|
||||
const coreValuesHeaders = ['We Value More', 'Over']
|
||||
const coreValuesRows = coreValues.map(v => [
|
||||
`<strong>${v.valueMore}</strong>`,
|
||||
v.over
|
||||
])
|
||||
|
||||
const teamValuesHeaders = ['Value', 'Meaning']
|
||||
const teamValuesRows = teamValues.map(v => [
|
||||
`<strong>${v.name}</strong>`,
|
||||
v.description.split('.')[0] + '.'
|
||||
])
|
||||
|
||||
const constraintsHeaders = ['Constraint', 'Limit']
|
||||
const constraintsRows = constraints.map(c => [
|
||||
c.constraint,
|
||||
`<strong class="text-blue-600 dark:text-blue-400">${c.limit}</strong>`
|
||||
])
|
||||
|
||||
const bucketsHeaders = ['Bucket', 'Meaning']
|
||||
const bucketsRows = priorityBuckets.map(b => [
|
||||
`<strong>${b.name}</strong>`,
|
||||
b.description.split('.')[0]
|
||||
])
|
||||
|
||||
const rolesHeaders = ['Role', 'Purpose']
|
||||
const rolesRows = roles.map(r => [
|
||||
`<strong>${r.name.replace('The ', '')}</strong>`,
|
||||
r.description.split('.')[0]
|
||||
])
|
||||
|
||||
const ceremoniesHeaders = ['Event', 'Duration', 'Purpose']
|
||||
const ceremoniesRows = ceremonies.map(c => [
|
||||
`<strong>${c.name}</strong>`,
|
||||
c.duration,
|
||||
c.purpose
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-cyan-50 via-blue-50 to-indigo-50 dark:from-gray-900 dark:via-cyan-900/10 dark:to-blue-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-cyan-300 dark:bg-cyan-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-book text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">Quick Reference</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
Everything you need at a glance. Print this page and keep it handy.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Core Values -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
|
||||
<TableCard :headers="coreValuesHeaders" :rows="coreValuesRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Team Values -->
|
||||
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Team Values</h2>
|
||||
<TableCard :headers="teamValuesHeaders" :rows="teamValuesRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The Numbers -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Numbers</h2>
|
||||
<TableCard :headers="constraintsHeaders" :rows="constraintsRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Buckets & Roles -->
|
||||
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="grid md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Priority Buckets</h2>
|
||||
<TableCard :headers="bucketsHeaders" :rows="bucketsRows" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
|
||||
<TableCard :headers="rolesHeaders" :rows="rolesRows" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Ceremonies -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Ceremonies</h2>
|
||||
<TableCard :headers="ceremoniesHeaders" :rows="ceremoniesRows" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Templates -->
|
||||
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-6">Templates</h2>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3">Daily Check-in</h3>
|
||||
<CodeBlock>Working on: [task]
|
||||
Blocked by: [nothing / issue]</CodeBlock>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3">Spotted Issue Decision</h3>
|
||||
<CodeBlock>Blocking? → Fix now
|
||||
≤5 min? → Fix now
|
||||
>5 min? → Log it, continue
|
||||
Critical? → Flag team</CodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Definition of Done -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Definition of Done (Code)</h2>
|
||||
<CodeBlock>{{ definitionOfDone.code.map(item => '✓ ' + item).join('\n') }}</CodeBlock>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Incident Protocol -->
|
||||
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incident Protocol</h2>
|
||||
<CodeBlock>{{ incidentProtocol.map(step => step.step + ' ' + step.description.split('.')[0]).join('\n') }}</CodeBlock>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer Note -->
|
||||
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="glass p-6 rounded-xl">
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm mb-2">
|
||||
BEAT v1.0 by <strong>Lukasz Raczylo</strong>
|
||||
</p>
|
||||
<p class="text-gray-500 dark:text-gray-500 text-xs">
|
||||
Attribution appreciated. Improvement welcomed. Dogma discouraged.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup>
|
||||
import IconCard from '@/components/ui/IconCard.vue'
|
||||
import TableCard from '@/components/ui/TableCard.vue'
|
||||
import { coreValues, teamValues } from '@/data/manifesto'
|
||||
|
||||
const coreValuesHeaders = ['We Value More', 'Over']
|
||||
const coreValuesRows = coreValues.map(v => [
|
||||
`<strong class="text-blue-600 dark:text-blue-400">${v.valueMore}</strong>`,
|
||||
v.over
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-red-50 via-pink-50 to-purple-50 dark:from-gray-900 dark:via-red-900/10 dark:to-pink-900/10 transition-colors duration-300"></div>
|
||||
<div class="absolute top-0 -left-4 w-72 h-72 bg-red-300 dark:bg-red-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
|
||||
<div class="absolute top-0 -right-4 w-72 h-72 bg-pink-300 dark:bg-pink-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
|
||||
|
||||
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-red-500 to-pink-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
|
||||
<i class="fas fa-heart text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="section-title animate-fade-in-up animate-delay-100">Values</h1>
|
||||
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
|
||||
The foundation of everything we do. What we value in our work and how we treat each other.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Core Values -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
While there is value in the items on the right, we value the items on the left more.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<TableCard :headers="coreValuesHeaders" :rows="coreValuesRows" />
|
||||
|
||||
<!-- Visual Cards -->
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 mt-12">
|
||||
<div
|
||||
v-for="value in coreValues"
|
||||
:key="value.valueMore"
|
||||
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-center gap-4 mb-3">
|
||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
|
||||
<i :class="value.icon" class="text-white text-sm"></i>
|
||||
</div>
|
||||
<h3 class="font-semibold text-gray-900 dark:text-gray-100">{{ value.valueMore }}</h3>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-500">
|
||||
over {{ value.over }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Team Values -->
|
||||
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Five Team Values</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
|
||||
Beyond what we value in our work, we hold these values in how we treat each other.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div
|
||||
v-for="value in teamValues"
|
||||
:key="value.name"
|
||||
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
|
||||
>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div
|
||||
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center group-hover:scale-110 transition-transform duration-300"
|
||||
:class="value.gradient"
|
||||
>
|
||||
<i :class="value.icon" class="text-white"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ value.name }}</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
|
||||
{{ value.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Summary -->
|
||||
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
|
||||
<div class="glass p-8 rounded-2xl">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Values in Action</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
These values are not just words on a page. They guide our daily decisions, how we interact with each other, and how we approach every piece of work. When in doubt, return to these values.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||
],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
mono: ['JetBrains Mono', 'monospace'],
|
||||
},
|
||||
animation: {
|
||||
'fade-in-up': 'fadeInUp 0.6s ease-out',
|
||||
'float': 'float 3s ease-in-out infinite',
|
||||
},
|
||||
keyframes: {
|
||||
fadeInUp: {
|
||||
'0%': { opacity: '0', transform: 'translateY(20px)' },
|
||||
'100%': { opacity: '1', transform: 'translateY(0)' },
|
||||
},
|
||||
float: {
|
||||
'0%, 100%': { transform: 'translateY(0px)' },
|
||||
'50%': { transform: 'translateY(-10px)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src')
|
||||
}
|
||||
},
|
||||
base: './'
|
||||
})
|
||||
Reference in New Issue
Block a user