Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b7e97c5
fix: friendly types
techpixel Nov 6, 2025
480b383
feat: hackatime editing
techpixel Nov 6, 2025
6e73e44
fix: replace red email text with italics
techpixel Nov 6, 2025
27490c0
fix: butler, calculator copy
techpixel Nov 6, 2025
14ed4ce
fix: emphasize hackatime project linking
techpixel Nov 6, 2025
c9d3008
fix: coloring did not apply on terminal cli projects
techpixel Nov 6, 2025
49ad5cf
feat: skeleton for progress bar
techpixel Nov 6, 2025
f8e27d5
fix: swap hackclub.com -> gmail.com
techpixel Nov 6, 2025
fdb44c6
fix: shake nav
techpixel Nov 6, 2025
00cdaab
feat: move to layout loading for individ project page
techpixel Nov 6, 2025
d5e0a61
fix: optimization to site structure
techpixel Nov 6, 2025
3e213cb
fix: layouts conflicts irt loading
techpixel Nov 6, 2025
3fc8cc4
fix: override layout for onboarding
techpixel Nov 7, 2025
fc7f7fe
fix: allow duplicated projects globally
LeafdTK Nov 7, 2025
4b9376a
fix: make now_hackatime_hours get sum of linked projects
LeafdTK Nov 7, 2025
201a638
fix: eliminate 1 submission requirement
LeafdTK Nov 7, 2025
3ad7c76
chore: remove unused imports
techpixel Nov 8, 2025
f81322a
fix: state sharing issues
techpixel Nov 8, 2025
5b4f617
fix: re-initalize project when page changes
techpixel Nov 8, 2025
2a17de2
feat: add upload endpoint
LeafdTK Nov 10, 2025
0ef1ad6
feat: submission flow v1
techpixel Nov 12, 2025
d8168e5
fix: better errors in submit
techpixel Nov 12, 2025
6dde793
fix: health check endpoint
techpixel Nov 12, 2025
ddae9d2
fix: add required stars
techpixel Nov 12, 2025
bd904e3
fix: make screenshot required
techpixel Nov 12, 2025
f46d881
disable dropdown for now
techpixel Nov 12, 2025
48346e0
fix: navbar layering
techpixel Nov 13, 2025
2dfb09a
feat: add pre-submit checklist (incomplete copy)
techpixel Nov 13, 2025
7e54645
fix: age verification
LeafdTK Nov 13, 2025
cc4a02c
fix: add sum hours endpoints
LeafdTK Nov 13, 2025
d6f3627
fix: add hackatime hours update endpoint
LeafdTK Nov 13, 2025
065956e
feat: progress bar
techpixel Nov 13, 2025
ee57f30
feat: add admin panel
LeafdTK Nov 13, 2025
0141d50
feat: implement copy text
techpixel Nov 13, 2025
77d1a44
feat: add posthog
LeafdTK Nov 13, 2025
f9dfe11
fix: incorrect data from updateProject
techpixel Nov 13, 2025
4dc79aa
fix: limit hackatime projects to oct 10
LeafdTK Nov 13, 2025
76b03e0
fix: update pnpm lockfile
LeafdTK Nov 13, 2025
e976abf
fix: add posthog
LeafdTK Nov 13, 2025
5c605e6
feat: new progress bar design
techpixel Nov 13, 2025
0c625d9
fix: progress bar data
techpixel Nov 14, 2025
91e7258
fix: tofixed
techpixel Nov 14, 2025
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
8 changes: 8 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ LARK_UI_PORT=5173
PUBLIC_API_URL=http://localhost:3000
VITE_API_URL=http://localhost:3002

# Cloudflare R2 Configuration
R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
R2_REGION=auto
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_BUCKET=your_r2_bucket_name
R2_PUBLIC_BASE_URL=https://cdn.midnigh.leafd.dev

# Datadog Configuration (optional)
DD_AGENT_HOST=localhost
DD_TRACE_AGENT_PORT=8126
Expand Down
22 changes: 15 additions & 7 deletions lark-ui/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@ RUN corepack enable && corepack prepare pnpm@latest --activate

FROM base AS deps
WORKDIR /app
COPY lark-ui/package.json lark-ui/pnpm-lock.yaml* ./
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
COPY lark-ui/package.json ./lark-ui/
COPY owl-api/package.json ./owl-api/
COPY gateway/package.json ./gateway/
RUN pnpm install --frozen-lockfile

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY lark-ui/ .
RUN pnpm run build
COPY pnpm-workspace.yaml pnpm-lock.yaml ./
COPY lark-ui/package.json ./lark-ui/
COPY owl-api/package.json ./owl-api/
COPY gateway/package.json ./gateway/
COPY lark-ui/ ./lark-ui/
RUN pnpm install --frozen-lockfile
RUN pnpm --filter lark-ui run build

FROM base AS runner
WORKDIR /app
Expand All @@ -23,9 +30,10 @@ ENV HOST=0.0.0.0
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 sveltekit

COPY --from=builder --chown=sveltekit:nodejs /app/build ./build
COPY --from=builder --chown=sveltekit:nodejs /app/package.json ./package.json
COPY --from=deps --chown=sveltekit:nodejs /app/node_modules ./node_modules
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder --chown=sveltekit:nodejs /app/lark-ui ./lark-ui

WORKDIR /app/lark-ui

USER sveltekit

Expand Down
3 changes: 2 additions & 1 deletion lark-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
]
},
"dependencies": {
"@tailwindcss/vite": "^4.1.14"
"@tailwindcss/vite": "^4.1.14",
"posthog-js": "^1.292.0"
}
}
4 changes: 3 additions & 1 deletion lark-ui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
overscroll-behavior: none;
}

