app/pages/tools/wizards.vue

204 lines
6.3 KiB
Vue

<template>
<div>
<div
class="template-container min-h-screen bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100 py-8">
<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">
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>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
const templates = [
{
id: "membership-agreement",
name: "Membership Agreement",
description:
"An agreement outlining member rights, responsibilities, decision-making processes, and financial arrangements.",
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",
description:
"A 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:
"How do you decide what technology and tools align with your values? This wizard helps you define principles, technical constraints, and evaluation criteria for tech 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:
"Need help deciding how to decide? This wizard guides you towards a 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>
.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;
}
</style>