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
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,15 @@ import type { Task } from "@shared/types";
import type { ArchivedTask } from "@shared/types/archive";
import { useNavigationStore } from "@stores/navigationStore";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { formatRelativeTimeLong } from "@utils/time";
import { toast } from "@utils/toast";
import { useMemo, useState } from "react";

const BRANCH_NOT_FOUND_PATTERN = /Branch '(.+)' does not exist/;

function formatRelativeDate(isoDate: string | undefined): string {
if (!isoDate) return "—";
const date = new Date(isoDate);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffSeconds = Math.floor(diffMs / 1000);
const diffMinutes = Math.floor(diffSeconds / 60);
const diffHours = Math.floor(diffMinutes / 60);
const diffDays = Math.floor(diffHours / 24);

if (diffSeconds < 60) {
return "just now";
}
if (diffMinutes < 60) {
return diffMinutes === 1 ? "1 minute ago" : `${diffMinutes} minutes ago`;
}
if (diffHours < 24) {
return diffHours === 1 ? "1 hour ago" : `${diffHours} hours ago`;
}
if (diffDays < 7) {
return diffDays === 1 ? "1 day ago" : `${diffDays} days ago`;
}

return date.toLocaleDateString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
});
return formatRelativeTimeLong(isoDate);
}

function getRepoName(repository: string | null | undefined): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PushPin,
} from "@phosphor-icons/react";
import { selectIsFocusedOnWorktree, useFocusStore } from "@stores/focusStore";
import { formatRelativeTimeShort } from "@utils/time";
import { useCallback, useEffect, useRef, useState } from "react";
import { SidebarItem } from "../SidebarItem";

Expand Down Expand Up @@ -44,26 +45,6 @@ interface TaskItemProps {
onEditCancel?: () => void;
}

function formatRelativeTime(timestamp: number): string {
const now = Date.now();
const diff = now - timestamp;

const minutes = Math.floor(diff / (1000 * 60));
const hours = Math.floor(diff / (1000 * 60 * 60));
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const weeks = Math.floor(days / 7);
const months = Math.floor(days / 30);
const years = Math.floor(days / 365);

if (years > 0) return `${years}y`;
if (months > 0) return `${months}mo`;
if (weeks > 0) return `${weeks}w`;
if (days > 0) return `${days}d`;
if (hours > 0) return `${hours}h`;
if (minutes > 0) return `${minutes}m`;
return "now";
}

interface TaskHoverToolbarProps {
isPinned: boolean;
onTogglePin?: () => void;
Expand Down Expand Up @@ -250,7 +231,7 @@ export function TaskItem({

const timestampNode = timestamp ? (
<span className="shrink-0 text-[11px] text-gray-11 group-hover:hidden">
{formatRelativeTime(timestamp)}
{formatRelativeTimeShort(timestamp)}
</span>
) : null;

Expand Down
52 changes: 52 additions & 0 deletions apps/code/src/renderer/utils/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Format a timestamp as a short relative string (e.g. "3m", "2h", "5d").
* Accepts either a Unix ms timestamp or an ISO date string.
*/
export function formatRelativeTimeShort(timestamp: number | string): string {
const ms =
typeof timestamp === "string" ? new Date(timestamp).getTime() : timestamp;
const diff = Date.now() - ms;

const minutes = Math.floor(diff / 60_000);
const hours = Math.floor(diff / 3_600_000);
const days = Math.floor(diff / 86_400_000);
const weeks = Math.floor(days / 7);
const months = Math.floor(days / 30);
const years = Math.floor(days / 365);

if (years > 0) return `${years}y`;
if (months > 0) return `${months}mo`;
if (weeks > 0) return `${weeks}w`;
if (days > 0) return `${days}d`;
if (hours > 0) return `${hours}h`;
if (minutes > 0) return `${minutes}m`;
return "now";
}

/**
* Format a timestamp as a longer relative string (e.g. "3 minutes ago", "1 day ago").
* Falls back to a locale date for anything older than a week.
* Accepts either a Unix ms timestamp or an ISO date string.
*/
export function formatRelativeTimeLong(timestamp: number | string): string {
const date =
typeof timestamp === "string" ? new Date(timestamp) : new Date(timestamp);
const diff = Date.now() - date.getTime();

const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);

if (seconds < 60) return "just now";
if (minutes < 60)
return minutes === 1 ? "1 minute ago" : `${minutes} minutes ago`;
if (hours < 24) return hours === 1 ? "1 hour ago" : `${hours} hours ago`;
if (days < 7) return days === 1 ? "1 day ago" : `${days} days ago`;

return date.toLocaleDateString(undefined, {
month: "short",
day: "numeric",
year: "numeric",
});
}
Loading