refactor: enhance UI components and navigation structure, implement export functionality for wizard steps, and update routing for improved user experience
This commit is contained in:
parent
37ab8d7bab
commit
d7e52293e4
18 changed files with 3802 additions and 3318 deletions
114
app.vue
114
app.vue
|
|
@ -5,65 +5,69 @@
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<template v-if="$route.meta.layout !== 'template'">
|
<template v-if="$route.meta.layout !== 'template'">
|
||||||
<UContainer class="bg-transparent">
|
<UContainer class="bg-transparent">
|
||||||
<header class="py-4 flex items-center justify-between">
|
<header class="py-6">
|
||||||
<div class="flex items-center gap-4">
|
<div class="relative flex items-center justify-center">
|
||||||
<NuxtLink to="/" class="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
|
||||||
<UIcon name="i-heroicons-rocket-launch" class="text-primary-500" />
|
|
||||||
<h1 class="font-semibold text-black dark:text-white">Urgent Tools</h1>
|
|
||||||
</NuxtLink>
|
|
||||||
<nav class="hidden md:flex items-center gap-1" role="navigation" aria-label="Main navigation">
|
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/"
|
to="/"
|
||||||
|
class="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
||||||
|
<UIcon
|
||||||
|
name="i-heroicons-rocket-launch"
|
||||||
|
class="text-primary-500" />
|
||||||
|
<h1
|
||||||
|
class="font-semibold text-black dark:text-white text-center">
|
||||||
|
Urgent Tools
|
||||||
|
</h1>
|
||||||
|
</NuxtLink>
|
||||||
|
<div class="absolute right-0">
|
||||||
|
<ColorModeToggle />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<nav
|
||||||
|
class="mt-4 flex items-center justify-center gap-1"
|
||||||
|
role="navigation"
|
||||||
|
aria-label="Main navigation">
|
||||||
|
<NuxtLink
|
||||||
|
to="/coop-planner"
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/' }"
|
:class="{
|
||||||
>
|
'bg-neutral-100 dark:bg-neutral-800': isCoopSection,
|
||||||
Dashboard
|
}">
|
||||||
|
Co-Op in 6 Months
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/mix"
|
to="/wizards"
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/mix' }"
|
:class="{
|
||||||
>
|
'bg-neutral-100 dark:bg-neutral-800':
|
||||||
Revenue Mix
|
$route.path === '/wizards',
|
||||||
|
}">
|
||||||
|
Wizards
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
variant="ghost"
|
||||||
|
disabled
|
||||||
|
class="px-3 py-2 text-sm text-black dark:text-white rounded-md opacity-60 cursor-not-allowed">
|
||||||
|
Downloads
|
||||||
|
</UButton>
|
||||||
|
</nav>
|
||||||
|
<nav
|
||||||
|
v-if="isCoopSection"
|
||||||
|
class="mt-2 flex items-center justify-center gap-1"
|
||||||
|
role="navigation"
|
||||||
|
aria-label="Co-Op in 6 Months sub navigation">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/budget"
|
v-for="item in coopMenu[0]"
|
||||||
|
:key="item.to"
|
||||||
|
:to="item.to"
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/budget' }"
|
:class="{
|
||||||
>
|
'bg-neutral-100 dark:bg-neutral-800':
|
||||||
Budget
|
route.path === item.to,
|
||||||
</NuxtLink>
|
}">
|
||||||
<NuxtLink
|
{{ item.label }}
|
||||||
to="/scenarios"
|
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/scenarios' }"
|
|
||||||
>
|
|
||||||
Scenarios
|
|
||||||
</NuxtLink>
|
|
||||||
<NuxtLink
|
|
||||||
to="/cash"
|
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/cash' }"
|
|
||||||
>
|
|
||||||
Cash
|
|
||||||
</NuxtLink>
|
|
||||||
<NuxtLink
|
|
||||||
to="/glossary"
|
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path === '/glossary' }"
|
|
||||||
>
|
|
||||||
Glossary
|
|
||||||
</NuxtLink>
|
|
||||||
<NuxtLink
|
|
||||||
to="/templates"
|
|
||||||
class="px-3 py-2 text-sm text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
|
||||||
:class="{ 'bg-neutral-100 dark:bg-neutral-800': $route.path.startsWith('/templates') }"
|
|
||||||
>
|
|
||||||
Templates
|
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
|
||||||
<ColorModeToggle />
|
|
||||||
</header>
|
</header>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
@ -78,5 +82,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// noop
|
const coopMenu = [
|
||||||
|
[
|
||||||
|
{ label: "Dashboard", to: "/" },
|
||||||
|
{ label: "Revenue Mix", to: "/mix" },
|
||||||
|
{ label: "Budget", to: "/budget" },
|
||||||
|
{ label: "Scenarios", to: "/scenarios" },
|
||||||
|
{ label: "Cash", to: "/cash" },
|
||||||
|
{ label: "Glossary", to: "/glossary" },
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const isCoopSection = computed(() => route.path === "/coop-planner");
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,20 @@
|
||||||
html.dark { @apply bg-neutral-950 text-neutral-100; }
|
html.dark { @apply bg-neutral-950 text-neutral-100; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable all animations, transitions, and smooth scrolling app-wide */
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
scroll-behavior: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
animation: none !important;
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.document-page {
|
||||||
|
@apply max-w-4xl mx-auto bg-white relative p-8 border-1 border-neutral-900 dark:border-neutral-100;
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-6">
|
<div class="max-w-4xl mx-auto space-y-6">
|
||||||
|
<!-- Section Header with Export Controls -->
|
||||||
|
<div class="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-2xl font-black text-black mb-4">
|
<h3 class="text-2xl font-black text-black mb-2">
|
||||||
Where does your money go?
|
Where does your money go?
|
||||||
</h3>
|
</h3>
|
||||||
|
<p class="text-neutral-600">
|
||||||
|
Add costs like rent, tools, insurance, or other recurring expenses.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton variant="outline" color="gray" size="sm" @click="exportCosts">
|
||||||
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-1" />
|
||||||
|
Export
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Overhead Costs -->
|
<!-- Overhead Costs -->
|
||||||
|
|
@ -31,7 +43,7 @@
|
||||||
class="text-center py-12 border-4 border-dashed border-black rounded-xl bg-white shadow-lg">
|
class="text-center py-12 border-4 border-dashed border-black rounded-xl bg-white shadow-lg">
|
||||||
<h4 class="font-medium text-neutral-900 mb-2">No overhead costs yet</h4>
|
<h4 class="font-medium text-neutral-900 mb-2">No overhead costs yet</h4>
|
||||||
<p class="text-sm text-neutral-500 mb-4">
|
<p class="text-sm text-neutral-500 mb-4">
|
||||||
Add costs like rent, tools, insurance, or other recurring expenses.
|
Get started by adding your first overhead cost.
|
||||||
</p>
|
</p>
|
||||||
<UButton
|
<UButton
|
||||||
@click="addOverheadCost"
|
@click="addOverheadCost"
|
||||||
|
|
@ -202,4 +214,24 @@ function addOverheadCost() {
|
||||||
function removeCost(id: string) {
|
function removeCost(id: string) {
|
||||||
budgetStore.removeOverheadLine(id);
|
budgetStore.removeOverheadLine(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportCosts() {
|
||||||
|
const exportData = {
|
||||||
|
overheadCosts: overheadCosts.value,
|
||||||
|
exportedAt: new Date().toISOString(),
|
||||||
|
section: "costs",
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = `coop-costs-${new Date().toISOString().split("T")[0]}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="max-w-4xl mx-auto space-y-6">
|
||||||
|
<!-- Section Header with Export Controls -->
|
||||||
|
<div class="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-6">
|
<h3 class="text-2xl font-black text-black mb-2">Who's on your team?</h3>
|
||||||
<h3 class="text-2xl font-black text-black">Who's on your team?</h3>
|
<p class="text-neutral-600">
|
||||||
|
Add everyone who'll be working in the co-op, even if they're not ready
|
||||||
|
to be paid yet.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton
|
||||||
|
variant="outline"
|
||||||
|
color="gray"
|
||||||
|
size="sm"
|
||||||
|
@click="exportMembers">
|
||||||
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-1" />
|
||||||
|
Export
|
||||||
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="members.length > 0"
|
v-if="members.length > 0"
|
||||||
@click="addMember"
|
@click="addMember"
|
||||||
|
|
@ -26,8 +41,7 @@
|
||||||
class="text-center py-12 border-4 border-dashed border-black rounded-xl bg-white shadow-lg">
|
class="text-center py-12 border-4 border-dashed border-black rounded-xl bg-white shadow-lg">
|
||||||
<h4 class="font-medium text-neutral-900 mb-2">No team members yet</h4>
|
<h4 class="font-medium text-neutral-900 mb-2">No team members yet</h4>
|
||||||
<p class="text-sm text-neutral-500 mb-4">
|
<p class="text-sm text-neutral-500 mb-4">
|
||||||
Add everyone who'll be working in the co-op, even if they're not ready
|
Get started by adding your first team member.
|
||||||
to be paid yet.
|
|
||||||
</p>
|
</p>
|
||||||
<UButton @click="addMember" size="lg" variant="solid" color="primary">
|
<UButton @click="addMember" size="lg" variant="solid" color="primary">
|
||||||
<UIcon name="i-heroicons-plus" class="mr-2" />
|
<UIcon name="i-heroicons-plus" class="mr-2" />
|
||||||
|
|
@ -218,4 +232,24 @@ function addMember() {
|
||||||
function removeMember(id: string) {
|
function removeMember(id: string) {
|
||||||
membersStore.removeMember(id);
|
membersStore.removeMember(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportMembers() {
|
||||||
|
const exportData = {
|
||||||
|
members: members.value,
|
||||||
|
exportedAt: new Date().toISOString(),
|
||||||
|
section: "members",
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = `coop-members-${new Date().toISOString().split("T")[0]}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="max-w-4xl mx-auto space-y-6">
|
||||||
|
<!-- Section Header with Export Controls -->
|
||||||
|
<div class="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-2xl font-black text-black mb-6">
|
<h3 class="text-2xl font-black text-black mb-2">
|
||||||
What's your equal hourly wage?
|
What's your equal hourly wage?
|
||||||
</h3>
|
</h3>
|
||||||
|
<p class="text-neutral-600">
|
||||||
|
Set the hourly rate that all co-op members will earn for their work.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton
|
||||||
|
variant="outline"
|
||||||
|
color="gray"
|
||||||
|
size="sm"
|
||||||
|
@click="exportPolicies">
|
||||||
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-1" />
|
||||||
|
Export
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="max-w-md">
|
<div class="max-w-md">
|
||||||
|
|
@ -101,4 +117,32 @@ onMounted(() => {
|
||||||
setDefaults();
|
setDefaults();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function exportPolicies() {
|
||||||
|
const exportData = {
|
||||||
|
policies: {
|
||||||
|
equalHourlyWage: policiesStore.equalHourlyWage,
|
||||||
|
payrollOncostPct: policiesStore.payrollOncostPct,
|
||||||
|
savingsTargetMonths: policiesStore.savingsTargetMonths,
|
||||||
|
minCashCushionAmount: policiesStore.minCashCushionAmount,
|
||||||
|
deferredCapHoursPerQtr: policiesStore.deferredCapHoursPerQtr,
|
||||||
|
deferredSunsetMonths: policiesStore.deferredSunsetMonths,
|
||||||
|
volunteerScope: policiesStore.volunteerScope,
|
||||||
|
},
|
||||||
|
exportedAt: new Date().toISOString(),
|
||||||
|
section: "policies",
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = `coop-policies-${new Date().toISOString().split("T")[0]}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="max-w-4xl mx-auto space-y-6">
|
||||||
|
<!-- Section Header with Export Controls -->
|
||||||
|
<div class="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-6">
|
<h3 class="text-2xl font-black text-black mb-2">
|
||||||
<h3 class="text-2xl font-black text-black">
|
|
||||||
Where will your money come from?
|
Where will your money come from?
|
||||||
</h3>
|
</h3>
|
||||||
|
<p class="text-neutral-600">
|
||||||
|
Add sources like client work, grants, product sales, or donations.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton
|
||||||
|
variant="outline"
|
||||||
|
color="gray"
|
||||||
|
size="sm"
|
||||||
|
@click="exportStreams">
|
||||||
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-1" />
|
||||||
|
Export
|
||||||
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="streams.length > 0"
|
v-if="streams.length > 0"
|
||||||
@click="addRevenueStream"
|
@click="addRevenueStream"
|
||||||
|
|
@ -29,7 +43,7 @@
|
||||||
No revenue streams yet
|
No revenue streams yet
|
||||||
</h4>
|
</h4>
|
||||||
<p class="text-sm text-neutral-500 mb-4">
|
<p class="text-sm text-neutral-500 mb-4">
|
||||||
Add sources like client work, grants, product sales, or donations.
|
Get started by adding your first revenue source.
|
||||||
</p>
|
</p>
|
||||||
<UButton
|
<UButton
|
||||||
@click="addRevenueStream"
|
@click="addRevenueStream"
|
||||||
|
|
@ -247,4 +261,24 @@ function addRevenueStream() {
|
||||||
function removeStream(id: string) {
|
function removeStream(id: string) {
|
||||||
streamsStore.removeStream(id);
|
streamsStore.removeStream(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportStreams() {
|
||||||
|
const exportData = {
|
||||||
|
streams: streams.value,
|
||||||
|
exportedAt: new Date().toISOString(),
|
||||||
|
section: "revenue",
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = `coop-revenue-${new Date().toISOString().split("T")[0]}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-6">
|
<div class="max-w-4xl mx-auto space-y-6">
|
||||||
|
<!-- Section Header with Export Controls -->
|
||||||
|
<div class="flex items-center justify-between mb-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium mb-4">Review & Complete</h3>
|
<h3 class="text-2xl font-black text-black mb-2">Review & Complete</h3>
|
||||||
<p class="text-neutral-600 mb-6">
|
<p class="text-neutral-600">
|
||||||
Review your setup and complete the wizard to start using your co-op
|
Review your setup and complete the wizard to start using your co-op
|
||||||
tool.
|
tool.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<UButton variant="outline" color="gray" size="sm" @click="exportSetup">
|
||||||
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-1" />
|
||||||
|
Export All
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<!-- Members Summary -->
|
<!-- Members Summary -->
|
||||||
|
|
@ -284,9 +293,6 @@
|
||||||
</UButton>
|
</UButton>
|
||||||
|
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
<UButton variant="outline" color="gray" @click="exportSetup">
|
|
||||||
Export Setup
|
|
||||||
</UButton>
|
|
||||||
<UButton
|
<UButton
|
||||||
@click="completeSetup"
|
@click="completeSetup"
|
||||||
:disabled="!canComplete"
|
:disabled="!canComplete"
|
||||||
|
|
|
||||||
101
components/WizardSubnav.vue
Normal file
101
components/WizardSubnav.vue
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="border-b border-neutral-200 dark:border-neutral-700 bg-neutral-50 dark:bg-neutral-900">
|
||||||
|
<div class="max-w-4xl mx-auto px-4 py-3">
|
||||||
|
<nav class="flex items-center space-x-1 overflow-x-auto">
|
||||||
|
<!-- Main Setup Wizard -->
|
||||||
|
<NuxtLink
|
||||||
|
to="/wizard"
|
||||||
|
class="inline-flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="
|
||||||
|
isActive('/wizard')
|
||||||
|
? 'bg-black text-white dark:bg-white dark:text-black'
|
||||||
|
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||||
|
">
|
||||||
|
<UIcon name="i-heroicons-cog-6-tooth" class="w-4 h-4 mr-2" />
|
||||||
|
Setup Wizard
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
|
<!-- Divider -->
|
||||||
|
<div class="h-6 w-px bg-neutral-300 dark:bg-neutral-600 mx-2"></div>
|
||||||
|
|
||||||
|
<!-- Template Wizards -->
|
||||||
|
<NuxtLink
|
||||||
|
v-for="wizard in templateWizards"
|
||||||
|
:key="wizard.id"
|
||||||
|
:to="wizard.path"
|
||||||
|
class="inline-flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="
|
||||||
|
isActive(wizard.path)
|
||||||
|
? 'bg-black text-white dark:bg-white dark:text-black'
|
||||||
|
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||||
|
">
|
||||||
|
<UIcon :name="wizard.icon" class="w-4 h-4 mr-2" />
|
||||||
|
{{ wizard.name }}
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
|
<!-- All Wizards Link -->
|
||||||
|
<div class="h-6 w-px bg-neutral-300 dark:bg-neutral-600 mx-2"></div>
|
||||||
|
<NuxtLink
|
||||||
|
to="/wizards"
|
||||||
|
class="inline-flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap"
|
||||||
|
:class="
|
||||||
|
isActive('/wizards')
|
||||||
|
? 'bg-black text-white dark:bg-white dark:text-black'
|
||||||
|
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-neutral-100 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||||
|
">
|
||||||
|
<UIcon name="i-heroicons-squares-plus" class="w-4 h-4 mr-2" />
|
||||||
|
All Wizards
|
||||||
|
</NuxtLink>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
// Template wizards data - matches the wizards.vue page
|
||||||
|
const templateWizards = [
|
||||||
|
{
|
||||||
|
id: "membership-agreement",
|
||||||
|
name: "Membership Agreement",
|
||||||
|
icon: "i-heroicons-user-group",
|
||||||
|
path: "/templates/membership-agreement",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "conflict-resolution-framework",
|
||||||
|
name: "Conflict Resolution",
|
||||||
|
icon: "i-heroicons-scale",
|
||||||
|
path: "/templates/conflict-resolution-framework",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "tech-charter",
|
||||||
|
name: "Tech Charter",
|
||||||
|
icon: "i-heroicons-cog-6-tooth",
|
||||||
|
path: "/templates/tech-charter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "decision-framework",
|
||||||
|
name: "Decision Helper",
|
||||||
|
icon: "i-heroicons-light-bulb",
|
||||||
|
path: "/templates/decision-framework",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function isActive(path: string): boolean {
|
||||||
|
return route.path === path;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Ensure horizontal scroll on mobile */
|
||||||
|
nav {
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
nav::-webkit-scrollbar {
|
||||||
|
display: none; /* WebKit */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
export default defineNuxtRouteMiddleware((to) => {
|
export default defineNuxtRouteMiddleware((to) => {
|
||||||
// Skip middleware for wizard, templates, and API routes
|
// Skip middleware for coop-planner, wizards, templates, and API routes
|
||||||
if (to.path === "/wizard" || to.path.startsWith("/templates") || to.path.startsWith("/api/")) {
|
if (
|
||||||
|
to.path === "/coop-planner" ||
|
||||||
|
to.path === "/wizards" ||
|
||||||
|
to.path.startsWith("/templates") ||
|
||||||
|
to.path.startsWith("/api/")
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,6 +20,6 @@ export default defineNuxtRouteMiddleware((to) => {
|
||||||
streamsStore.hasValidStreams;
|
streamsStore.hasValidStreams;
|
||||||
|
|
||||||
if (!setupComplete) {
|
if (!setupComplete) {
|
||||||
return navigateTo("/wizard");
|
return navigateTo("/coop-planner");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,17 @@ export default defineNuxtConfig({
|
||||||
|
|
||||||
modules: ["@pinia/nuxt", "@nuxtjs/color-mode", "@nuxt/ui"],
|
modules: ["@pinia/nuxt", "@nuxtjs/color-mode", "@nuxt/ui"],
|
||||||
|
|
||||||
|
// Redirect old Templates landing to Wizards (keep detail routes working)
|
||||||
|
routeRules: {
|
||||||
|
"/templates": { redirect: { to: "/wizards", statusCode: 301 } },
|
||||||
|
"/wizard": { redirect: { to: "/coop-planner", statusCode: 301 } },
|
||||||
|
},
|
||||||
|
|
||||||
colorMode: {
|
colorMode: {
|
||||||
preference: 'system',
|
preference: "system",
|
||||||
fallback: 'light',
|
fallback: "light",
|
||||||
classSuffix: '',
|
classSuffix: "",
|
||||||
dataValue: 'dark'
|
dataValue: "dark",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Google Fonts
|
// Google Fonts
|
||||||
|
|
|
||||||
8
pages/coop-planner.vue
Normal file
8
pages/coop-planner.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<template>
|
||||||
|
<WizardPage />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// Reuse the existing wizard content by importing it as a component
|
||||||
|
import WizardPage from "~/pages/wizard.vue";
|
||||||
|
</script>
|
||||||
|
|
@ -562,8 +562,8 @@ async function restartWizard() {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||||
isResetting.value = false;
|
isResetting.value = false;
|
||||||
|
|
||||||
// Navigate to wizard
|
// Navigate to coop planner
|
||||||
await navigateTo("/wizard");
|
await navigateTo("/coop-planner");
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Wizard Subnav -->
|
||||||
|
<WizardSubnav />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="min-h-screen bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100 py-8 px-4"
|
class="template-wrapper bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100"
|
||||||
style="font-family: 'Ubuntu', monospace">
|
style="font-family: 'Ubuntu', monospace">
|
||||||
<div class="max-w-4xl mx-auto relative">
|
<!-- Spacer for consistency -->
|
||||||
|
<div class="py-4"></div>
|
||||||
|
|
||||||
|
<div class="max-w-4xl mx-auto relative px-4">
|
||||||
<div
|
<div
|
||||||
class="bg-white dark:bg-neutral-950 border border-black dark:border-white decision-framework-container">
|
class="bg-white dark:bg-neutral-950 border-2 border-neutral-900 dark:border-neutral-100 decision-framework-container">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div
|
<div
|
||||||
class="bg-black dark:bg-white text-white dark:text-black px-8 py-12 text-center header-section">
|
class="bg-black dark:bg-white text-white dark:text-black px-8 py-12 text-center header-section">
|
||||||
|
|
@ -13,7 +20,7 @@
|
||||||
class="absolute top-4 left-4 right-0 bottom-0 dither-shadow-header"></div>
|
class="absolute top-4 left-4 right-0 bottom-0 dither-shadow-header"></div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative bg-black dark:bg-white text-white dark:text-black px-4 py-4 border border-white dark:border-black">
|
class="relative bg-black dark:bg-white text-white dark:text-black px-4 py-4 border-2 border-neutral-100 dark:border-neutral-900">
|
||||||
<h1
|
<h1
|
||||||
class="text-3xl font-bold mb-2 uppercase"
|
class="text-3xl font-bold mb-2 uppercase"
|
||||||
style="font-family: 'Ubuntu', monospace">
|
style="font-family: 'Ubuntu', monospace">
|
||||||
|
|
@ -38,7 +45,7 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="w-full bg-white dark:bg-black h-2 border border-white dark:border-black">
|
class="w-full bg-white dark:bg-black h-2 border-2 border-neutral-100 dark:border-neutral-900">
|
||||||
<div
|
<div
|
||||||
class="bg-black dark:bg-white h-full transition-all duration-300 progress-dither"
|
class="bg-black dark:bg-white h-full transition-all duration-300 progress-dither"
|
||||||
:style="{
|
:style="{
|
||||||
|
|
@ -61,7 +68,7 @@
|
||||||
How urgent is this decision?
|
How urgent is this decision?
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="bg-white dark:bg-neutral-950 p-8 border border-black dark:border-white relative">
|
class="bg-white dark:bg-neutral-950 p-8 border-2 border-neutral-900 dark:border-neutral-100 relative">
|
||||||
<!-- Dithered shadow background -->
|
<!-- Dithered shadow background -->
|
||||||
<div
|
<div
|
||||||
class="absolute top-2 left-2 right-0 bottom-0 dither-shadow"></div>
|
class="absolute top-2 left-2 right-0 bottom-0 dither-shadow"></div>
|
||||||
|
|
@ -120,7 +127,9 @@
|
||||||
]"
|
]"
|
||||||
@click="selectOption('reversible', option.value)">
|
@click="selectOption('reversible', option.value)">
|
||||||
<div class="font-semibold mb-1">{{ option.title }}</div>
|
<div class="font-semibold mb-1">{{ option.title }}</div>
|
||||||
<div class="text-sm opacity-85">{{ option.description }}</div>
|
<div class="text-sm opacity-85">
|
||||||
|
{{ option.description }}
|
||||||
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -142,7 +151,9 @@
|
||||||
]"
|
]"
|
||||||
@click="selectOption('expertise', option.value)">
|
@click="selectOption('expertise', option.value)">
|
||||||
<div class="font-semibold mb-1">{{ option.title }}</div>
|
<div class="font-semibold mb-1">{{ option.title }}</div>
|
||||||
<div class="text-sm opacity-85">{{ option.description }}</div>
|
<div class="text-sm opacity-85">
|
||||||
|
{{ option.description }}
|
||||||
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -164,7 +175,9 @@
|
||||||
]"
|
]"
|
||||||
@click="selectOption('impact', option.value)">
|
@click="selectOption('impact', option.value)">
|
||||||
<div class="font-semibold mb-1">{{ option.title }}</div>
|
<div class="font-semibold mb-1">{{ option.title }}</div>
|
||||||
<div class="text-sm opacity-85">{{ option.description }}</div>
|
<div class="text-sm opacity-85">
|
||||||
|
{{ option.description }}
|
||||||
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -186,7 +199,9 @@
|
||||||
]"
|
]"
|
||||||
@click="selectOption('options', option.value)">
|
@click="selectOption('options', option.value)">
|
||||||
<div class="font-semibold mb-1">{{ option.title }}</div>
|
<div class="font-semibold mb-1">{{ option.title }}</div>
|
||||||
<div class="text-sm opacity-85">{{ option.description }}</div>
|
<div class="text-sm opacity-85">
|
||||||
|
{{ option.description }}
|
||||||
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -208,7 +223,9 @@
|
||||||
]"
|
]"
|
||||||
@click="selectOption('investment', option.value)">
|
@click="selectOption('investment', option.value)">
|
||||||
<div class="font-semibold mb-1">{{ option.title }}</div>
|
<div class="font-semibold mb-1">{{ option.title }}</div>
|
||||||
<div class="text-sm opacity-85">{{ option.description }}</div>
|
<div class="text-sm opacity-85">
|
||||||
|
{{ option.description }}
|
||||||
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -236,11 +253,11 @@
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-center mt-12 pt-8 border-t border-neutral-200">
|
class="flex justify-between items-center mt-12 pt-8 border-t-2 border-neutral-200">
|
||||||
<button
|
<button
|
||||||
v-if="currentStep > 1"
|
v-if="currentStep > 1"
|
||||||
@click="previousStep"
|
@click="previousStep"
|
||||||
class="px-6 py-3 text-violet-700 border border-violet-700 rounded-md hover:bg-violet-50 transition-all duration-200">
|
class="px-6 py-3 text-violet-700 border-2 border-violet-700 rounded-md hover:bg-violet-50 transition-all duration-200">
|
||||||
← Previous
|
← Previous
|
||||||
</button>
|
</button>
|
||||||
<div v-else></div>
|
<div v-else></div>
|
||||||
|
|
@ -264,7 +281,7 @@
|
||||||
<div
|
<div
|
||||||
v-if="showResult"
|
v-if="showResult"
|
||||||
data-results
|
data-results
|
||||||
class="border-t border-neutral-200 pt-12">
|
class="border-t-2 border-neutral-200 pt-12">
|
||||||
<UCard class="bg-neutral-50">
|
<UCard class="bg-neutral-50">
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-2xl font-semibold text-violet-700 mb-2">
|
<h2 class="text-2xl font-semibold text-violet-700 mb-2">
|
||||||
|
|
@ -355,7 +372,10 @@
|
||||||
<UButton @click="resetForm" color="violet">
|
<UButton @click="resetForm" color="violet">
|
||||||
Try Another Decision
|
Try Another Decision
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton @click="printResult" variant="outline" color="violet">
|
<UButton
|
||||||
|
@click="printResult"
|
||||||
|
variant="outline"
|
||||||
|
color="violet">
|
||||||
Print Recommendation
|
Print Recommendation
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -365,6 +385,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
|
||||||
|
|
@ -1,121 +1,66 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Wizard Subnav -->
|
||||||
|
<WizardSubnav />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="template-wrapper bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100">
|
class="template-wrapper bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100">
|
||||||
<!-- Export Controls -->
|
<!-- Export Controls -->
|
||||||
<div class="export-controls no-print no-pdf">
|
<div class="max-w-4xl mx-auto no-print no-pdf mb-8 py-4">
|
||||||
<div class="export-content">
|
<div class="flex justify-end">
|
||||||
<div class="export-section">
|
<div class="flex items-center gap-4">
|
||||||
<h3 class="export-title">Export to:</h3>
|
<UButton
|
||||||
<div class="export-buttons">
|
variant="outline"
|
||||||
<button
|
color="gray"
|
||||||
@click="exportPDF"
|
size="lg"
|
||||||
class="export-btn primary"
|
@click="exportPDF">
|
||||||
title="Download PDF">
|
<UIcon name="i-heroicons-document-arrow-down" class="mr-2" />
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round">
|
|
||||||
<path
|
|
||||||
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
||||||
<polyline points="14,2 14,8 20,8" />
|
|
||||||
<line x1="16" y1="13" x2="8" y2="13" />
|
|
||||||
<line x1="16" y1="17" x2="8" y2="17" />
|
|
||||||
<polyline points="10,9 9,9 8,9" />
|
|
||||||
</svg>
|
|
||||||
PDF
|
PDF
|
||||||
</button>
|
</UButton>
|
||||||
<button
|
<UButton
|
||||||
@click="handlePrint"
|
variant="outline"
|
||||||
class="export-btn"
|
color="gray"
|
||||||
title="Print Document">
|
size="lg"
|
||||||
<svg
|
@click="handlePrint">
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<UIcon name="i-heroicons-printer" class="mr-2" />
|
||||||
width="16"
|
Print
|
||||||
height="16"
|
</UButton>
|
||||||
viewBox="0 0 24 24"
|
<UButton
|
||||||
fill="none"
|
variant="outline"
|
||||||
stroke="currentColor"
|
color="gray"
|
||||||
stroke-width="2"
|
size="lg"
|
||||||
stroke-linecap="round"
|
@click="exportText">
|
||||||
stroke-linejoin="round">
|
<UIcon name="i-heroicons-document-text" class="mr-2" />
|
||||||
<polyline points="6,9 6,2 18,2 18,9" />
|
Text
|
||||||
<path
|
</UButton>
|
||||||
d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" />
|
<UButton
|
||||||
<rect x="6" y="14" width="12" height="8" />
|
variant="outline"
|
||||||
</svg>
|
color="gray"
|
||||||
PRINT
|
size="lg"
|
||||||
</button>
|
@click="exportMarkdown">
|
||||||
<button
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-2" />
|
||||||
@click="exportText"
|
Markdown
|
||||||
class="export-btn"
|
</UButton>
|
||||||
title="Download Text">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round">
|
|
||||||
<path
|
|
||||||
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
||||||
<polyline points="14,2 14,8 20,8" />
|
|
||||||
<line x1="16" y1="13" x2="8" y2="13" />
|
|
||||||
<line x1="16" y1="17" x2="8" y2="17" />
|
|
||||||
<line x1="12" y1="9" x2="8" y2="9" />
|
|
||||||
</svg>
|
|
||||||
TXT
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
@click="exportMarkdown"
|
|
||||||
class="export-btn"
|
|
||||||
title="Download Markdown">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round">
|
|
||||||
<path
|
|
||||||
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
||||||
<polyline points="14,2 14,8 20,8" />
|
|
||||||
<line x1="12" y1="18" x2="12" y2="12" />
|
|
||||||
<path d="m9 15 3-3 3 3" />
|
|
||||||
</svg>
|
|
||||||
MD
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Document Container -->
|
<!-- Document Container -->
|
||||||
<div
|
<div class="document-page">
|
||||||
class="document-page max-w-[8.5in] min-h-[11in] mx-auto bg-white relative p-[0.5in]">
|
|
||||||
<div class="template-content">
|
<div class="template-content">
|
||||||
<!-- Document Title -->
|
<!-- Document Title -->
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<h1
|
<h1
|
||||||
class="text-3xl md:text-5xl font-bold uppercase text-neutral-900 dark:text-white m-0 py-4 border-t-2 border-b-2 border-neutral-900 dark:border-neutral-100"
|
class="text-3xl md:text-5xl font-bold uppercase text-neutral-900 dark:text-white m-0 py-4 border-t-2 border-b-2 border-neutral-900 dark:border-neutral-100"
|
||||||
:data-coop-name="formData.cooperativeName || 'Worker Cooperative'">
|
:data-coop-name="
|
||||||
|
formData.cooperativeName || 'Worker Cooperative'
|
||||||
|
">
|
||||||
MEMBERSHIP AGREEMENT
|
MEMBERSHIP AGREEMENT
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 1: Who We Are -->
|
<!-- Section 1: Who We Are -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
1. Who We Are
|
1. Who We Are
|
||||||
|
|
@ -249,7 +194,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 2: Membership -->
|
<!-- Section 2: Membership -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
2. Membership
|
2. Membership
|
||||||
|
|
@ -282,9 +227,9 @@
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<p class="content-paragraph">
|
<p class="content-paragraph">
|
||||||
New members join through a consent process, which means existing
|
New members join through a consent process, which means
|
||||||
members must agree that adding this person won't harm the
|
existing members must agree that adding this person won't harm
|
||||||
cooperative.
|
the cooperative.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
||||||
|
|
@ -318,7 +263,8 @@
|
||||||
Leaving the Cooperative
|
Leaving the Cooperative
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<p class="content-paragraph flex items-baseline gap-2 flex-wrap">
|
<p
|
||||||
|
class="content-paragraph flex items-baseline gap-2 flex-wrap">
|
||||||
Members can leave anytime with
|
Members can leave anytime with
|
||||||
<UInput
|
<UInput
|
||||||
v-model="formData.noticeDays"
|
v-model="formData.noticeDays"
|
||||||
|
|
@ -350,14 +296,16 @@
|
||||||
@change="autoSave" />
|
@change="autoSave" />
|
||||||
days
|
days
|
||||||
</li>
|
</li>
|
||||||
<li>Maintain respectful ongoing relationships when possible</li>
|
<li>
|
||||||
|
Maintain respectful ongoing relationships when possible
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 3: How We Make Decisions -->
|
<!-- Section 3: How We Make Decisions -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
3. How We Make Decisions
|
3. How We Make Decisions
|
||||||
|
|
@ -470,14 +418,16 @@
|
||||||
hours notice
|
hours notice
|
||||||
</li>
|
</li>
|
||||||
<li>We rotate who facilitates meetings</li>
|
<li>We rotate who facilitates meetings</li>
|
||||||
<li>Decisions and reasoning get documented in shared notes</li>
|
<li>
|
||||||
|
Decisions and reasoning get documented in shared notes
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 4: Money and Labour -->
|
<!-- Section 4: Money and Labour -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
4. Money and Labour
|
4. Money and Labour
|
||||||
|
|
@ -571,7 +521,9 @@
|
||||||
Financial Transparency
|
Financial Transparency
|
||||||
</h3>
|
</h3>
|
||||||
<ul class="content-list my-2 pl-6 list-disc">
|
<ul class="content-list my-2 pl-6 list-disc">
|
||||||
<li>All members can access all financial records anytime</li>
|
<li>
|
||||||
|
All members can access all financial records anytime
|
||||||
|
</li>
|
||||||
<li>Monthly financial check-ins at meetings</li>
|
<li>Monthly financial check-ins at meetings</li>
|
||||||
<li>
|
<li>
|
||||||
Quarterly reviews of our runway (how many months we can
|
Quarterly reviews of our runway (how many months we can
|
||||||
|
|
@ -584,7 +536,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 5: Roles and Responsibilities -->
|
<!-- Section 5: Roles and Responsibilities -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
5. Roles and Responsibilities
|
5. Roles and Responsibilities
|
||||||
|
|
@ -636,7 +588,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 6: Conflict and Care -->
|
<!-- Section 6: Conflict and Care -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
6. Conflict and Care
|
6. Conflict and Care
|
||||||
|
|
@ -665,14 +617,16 @@
|
||||||
<li>We check in about capacity and wellbeing regularly</li>
|
<li>We check in about capacity and wellbeing regularly</li>
|
||||||
<li>We honour diverse access needs</li>
|
<li>We honour diverse access needs</li>
|
||||||
<li>We maintain flexibility for life circumstances</li>
|
<li>We maintain flexibility for life circumstances</li>
|
||||||
<li>We contribute to mutual aid when members face hardship</li>
|
<li>
|
||||||
|
We contribute to mutual aid when members face hardship
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 7: Changing This Agreement -->
|
<!-- Section 7: Changing This Agreement -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
7. Changing This Agreement
|
7. Changing This Agreement
|
||||||
|
|
@ -686,13 +640,13 @@
|
||||||
placeholder="year"
|
placeholder="year"
|
||||||
class="inline-field"
|
class="inline-field"
|
||||||
@change="autoSave" />
|
@change="autoSave" />
|
||||||
and update it through our consent process. Small clarifications can
|
and update it through our consent process. Small clarifications
|
||||||
happen anytime; structural changes need full member consent.
|
can happen anytime; structural changes need full member consent.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 8: If We Need to Close -->
|
<!-- Section 8: If We Need to Close -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
8. If We Need to Close
|
8. If We Need to Close
|
||||||
|
|
@ -718,7 +672,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 9: Legal Bits -->
|
<!-- Section 9: Legal Bits -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
9. Legal Bits
|
9. Legal Bits
|
||||||
|
|
@ -774,7 +728,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Section 10: Agreement Review -->
|
<!-- Section 10: Agreement Review -->
|
||||||
<div class="section-card mb-6 p-0">
|
<div class="section-card">
|
||||||
<h2
|
<h2
|
||||||
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
||||||
10. Agreement Review
|
10. Agreement Review
|
||||||
|
|
@ -817,6 +771,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
@ -1662,6 +1617,11 @@ const downloadFile = (content, filename, mimeType) => {
|
||||||
color: #1f2937;
|
color: #1f2937;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Section styling */
|
||||||
|
.section-card {
|
||||||
|
@apply border border-neutral-200 dark:border-neutral-800 rounded-lg p-5 mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
.section-card:last-child::after {
|
.section-card:last-child::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Wizard Subnav -->
|
||||||
|
<WizardSubnav />
|
||||||
|
|
||||||
<section class="py-8 max-w-4xl mx-auto">
|
<section class="py-8 max-w-4xl mx-auto">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="mb-10">
|
<div class="mb-10">
|
||||||
|
|
@ -170,7 +174,9 @@
|
||||||
<span v-else>4</span>
|
<span v-else>4</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-2xl font-black text-black">Revenue streams</h3>
|
<h3 class="text-2xl font-black text-black">
|
||||||
|
Revenue streams
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UIcon
|
<UIcon
|
||||||
|
|
@ -208,7 +214,9 @@
|
||||||
<span v-else>5</span>
|
<span v-else>5</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-2xl font-black text-black">Review & finish</h3>
|
<h3 class="text-2xl font-black text-black">
|
||||||
|
Review & finish
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UIcon
|
<UIcon
|
||||||
|
|
@ -264,6 +272,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
|
||||||
339
pages/wizards.vue
Normal file
339
pages/wizards.vue
Normal file
|
|
@ -0,0 +1,339 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Wizard Subnav -->
|
||||||
|
<WizardSubnav />
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="template-container min-h-screen bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100 py-8"
|
||||||
|
style="font-family: 'Ubuntu', 'Ubuntu Mono', monospace">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 relative">
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1
|
||||||
|
class="text-3xl font-bold text-neutral-900 dark:text-white mb-2"
|
||||||
|
style="font-family: 'Ubuntu', monospace">
|
||||||
|
Wizards
|
||||||
|
</h1>
|
||||||
|
<p class="text-neutral-700 dark:text-neutral-200">
|
||||||
|
Fillable forms for cooperative documents. Data saves locally in your
|
||||||
|
browser.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<div
|
||||||
|
v-for="template in templates"
|
||||||
|
:key="template.id"
|
||||||
|
class="template-card h-full flex flex-col">
|
||||||
|
<div
|
||||||
|
class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||||||
|
<div
|
||||||
|
class="relative bg-white dark:bg-neutral-950 border border-black dark:border-white p-6 h-full flex flex-col">
|
||||||
|
<div class="mb-4">
|
||||||
|
<h3
|
||||||
|
class="text-xl font-semibold text-neutral-900 dark:text-white">
|
||||||
|
{{ template.name }}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-neutral-700 dark:text-neutral-200 mb-4">
|
||||||
|
{{ template.description }}
|
||||||
|
</p>
|
||||||
|
<div class="flex flex-wrap gap-2 mb-4">
|
||||||
|
<span
|
||||||
|
v-for="tag in template.tags"
|
||||||
|
:key="tag"
|
||||||
|
class="px-2 py-1 text-xs font-medium bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-900 border border-black dark:border-white dither-tag">
|
||||||
|
{{ tag }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-neutral-700 dark:text-neutral-200 mb-4">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<span>{{ template.estimatedTime }}</span>
|
||||||
|
<span>{{ template.fields }} fields</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex gap-2 mt-auto">
|
||||||
|
<NuxtLink
|
||||||
|
:to="template.path"
|
||||||
|
class="flex-1 px-4 py-2 bg-black dark:bg-white text-white dark:text-black text-center font-medium tracking-wider hover:underline"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
START WIZARD
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
v-if="hasData(template.id)"
|
||||||
|
:to="template.path"
|
||||||
|
class="px-4 py-2 bg-white dark:bg-neutral-950 text-black dark:text-white border border-black dark:border-white hover:bg-white dark:hover:bg-neutral-950 transition-colors bitmap-button"
|
||||||
|
title="Continue from saved data"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
RESUME
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-12 help-section">
|
||||||
|
<div class="absolute top-2 left-2 w-full h-full dither-shadow"></div>
|
||||||
|
<div
|
||||||
|
class="relative bg-white dark:bg-neutral-950 border border-black dark:border-white p-6">
|
||||||
|
<h2
|
||||||
|
class="text-xl font-semibold text-neutral-900 dark:text-white mb-3"
|
||||||
|
style="font-family: 'Ubuntu', monospace">
|
||||||
|
How Wizards Work
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
class="grid md:grid-cols-2 gap-6 text-neutral-900 dark:text-neutral-100">
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="font-medium mb-2 text-neutral-900 dark:text-white"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
FILL OUT FORMS
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-neutral-700 dark:text-neutral-200">
|
||||||
|
Wizards include form fields for all necessary information.
|
||||||
|
Data auto-saves as you type.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="font-medium mb-2 text-neutral-900 dark:text-white"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
LOCAL STORAGE
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-neutral-700 dark:text-neutral-200">
|
||||||
|
All data saves in your browser only. Nothing is sent to
|
||||||
|
external servers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="font-medium mb-2 text-neutral-900 dark:text-white"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
EXPORT OPTIONS
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-neutral-700 dark:text-neutral-200">
|
||||||
|
Download as PDF (print), plain text, Markdown, or Word
|
||||||
|
document.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="font-medium mb-2 text-neutral-900 dark:text-white"
|
||||||
|
style="font-family: 'Ubuntu Mono', monospace">
|
||||||
|
RESUME ANYTIME
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-neutral-700 dark:text-neutral-200">
|
||||||
|
Come back later and your progress will be saved. Clear browser
|
||||||
|
data to start fresh.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
const templates = [
|
||||||
|
{
|
||||||
|
id: "membership-agreement",
|
||||||
|
name: "Membership Agreement",
|
||||||
|
description:
|
||||||
|
"A comprehensive agreement outlining member rights, responsibilities, decision-making processes, and financial arrangements for worker cooperatives.",
|
||||||
|
icon: "i-heroicons-user-group",
|
||||||
|
path: "/templates/membership-agreement",
|
||||||
|
tags: ["Legal", "Governance", "Membership"],
|
||||||
|
estimatedTime: "15-30 min",
|
||||||
|
fields: 25,
|
||||||
|
storageKey: "membership-agreement-data",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "conflict-resolution-framework",
|
||||||
|
name: "Conflict Resolution Framework",
|
||||||
|
description:
|
||||||
|
"A customizable framework for handling conflicts with restorative justice principles, clear processes, and organizational values alignment.",
|
||||||
|
icon: "i-heroicons-scale",
|
||||||
|
path: "/templates/conflict-resolution-framework",
|
||||||
|
tags: ["Governance", "Process", "Care"],
|
||||||
|
estimatedTime: "20-40 min",
|
||||||
|
fields: 35,
|
||||||
|
storageKey: "conflict-resolution-framework-data",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "tech-charter",
|
||||||
|
name: "Technology Charter",
|
||||||
|
description:
|
||||||
|
"Build technology decisions on cooperative values. Define principles, technical constraints, and evaluation criteria for vendor selection.",
|
||||||
|
icon: "i-heroicons-cog-6-tooth",
|
||||||
|
path: "/templates/tech-charter",
|
||||||
|
tags: ["Technology", "Decision-Making", "Governance"],
|
||||||
|
estimatedTime: "10-20 min",
|
||||||
|
fields: 20,
|
||||||
|
storageKey: "tech-charter-data",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "decision-framework",
|
||||||
|
name: "Decision Framework Helper",
|
||||||
|
description:
|
||||||
|
"Interactive tool to help determine the best decision-making approach based on urgency, expertise, stakes, and team dynamics.",
|
||||||
|
icon: "i-heroicons-light-bulb",
|
||||||
|
path: "/templates/decision-framework",
|
||||||
|
tags: ["Decision-Making", "Process", "Governance"],
|
||||||
|
estimatedTime: "5-10 min",
|
||||||
|
fields: 7,
|
||||||
|
storageKey: "decision-framework-data",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const hasData = (templateId) => {
|
||||||
|
const template = templates.find((t) => t.id === templateId);
|
||||||
|
if (!template?.storageKey) return false;
|
||||||
|
if (process.client) {
|
||||||
|
const saved = localStorage.getItem(template.storageKey);
|
||||||
|
return saved && saved !== "{}";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: "Wizards - Co-op Pay & Value Tool",
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
content:
|
||||||
|
"Interactive wizards for worker cooperatives including membership agreements and governance documents.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&family=Ubuntu+Mono:wght@400;700&display=swap");
|
||||||
|
|
||||||
|
.dither-shadow {
|
||||||
|
background: black;
|
||||||
|
background-image: radial-gradient(white 1px, transparent 1px);
|
||||||
|
background-size: 2px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.dither-shadow {
|
||||||
|
background: white;
|
||||||
|
background-image: radial-gradient(black 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .dither-shadow {
|
||||||
|
background: white;
|
||||||
|
background-image: radial-gradient(black 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dither-shadow-disabled {
|
||||||
|
background: black;
|
||||||
|
background-image: radial-gradient(white 1px, transparent 1px);
|
||||||
|
background-size: 2px 2px;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.dither-shadow-disabled {
|
||||||
|
background: white;
|
||||||
|
background-image: radial-gradient(black 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .dither-shadow-disabled {
|
||||||
|
background: white;
|
||||||
|
background-image: radial-gradient(black 1px, transparent 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-card {
|
||||||
|
@apply relative;
|
||||||
|
font-family: "Ubuntu", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-section {
|
||||||
|
@apply relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coming-soon {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dither-tag {
|
||||||
|
position: relative;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
.dither-tag::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-image: repeating-linear-gradient(
|
||||||
|
45deg,
|
||||||
|
transparent 0px,
|
||||||
|
transparent 1px,
|
||||||
|
black 1px,
|
||||||
|
black 2px
|
||||||
|
);
|
||||||
|
opacity: 0.1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bitmap-button {
|
||||||
|
font-family: "Ubuntu Mono", monospace !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bitmap-button:hover::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
left: 1px;
|
||||||
|
right: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background: white;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled-button {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-card > *,
|
||||||
|
.help-section > *,
|
||||||
|
button,
|
||||||
|
.px-4,
|
||||||
|
div[class*="border"] {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
font-family: "Ubuntu", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark :deep(.text-neutral-700),
|
||||||
|
html.dark :deep(.text-neutral-500),
|
||||||
|
html.dark :deep(.bg-neutral-50),
|
||||||
|
html.dark :deep(.bg-neutral-100) {
|
||||||
|
color: white !important;
|
||||||
|
background-color: #0a0a0a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.border-neutral-200),
|
||||||
|
:deep(.border-neutral-300) {
|
||||||
|
border-color: black !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue