Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist

# Node dependencies
node_modules

# Logs
logs
*.log

# Misc
.DS_Store
.fleet
.idea

# Local env files
.env
.env.*
!.env.example
75 changes: 75 additions & 0 deletions website/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Nuxt Minimal Starter

Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.

## Setup

Make sure to install dependencies:

```bash
# npm
npm install

# pnpm
pnpm install

# yarn
yarn install

# bun
bun install
```

## Development Server

Start the development server on `http://localhost:3000`:

```bash
# npm
npm run dev

# pnpm
pnpm dev

# yarn
yarn dev

# bun
bun run dev
```

## Production

Build the application for production:

```bash
# npm
npm run build

# pnpm
pnpm build

# yarn
yarn build

# bun
bun run build
```

Locally preview production build:

```bash
# npm
npm run preview

# pnpm
pnpm preview

# yarn
yarn preview

# bun
bun run preview
```

Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
9 changes: 9 additions & 0 deletions website/app/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<template>
<NuxtPage />
</template>

<style>
html, body {
font-family: 'Sora', system-ui, -apple-system, sans-serif;
}
</style>
63 changes: 63 additions & 0 deletions website/app/components/CompetitorComparison.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<section class="py-24 sm:py-32 px-6 bg-brand-linen dark:bg-dark-card">
<div class="max-w-4xl mx-auto">
<div class="text-center mb-12">
<p class="font-mono text-sm text-brand-orange tracking-widest uppercase mb-4">// the landscape</p>
<h2 class="font-mono font-bold text-3xl sm:text-4xl mb-4">How Foqus compares</h2>
<p class="text-brand-teal dark:text-dark-muted">Honest look at what's out there.</p>
</div>

<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-brand-teal/10 dark:border-dark-muted/20">
<th class="text-left font-mono font-semibold py-4 pr-4" />
<th class="text-center font-mono font-semibold py-4 px-4 text-brand-orange">Foqus</th>
<th class="text-center font-mono font-semibold py-4 px-4 text-brand-teal/50 dark:text-dark-muted/50">BlockSite</th>
<th class="text-center font-mono font-semibold py-4 px-4 text-brand-teal/50 dark:text-dark-muted/50">Cold Turkey</th>
<th class="text-center font-mono font-semibold py-4 px-4 text-brand-teal/50 dark:text-dark-muted/50">Freedom</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key="row.feature" class="border-b border-brand-teal/5 dark:border-dark-muted/10">
<td class="py-3 pr-4 font-medium">{{ row.feature }}</td>
<td class="py-3 px-4 text-center">
<span v-if="row.foqus === true" class="text-brand-teal text-lg">&#10003;</span>
<span v-else-if="row.foqus === false" class="text-brand-teal/20 text-lg">&#10005;</span>
<span v-else class="font-mono text-xs">{{ row.foqus }}</span>
</td>
<td class="py-3 px-4 text-center text-brand-teal/40 dark:text-dark-muted/40">
<span v-if="row.blocksite === true" class="text-lg">&#10003;</span>
<span v-else-if="row.blocksite === false" class="text-lg">&#10005;</span>
<span v-else class="font-mono text-xs">{{ row.blocksite }}</span>
</td>
<td class="py-3 px-4 text-center text-brand-teal/40 dark:text-dark-muted/40">
<span v-if="row.coldturkey === true" class="text-lg">&#10003;</span>
<span v-else-if="row.coldturkey === false" class="text-lg">&#10005;</span>
<span v-else class="font-mono text-xs">{{ row.coldturkey }}</span>
</td>
<td class="py-3 px-4 text-center text-brand-teal/40 dark:text-dark-muted/40">
<span v-if="row.freedom === true" class="text-lg">&#10003;</span>
<span v-else-if="row.freedom === false" class="text-lg">&#10005;</span>
<span v-else class="font-mono text-xs">{{ row.freedom }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</template>

<script setup lang="ts">
const rows = [
{ feature: 'Intention-first approach', foqus: true, blocksite: false, coldturkey: false, freedom: false },
{ feature: 'Personality-driven UI', foqus: true, blocksite: false, coldturkey: false, freedom: false },
{ feature: 'Privacy-first (no data collection)', foqus: true, blocksite: false, coldturkey: true, freedom: false },
{ feature: 'No account required', foqus: true, blocksite: false, coldturkey: true, freedom: false },
{ feature: 'Graceful unblocking', foqus: true, blocksite: false, coldturkey: false, freedom: false },
{ feature: 'Positive alternatives', foqus: true, blocksite: false, coldturkey: false, freedom: false },
{ feature: 'Free core experience', foqus: true, blocksite: 'Freemium', coldturkey: 'Freemium', freedom: '$8.99/mo' },
{ feature: 'Shame-free design', foqus: true, blocksite: false, coldturkey: false, freedom: false },
]
</script>
36 changes: 36 additions & 0 deletions website/app/components/FeatureItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<div class="flex gap-4">
<div class="mt-1 flex-shrink-0">
<div
:class="[
'w-5 h-5 rounded-full flex items-center justify-center text-white text-xs',
live ? 'bg-brand-teal' : 'bg-brand-teal/30',
]"
>
<svg v-if="live" class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7" />
</svg>
</div>
</div>
<div>
<div class="flex items-center gap-2">
<h3 class="font-mono font-semibold text-base">{{ name }}</h3>
<span
v-if="!live"
class="font-mono text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-brand-orange/10 text-brand-orange"
>
coming soon
</span>
</div>
<p class="text-brand-teal dark:text-dark-muted text-sm leading-relaxed mt-1">{{ description }}</p>
</div>
</div>
</template>