body {
html, body {
background-color: #F24B4B;

min-height: 100%;
}

::-webkit-scrollbar {
Expand Down
217 changes: 156 additions & 61 deletions lark-ui/src/lib/BottomNavigation.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { getReferralCode } from './auth';

const { onboarding = false, currentTab = 'create' } = $props();
import { onMount } from 'svelte';
import { getReferralCode, type User } from './auth';
import { getHourCounts } from './auth';

type Tab = 'create' | 'explore' | 'shop' | 'settings';

const { page, onboarding = false, user }: {
page: string;
onboarding?: boolean;
user?: User;
} = $props();

let activeTab = $state(currentTab);
let activeTab = $derived.by(() => {
if (page.startsWith('/app/projects')) return 'create';
if (page.startsWith('/app/settings')) return 'settings';
return 'create';
});

let shakingTab = $state('');

let referralPopover = $state(false);
Expand All @@ -31,7 +44,7 @@
}

function navigateTo(tab: string) {
if (onboarding && (tab === 'explore' || tab === 'shop')) {
if ((tab === 'explore' || tab === 'shop')) {
handleLockedClick(tab);
return;
}
Expand All @@ -49,83 +62,165 @@
break;
}
}


</script>

<div class="bottom-navigation">
<div class="nav-tabs">
<button
class="nav-item"
class:active={activeTab === 'create'}
onclick={() => navigateTo('create')}
role="tab"
aria-selected={activeTab === 'create'}
class:enabled={true}
>
Create
</button>
<button
class="nav-item {true ? 'disabled' : 'enabled'}"
class:active={activeTab === 'explore'}
class:shake={shakingTab === 'explore'}
role="tab"
aria-selected={activeTab === 'explore'}
>
Explore
<!-- {#if onboarding} -->
<img class="lock" src="/icons/lock.svg" alt="Lock" />
<!-- {/if} -->
</button>
<button
class="nav-item {true ? 'disabled' : 'enabled'}"
class:active={activeTab === 'shop'}
class:shake={shakingTab === 'shop'}
role="tab"
aria-selected={activeTab === 'shop'}
>
Shop
<!-- {#if onboarding} -->
<img class="lock" src="/icons/lock.svg" alt="Lock" />
<!-- {/if} -->
</button>
</div>
<div class="tray">
{#if !onboarding}
<!-- <img src="/icons/bell.svg" alt="Notification" /> -->
<button class="referral" onclick={showReferralPopover}>
{#if referralPopover}
<div class="referral-popover">
<p>Referral link copied to clipboard</p>
</div>
{/if}
<img src="/icons/link.svg" alt="Referral" />
<div class="bottom-nav-items">
<div class="nav-tabs">
<button
class="nav-item"
class:active={activeTab === 'create'}
onclick={() => navigateTo('create')}
role="tab"
aria-selected={activeTab === 'create'}
class:enabled={true}
class:shake={shakingTab === 'create'}
>
Create
</button>
<button
class="nav-item {true ? 'disabled' : 'enabled'}"
class:active={activeTab === 'explore'}
class:shake={shakingTab === 'explore'}
onclick={() => navigateTo('explore')}
role="tab"
aria-selected={activeTab === 'explore'}
>
Explore
<!-- {#if onboarding} -->
<img class="lock" src="/icons/lock.svg" alt="Lock" />
<!-- {/if} -->
</button>
<a
class="settings"
class:active={activeTab === 'settings'}
href="/app/settings"
<button
class="nav-item {true ? 'disabled' : 'enabled'}"
class:active={activeTab === 'shop'}
class:shake={shakingTab === 'shop'}
onclick={() => navigateTo('shop')}
role="tab"
aria-selected={activeTab === 'shop'}
>
<img src="/icons/settings.svg" alt="Settings" />
</a>
{/if}
Shop
<!-- {#if onboarding} -->
<img class="lock" src="/icons/lock.svg" alt="Lock" />
<!-- {/if} -->
</button>
</div>
<div class="tray">
{#if !onboarding}
<!-- <img src="/icons/bell.svg" alt="Notification" /> -->
<button class="referral" onclick={showReferralPopover}>
{#if referralPopover}
<div class="referral-popover">
<p>Referral link copied to clipboard</p>
</div>
{/if}
<img src="/icons/link.svg" alt="Referral" />
</button>
<a
class="settings"
class:active={activeTab === 'settings'}
href="/app/settings"
>
<img src="/icons/settings.svg" alt="Settings" />
</a>
{/if}
</div>
</div>
</div>

<style>
.progress-bar {
height: 16px;

display: flex;
}

.approved-hours {
background: #1385F0;
height: 100%;
position: relative;
}

.tracked-hours {
background: #4F5B9C;
height: 100%;
position: relative;
}

.remaining-hours {
background: #5E5087;
height: 100%;
position: relative;
}

.marker {
position: absolute;
right: 0;
bottom: calc(100%);
transform: translateX(50%);

padding: 8px 12px;
background-image: url('/shapes/shape-popover-3.svg');
background-size: contain;
background-repeat: no-repeat;
background-position: bottom center;
white-space: nowrap;
}

.marker p {
font-family: 'PT Sans', sans-serif;
font-size: 12px;
font-weight: bold;
color: white;
margin: 0;
margin-top: 12px;
margin-bottom: 1.25px;
}

.goal-marker {
position: absolute;
right: 0;
bottom: calc(100%);

padding: 8px 12px;
background-image: url('/shapes/shape-popover-4.svg');
background-size: contain;
background-repeat: no-repeat;
background-position: bottom center;
white-space: nowrap;
}

.goal-marker p {
font-family: 'PT Sans', sans-serif;
font-size: 12px;
font-weight: bold;
color: white;
margin: 0;
margin-top: 12px;
margin-bottom: 5px;
rotate: -0.75deg;
}

.bottom-navigation {
position: fixed;
z-index: 1000;
bottom: 0;
left: 0;
right: 0;
}

.bottom-nav-items {
background: #2D273F;
z-index: 200;
height: 137px;
padding: 0 120px;
z-index: 200;

display: flex;
align-items: center;
justify-content: space-between;
}

.nav-tabs {
display: flex;
gap: 60px;
Expand Down
Loading