Compare commits
5 Commits
Dev
...
391f52af23
| Author | SHA1 | Date | |
|---|---|---|---|
| 391f52af23 | |||
| ac119c288b | |||
| 0bc9c74797 | |||
| 50ccbbc564 | |||
| a5ecee084e |
+64
-2
@@ -2,7 +2,7 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: [main, Dev]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
@@ -30,11 +30,13 @@ jobs:
|
||||
env:
|
||||
VITE_POCKETBASE_URL: ${{ vars.VITE_POCKETBASE_URL || 'https://pocketbase.ccllc.pro' }}
|
||||
|
||||
deploy:
|
||||
deploy_prod:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
container:
|
||||
image: node:20-bookworm
|
||||
env:
|
||||
APP_PORT: ${{ secrets.MAIN_PORT || '4000' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -85,3 +87,63 @@ jobs:
|
||||
sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=accept-new -p ${{ secrets.DEPLOY_SSH_PORT || '22' }} \
|
||||
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST || env.DEPLOY_HOST }} \
|
||||
'bash -lc "cd ${{ secrets.DEPLOY_PATH || env.DEPLOY_PATH }} && export PORT=${{ env.APP_PORT }} && (pm2 restart tasgrid 2>/dev/null || pm2 start \"bun run serve\" --name tasgrid --update-env)"'
|
||||
|
||||
deploy_dev:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/Dev' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
||||
container:
|
||||
image: node:20-bookworm
|
||||
env:
|
||||
DEPLOY_HOST: ${{ secrets.DEV_DEPLOY_HOST || env.DEPLOY_HOST }}
|
||||
DEPLOY_PATH: ${{ secrets.DEV_DEPLOY_PATH || '/var/www/tasgrid-dev' }}
|
||||
APP_PORT: ${{ secrets.DEV_PORT || '4001' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install curl and ca-certificates
|
||||
run: apt-get update -qq && apt-get install -y curl ca-certificates
|
||||
|
||||
- name: Install Bun
|
||||
run: |
|
||||
curl -fsSL https://bun.sh/install | bash
|
||||
echo "$HOME/.bun/bin" >> $GITHUB_PATH
|
||||
echo "PATH=$HOME/.bun/bin:$PATH" >> $GITHUB_ENV
|
||||
|
||||
- name: Install deploy tools
|
||||
run: apt-get update -qq && apt-get install -y rsync openssh-client sshpass
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
env:
|
||||
VITE_POCKETBASE_URL: ${{ secrets.DEV_VITE_POCKETBASE_URL || vars.VITE_POCKETBASE_URL || 'https://pocketbase.ccllc.pro' }}
|
||||
|
||||
- name: Verify build output
|
||||
run: |
|
||||
ls -la
|
||||
test -d dist || (echo "Missing dist/ (Vite output). Check Build step." && exit 1)
|
||||
|
||||
- name: Setup SSH known hosts
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -p ${{ secrets.DEV_DEPLOY_SSH_PORT || '22' }} -H ${{ secrets.DEV_DEPLOY_HOST || env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||
|
||||
- name: Deploy via rsync
|
||||
env:
|
||||
SSH_PASSWORD: ${{ secrets.DEV_DEPLOY_PASSWORD }}
|
||||
run: |
|
||||
sshpass -p "$SSH_PASSWORD" rsync -avz --delete \
|
||||
-e "ssh -o StrictHostKeyChecking=accept-new -p ${{ secrets.DEV_DEPLOY_SSH_PORT || '22' }}" \
|
||||
dist/ \
|
||||
${{ secrets.DEV_DEPLOY_USER }}@${{ secrets.DEV_DEPLOY_HOST || env.DEPLOY_HOST }}:${{ secrets.DEV_DEPLOY_PATH || env.DEPLOY_PATH }}/
|
||||
|
||||
- name: Restart app on server
|
||||
env:
|
||||
SSH_PASSWORD: ${{ secrets.DEV_DEPLOY_PASSWORD }}
|
||||
run: |
|
||||
sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=accept-new -p ${{ secrets.DEV_DEPLOY_SSH_PORT || '22' }} \
|
||||
${{ secrets.DEV_DEPLOY_USER }}@${{ secrets.DEV_DEPLOY_HOST || env.DEPLOY_HOST }} \
|
||||
'bash -lc "cd ${{ secrets.DEV_DEPLOY_PATH || env.DEPLOY_PATH }} && export PORT=${{ env.APP_PORT }} && (pm2 restart tasgrid-dev 2>/dev/null || pm2 start \"bun run serve\" --name tasgrid-dev --update-env)"'
|
||||
|
||||
@@ -77,18 +77,6 @@
|
||||
transform: translateX(3px);
|
||||
}
|
||||
}
|
||||
|
||||
--animate-task-enter: task-enter 0.25s ease-out backwards;
|
||||
|
||||
@keyframes task-enter {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
|
||||
@@ -28,10 +28,10 @@ export const CriticalView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Your tasks ranked by highest urgency + priority.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -33,10 +33,10 @@ export const DigInView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Largest tasks first. Tackle big projects head-on.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
+26
-22
@@ -175,7 +175,7 @@ export const NotepadView: Component<{
|
||||
<>
|
||||
{/* Editor Area */}
|
||||
<div class="flex-1 flex flex-col min-w-0 md:h-full overflow-visible md:overflow-y-auto relative p-4 md:p-6 space-y-4 md:space-y-6 scroll-smooth">
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-4 sticky top-0 z-30 bg-card/95 backdrop-blur-sm pt-4 pb-2 -mt-4 -mx-4 px-4 md:pt-6 md:-mt-6 md:-mx-6 md:px-6 md:pb-2">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<input
|
||||
class="text-3xl sm:text-4xl font-black tracking-tight bg-transparent border-none outline-none focus:ring-0 flex-1 placeholder:text-muted-foreground/30 px-0 min-w-0"
|
||||
@@ -200,17 +200,6 @@ export const NotepadView: Component<{
|
||||
</Show>
|
||||
</Button>
|
||||
</Show>
|
||||
|
||||
<Show when={isOwner}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-8 w-8 text-muted-foreground hover:text-destructive hover:bg-destructive/10 rounded-lg"
|
||||
onClick={() => handleDeleteNote(note().id)}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -245,7 +234,7 @@ export const NotepadView: Component<{
|
||||
}}
|
||||
>
|
||||
<div class={cn("flex items-center gap-2", !isLinkedTasksOpen() && "md:flex-col")}>
|
||||
<ChevronRight size={14} class={cn("text-muted-foreground transition-all duration-300 group-hover:text-foreground", !isLinkedTasksOpen() ? "rotate-90 md:rotate-0" : "rotate-90 md:rotate-180")} />
|
||||
<ChevronRight size={14} class={cn("text-muted-foreground transition-all duration-300 group-hover:text-foreground", !isLinkedTasksOpen() ? "-rotate-90 md:rotate-180" : "rotate-90 md:rotate-0")} />
|
||||
<Show when={isLinkedTasksOpen()} fallback={
|
||||
<div class="hidden md:flex items-center justify-center -rotate-90 origin-center whitespace-nowrap mt-8 text-[0.625rem] font-bold uppercase tracking-widest text-muted-foreground/50">
|
||||
<Link size={10} class="mr-2 rotate-90" />
|
||||
@@ -354,19 +343,34 @@ export const NotepadView: Component<{
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={!props.hideNavigation}>
|
||||
{/* Sticky Full-Width Mobile Close Footer */}
|
||||
<div class="md:hidden sticky bottom-0 z-[60] p-4 bg-background/95 backdrop-blur-sm border-t border-border flex justify-end shrink-0 w-full shadow-[0_-10px_40px_-5px_hsl(var(--background))]">
|
||||
{/* Sticky Footer Actions (Match TaskDetail style) */}
|
||||
<div class="px-6 py-4 border-t border-border/50 md:hidden flex items-center justify-between shrink-0 bg-background/95 backdrop-blur-sm z-40 w-full sticky bottom-0">
|
||||
{/* Delete button (persistent for owner) */}
|
||||
<Show when={isOwner}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="w-full h-11 rounded-xl text-sm font-bold shadow-sm"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="h-9 px-3 gap-2 hover:bg-destructive/10 hover:text-destructive text-muted-foreground transition-all rounded-xl border border-border/40"
|
||||
onClick={() => handleDeleteNote(note().id)}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
<span class="text-xs font-bold uppercase tracking-wider">Delete</span>
|
||||
</Button>
|
||||
</Show>
|
||||
|
||||
<Show when={!props.hideNavigation}>
|
||||
{/* Close button (Mobile only) */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="md:hidden h-9 px-3 gap-2 hover:bg-muted text-muted-foreground transition-all rounded-xl border border-border/40"
|
||||
onClick={() => props.setSelectedNoteId(null)}
|
||||
>
|
||||
<X size={16} class="mr-2" />
|
||||
Close Note
|
||||
<X size={16} />
|
||||
<span class="text-xs font-bold uppercase tracking-wider">Close</span>
|
||||
</Button>
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -28,10 +28,10 @@ export const PriorityView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Your tasks ordered by priority.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -35,10 +35,10 @@ export const ProgressView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Tasks sorted by progress status, then by focus score.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -33,10 +33,10 @@ export const SnowballView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Smallest tasks first. Build momentum with quick wins.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -32,10 +32,10 @@ export const UrgencyView: Component = () => {
|
||||
<p class="text-muted-foreground mt-1 text-lg">Your tasks ordered by deadline.</p>
|
||||
</header>
|
||||
|
||||
<div class="grid gap-3" ref={listRef}>
|
||||
<div class="grid grid-cols-1 gap-3 w-full" ref={listRef}>
|
||||
<For each={displayedTasks()}>
|
||||
{(task) => (
|
||||
<div class="animate-task-enter">
|
||||
<div class="w-full min-w-0">
|
||||
<TaskCard task={task} isShaking={shakingTaskIds().includes(task.id)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user