<script setup lang="ts">
defineProps<{
name: string
description: string
live: boolean
}>()
</script>
75 changes: 75 additions & 0 deletions website/app/components/Features.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<section id="features" class="py-24 sm:py-32 px-6">
<div class="max-w-5xl mx-auto">
<div class="text-center mb-16">
<p class="font-mono text-sm text-brand-orange tracking-widest uppercase mb-4">// what you get</p>
<h2 class="font-mono font-bold text-3xl sm:text-4xl">Features</h2>
</div>

<div class="grid sm:grid-cols-2 gap-x-12 gap-y-8 max-w-3xl mx-auto">
<FeatureItem
v-for="feature in features"
:key="feature.name"
:name="feature.name"
:description="feature.description"
:live="feature.live"
/>
</div>
</div>
</section>
</template>

<script setup lang="ts">
const features = [
{
name: 'Site intention lists',
description: 'Curate your avoid list and positive alternatives in one place.',
live: true,
},
{
name: 'Personality-driven overlay',
description: 'A beautiful 3D gradient overlay with witty, warm messages.',
live: true,
},
{
name: 'Graceful unblocking',
description: "Unblock for a set time — it's data, not failure.",
live: true,
},
{
name: 'Custom messages',
description: 'Set your own overlay text. Make it yours.',
live: true,
},
{
name: 'Dark mode',
description: 'Full dark mode support across popup and overlay.',
live: true,
},
{
name: 'Reduced motion',
description: 'Respects your system accessibility preferences.',
live: true,
},
{
name: 'Streak tracking',
description: 'Track your intentions-kept streaks over time.',
live: false,
},
{
name: 'Weekly reflections',
description: '"You visited Reddit 30% less this week" — gentle insights.',
live: false,
},
{
name: 'Trend lines',
description: 'See your browsing patterns shift over time, visually.',
live: false,
},
{
name: 'Data export',
description: 'Export your data as CSV or JSON. It\'s your data.',
live: false,
},
]
</script>
48 changes: 48 additions & 0 deletions website/app/components/HowDifferent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<section class="py-24 sm:py-32 px-6 bg-brand-linen dark:bg-dark-card">
<div class="max-w-6xl mx-auto">
<div class="text-center mb-16">
<p class="font-mono text-sm text-brand-orange tracking-widest uppercase mb-4">// a different philosophy</p>
<h2 class="font-mono font-bold text-3xl sm:text-4xl">How Foqus is different</h2>
</div>

<div class="grid md:grid-cols-3 gap-8 sm:gap-12">
<div class="bg-brand-parchment dark:bg-dark-bg p-8 sm:p-10 rounded-2xl">
<div class="w-12 h-12 rounded-xl bg-brand-orange/10 flex items-center justify-center mb-6">
<svg class="w-6 h-6 text-brand-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
</svg>
</div>
<h3 class="font-mono font-semibold text-xl mb-3">Intention, not restriction</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
You choose the sites you want to be mindful about. When you visit one, Foqus asks <em>why</em> — it never says "no."
</p>
</div>

<div class="bg-brand-parchment dark:bg-dark-bg p-8 sm:p-10 rounded-2xl">
<div class="w-12 h-12 rounded-xl bg-brand-orange/10 flex items-center justify-center mb-6">
<svg class="w-6 h-6 text-brand-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
<h3 class="font-mono font-semibold text-xl mb-3">Personality, not productivity</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
The overlay speaks like a friend: <span class="font-mono text-sm">"Come here often?"</span>, <span class="font-mono text-sm">"Captain, we're drifting off course!"</span> — warm, not clinical.
</p>
</div>

<div class="bg-brand-parchment dark:bg-dark-bg p-8 sm:p-10 rounded-2xl">
<div class="w-12 h-12 rounded-xl bg-brand-orange/10 flex items-center justify-center mb-6">
<svg class="w-6 h-6 text-brand-orange" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg>
</div>
<h3 class="font-mono font-semibold text-xl mb-3">Privacy-first</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
All data stays on your device. No accounts, no servers, no tracking. Period. Foqus literally cannot see your data.
</p>
</div>
</div>
</div>
</section>
</template>
36 changes: 36 additions & 0 deletions website/app/components/HowItWorks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<section id="how-it-works" class="py-24 sm:py-32 px-6">
<div class="max-w-5xl mx-auto">
<div class="text-center mb-16">
<p class="font-mono text-sm text-brand-orange tracking-widest uppercase mb-4">// three simple steps</p>
<h2 class="font-mono font-bold text-3xl sm:text-4xl">How it works</h2>
</div>

<div class="grid md:grid-cols-3 gap-12">
<div class="text-center">
<div class="font-mono text-6xl font-bold text-brand-orange/20 mb-4">01</div>
<h3 class="font-mono font-semibold text-lg mb-3">Add your sites</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
Choose the sites you want to be mindful about — your "avoid" list. Then add positive alternatives to your "visit" list.
</p>
</div>

<div class="text-center">
<div class="font-mono text-6xl font-bold text-brand-orange/20 mb-4">02</div>
<h3 class="font-mono font-semibold text-lg mb-3">A gentle nudge appears</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
When you visit a flagged site, a beautiful overlay appears with a friendly message and your positive alternatives.
</p>
</div>

<div class="text-center">
<div class="font-mono text-6xl font-bold text-brand-orange/20 mb-4">03</div>
<h3 class="font-mono font-semibold text-lg mb-3">You always choose</h3>
<p class="text-brand-teal dark:text-dark-muted leading-relaxed">
Unblock anytime, no guilt. Foqus respects your agency — it's information, not punishment. You have the final say.
</p>
</div>
</div>
</div>
</section>
</template>
Loading