feat: Add Todoist notification list item

This commit is contained in:
2024-01-27 00:09:50 +01:00
parent e0f90b0c42
commit ea40258f48
29 changed files with 146 additions and 106 deletions

View File

@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="1 1 14 14" fill="#fb773f"><path d="M2 4.74695C2 4.68722 2.01039 4.62899 2.02989 4.57451L2.11601 4.42269C2.15266 4.37819 2.19711 4.33975 2.24806 4.30966L3.16473 3.76824L3.92054 5.08013L3.5 5.32852V5.8313H2V4.74695Z"></path><path d="M4.8372 4.53871L4.0814 3.22682L5.91473 2.14398L6.67054 3.45588L4.8372 4.53871Z"></path><path d="M7.5872 2.91446L6.8314 1.60257L7.74806 1.06115C7.7997 1.03065 7.85539 1.01027 7.91244 1H8.08756C8.14461 1.01027 8.2003 1.03065 8.25194 1.06115L9.1686 1.60257L8.4128 2.91446L8 2.67065L7.5872 2.91446Z"></path><path d="M9.32946 3.45588L10.0853 2.14398L11.9186 3.22682L11.1628 4.53871L9.32946 3.45588Z"></path><path d="M12.0795 5.08013L12.8353 3.76824L13.7519 4.30966C13.8029 4.33975 13.8473 4.37819 13.884 4.42269L13.9701 4.57451C13.9896 4.62899 14 4.68722 14 4.74695V5.8313H12.5V5.32852L12.0795 5.08013Z"></path><path d="M12.5 6.91565H14V9.08435H12.5V6.91565Z"></path><path d="M12.5 10.1687H14V11.253C14 11.3128 13.9896 11.371 13.9701 11.4255L13.884 11.5773C13.8473 11.6218 13.8029 11.6602 13.7519 11.6903L12.8353 12.2318L12.0795 10.9199L12.5 10.6715V10.1687Z"></path><path d="M11.1628 11.4613L11.9186 12.7732L10.0853 13.856L9.32946 12.5441L11.1628 11.4613Z"></path><path d="M8.4128 13.0855L9.1686 14.3974L8.25194 14.9389C8.2003 14.9694 8.14461 14.9897 8.08756 15H7.91244C7.85539 14.9897 7.7997 14.9694 7.74806 14.9389L6.8314 14.3974L7.5872 13.0855L8 13.3294L8.4128 13.0855Z"></path><path d="M6.67054 12.5441L5.91473 13.856L4.0814 12.7732L4.8372 11.4613L6.67054 12.5441Z"></path><path d="M3.92054 10.9199L3.16473 12.2318L2.24806 11.6903C2.19711 11.6602 2.15266 11.6218 2.11601 11.5773L2.02989 11.4255C2.01039 11.371 2 11.3128 2 11.253V10.1687H3.5V10.6715L3.92054 10.9199Z"></path><path d="M3.5 9.08435H2V6.91565H3.5V9.08435Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="1 1 14 14" fill="#DCD8FE93"><path d="M5.96967 5.96967C6.26256 5.67678 6.73744 5.67678 7.03033 5.96967L8 6.93934L8.96967 5.96967C9.26256 5.67678 9.73744 5.67678 10.0303 5.96967C10.3232 6.26256 10.3232 6.73744 10.0303 7.03033L9.06066 8L10.0303 8.96967C10.3232 9.26256 10.3232 9.73744 10.0303 10.0303C9.73744 10.3232 9.26256 10.3232 8.96967 10.0303L8 9.06066L7.03033 10.0303C6.73744 10.3232 6.26256 10.3232 5.96967 10.0303C5.67678 9.73744 5.67678 9.26256 5.96967 8.96967L6.93934 8L5.96967 7.03033C5.67678 6.73744 5.67678 6.26256 5.96967 5.96967Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M8.75581 1.21148C8.28876 0.929507 7.71124 0.929507 7.24419 1.21148L2.74419 3.92829C2.28337 4.20651 2 4.71711 2 5.26927V10.7307C2 11.2829 2.28337 11.7935 2.74419 12.0717L7.24419 14.7885C7.71124 15.0705 8.28876 15.0705 8.75581 14.7885L13.2558 12.0717C13.7166 11.7935 14 11.2829 14 10.7307V5.26927C14 4.71711 13.7166 4.20651 13.2558 3.92829L8.75581 1.21148ZM12.5 5.26928L8 2.55246L3.5 5.26927L3.5 10.7307L8 13.4475L12.5 10.7307L12.5 5.26928Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="1 1 14 14" fill="#5e6ad2"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.5 5.125L8 2.5L3.5 5.125L3.5 10.4019L8 13.0269L12.5 10.4019L12.5 5.125ZM8.75581 1.20433C8.28876 0.93189 7.71124 0.931889 7.24419 1.20433L2.74419 3.82933C2.28337 4.09815 2 4.5915 2 5.125V10.4019C2 10.9354 2.28337 11.4287 2.74419 11.6976L7.24419 14.3226C7.71124 14.595 8.28876 14.595 8.75581 14.3226L13.2558 11.6976C13.7166 11.4287 14 10.9354 14 10.4019V5.125C14 4.5915 13.7166 4.09815 13.2558 3.82933L8.75581 1.20433Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M10.7381 5.69424C11.0526 5.96381 11.089 6.43728 10.8194 6.75178L7.81944 10.2518C7.68349 10.4104 7.48754 10.5051 7.27878 10.5131C7.07003 10.5212 6.86739 10.4417 6.71967 10.294L5.21967 8.79402C4.92678 8.50112 4.92678 8.02625 5.21967 7.73336C5.51256 7.44046 5.98744 7.44046 6.28033 7.73336L7.20764 8.66066L9.68056 5.77559C9.95012 5.4611 10.4236 5.42468 10.7381 5.69424Z"></path></svg>

After

Width:  |  Height:  |  Size: 971 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="1 1 14 14" fill="#DCD8FE93"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.75581 1.21148C8.28876 0.929507 7.71124 0.929507 7.24419 1.21148L2.74419 3.92829C2.28337 4.20651 2 4.71711 2 5.26927V10.7307C2 11.2829 2.28337 11.7935 2.74419 12.0717L7.24419 14.7885C7.71124 15.0705 8.28876 15.0705 8.75581 14.7885L13.2558 12.0717C13.7166 11.7935 14 11.2829 14 10.7307V5.26927C14 4.71711 13.7166 4.20651 13.2558 3.92829L8.75581 1.21148ZM12.5 5.26928L8 2.55246L3.5 5.26927L3.5 10.7307L8 13.4475L12.5 10.7307L12.5 5.26928Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M6.5 5.75C6.91421 5.75 7.25 6.08579 7.25 6.5V9.5C7.25 9.91421 6.91421 10.25 6.5 10.25C6.08579 10.25 5.75 9.91421 5.75 9.5V6.5C5.75 6.08579 6.08579 5.75 6.5 5.75Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9.5 5.75C9.91421 5.75 10.25 6.08579 10.25 6.5V9.5C10.25 9.91421 9.91421 10.25 9.5 10.25C9.08579 10.25 8.75 9.91421 8.75 9.5V6.5C8.75 6.08579 9.08579 5.75 9.5 5.75Z"></path></svg>

After

Width:  |  Height:  |  Size: 1009 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" viewBox="1 1 14 14" fill="#e2e2e2"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.5 5.36133L8 2.73633L3.5 5.36133L3.5 10.6382L8 13.2632L12.5 10.6382L12.5 5.36133ZM8.75581 1.44066C8.28876 1.16822 7.71124 1.16822 7.24419 1.44066L2.74419 4.06566C2.28337 4.33448 2 4.82783 2 5.36133V10.6382C2 11.1717 2.28337 11.6651 2.74419 11.9339L7.24419 14.5589C7.71124 14.8313 8.28876 14.8313 8.75581 14.5589L13.2558 11.9339C13.7166 11.6651 14 11.1717 14 10.6382V5.36133C14 4.82783 13.7166 4.33448 13.2558 4.06566L8.75581 1.44066Z"></path></svg>

After

Width:  |  Height:  |  Size: 564 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" fill="#f2be00" viewBox="1 1 14 14"><path d="M8.3779 4.74233C8.14438 4.60607 7.85562 4.60607 7.6221 4.74233L5.37209 6.05513C5.14168 6.18957 5 6.4363 5 6.70311V9.34216C5 9.60897 5.14168 9.85573 5.37209 9.99016L7.6221 11.303C7.85562 11.4392 8.14438 11.4392 8.3779 11.303L10.6279 9.99016C10.8583 9.85573 11 9.60897 11 9.34216V6.70311C11 6.4363 10.8583 6.18957 10.6279 6.05513L8.3779 4.74233Z" mask="url(#hole-50)"></path><mask id="hole-50"><rect width="100%" height="100%" fill="white"></rect><circle r="4" cx="7.5" cy="8" fill="black" stroke="white" stroke-width="8" stroke-dasharray="calc(12.56) 25.12" transform="rotate(-90) translate(-16)"></circle></mask><path fill-rule="evenodd" clip-rule="evenodd" d="M7.24419 1.44066C7.71124 1.16822 8.28876 1.16822 8.75581 1.44066L13.2558 4.06566C13.7166 4.33448 14 4.82783 14 5.36133V10.6382C14 11.1717 13.7166 11.6651 13.2558 11.9339L8.75581 14.5589C8.28876 14.8313 7.71124 14.8313 7.24419 14.5589L2.74419 11.9339C2.28337 11.6651 2 11.1717 2 10.6382V5.36133C2 4.82783 2.28337 4.33448 2.74419 4.06566L7.24419 1.44066ZM8 2.73633L12.5 5.36133V10.6382L8 13.2632L3.5 10.6382V5.36133L8 2.73633Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,15 +1,15 @@
import { Action, useNavigation, ActionPanel, Form, Icon, getPreferenceValues, showToast, Toast } from "@raycast/api";
import { MutatePromise, useForm, FormValidation, useFetch } from "@raycast/utils";
import { Page, UniversalInboxPreferences } from "../types";
import { default as dayjs, extend } from "dayjs";
import { Notification } from "../notification";
import { TaskPriority } from "../task";
import { handleErrors } from "../api";
import utc from "dayjs/plugin/utc";
import { useState } from "react";
import fetch from "node-fetch";
import dayjs from "dayjs";
dayjs.extend(utc);
extend(utc);
interface CreateTaskFromNotificationProps {
notification: Notification;

View File

@@ -3,15 +3,15 @@ import { Action, ActionPanel, Icon, getPreferenceValues, showToast, Toast } from
import { CreateTaskFromNotification } from "./CreateTaskFromNotification";
import { LinkNotificationToTask } from "./LinkNotificationToTask";
import { Page, UniversalInboxPreferences } from "../types";
import { default as dayjs, extend } from "dayjs";
import { MutatePromise } from "@raycast/utils";
import { useMemo, ReactElement } from "react";
import { handleErrors } from "../api";
import { TaskStatus } from "../task";
import utc from "dayjs/plugin/utc";
import fetch from "node-fetch";
import dayjs from "dayjs";
dayjs.extend(utc);
extend(utc);
interface NotificationActionsProps {
notification: Notification;
@@ -20,14 +20,13 @@ interface NotificationActionsProps {
}
export function NotificationActions({ notification, detailsTarget, mutate }: NotificationActionsProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
console.log("notification_html_url", notification_html_url, notification);
return (
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
<Action.Push title="Show Details" target={detailsTarget} />
<Action
title="Delete Notification"

View File

@@ -25,14 +25,15 @@ interface NotificationTaskActionsProps {
detailsTarget: ReactElement;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function NotificationTaskActions({ notification, detailsTarget }: NotificationTaskActionsProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
return (
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
<Action.Push title="Show Details" target={detailsTarget} />
<Action
title="Delete Notification"

View File

@@ -1,8 +1,8 @@
import { GoogleMailNotificationListItem } from "./integrations/google-mail/listitem/GoogleMailNotificationListItem";
import { Action, ActionPanel, Detail, List, getPreferenceValues, openExtensionPreferences } from "@raycast/api";
import { TodoistNotificationListItem } from "./integrations/todoist/listitem/TodoistNotificationListItem";
import { GithubNotificationListItem } from "./integrations/github/listitem/GithubNotificationListItem";
import { LinearNotificationListItem } from "./integrations/linear/listitem/LinearNotificationListItem";
import { TodoistNotificationListItem } from "./integrations/todoist/TodoistNotificationListItem";
import { Notification, NotificationListItemProps } from "./notification";
import { NotificationActions } from "./action/NotificationActions";
import { Page, UniversalInboxPreferences } from "./types";

View File

@@ -1,10 +1,13 @@
import { GithubActor, getGithubActorName } from "./types";
import { Icon, Image, List } from "@raycast/api";
import { getAvatarIcon } from "@raycast/utils";
export function getGithubActorAccessory(actor?: GithubActor): List.Item.Accessory {
if (actor) {
return {
icon: actor.content.avatar_url ? { source: actor.content.avatar_url, mask: Image.Mask.Circle } : Icon.Person,
icon: actor.content.avatar_url
? { source: actor.content.avatar_url, mask: Image.Mask.Circle }
: getAvatarIcon(getGithubActorName(actor)),
tooltip: getGithubActorName(actor),
};
}

View File

@@ -8,14 +8,12 @@ import { MutatePromise } from "@raycast/utils";
import { Page } from "../../../types";
interface GithubDiscussionNotificationListItemProps {
icon: string;
notification: Notification;
githubDiscussion: GithubDiscussion;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function GithubDiscussionNotificationListItem({
icon,
notification,
githubDiscussion,
mutate,
@@ -45,7 +43,7 @@ export function GithubDiscussionNotificationListItem({
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
icon={{ source: { light: "github-logo-dark.svg", dark: "github-logo-light.svg" } }}
subtitle={subtitle}
accessories={accessories}
actions={

View File

@@ -1,22 +1,12 @@
import { GithubPullRequestNotificationListItem } from "./GithubPullRequestNotificationListItem";
import { GithubDiscussionNotificationListItem } from "./GithubDiscussionNotificationListItem";
import { NotificationListItemProps } from "../../../notification";
import { environment } from "@raycast/api";
import { useMemo } from "react";
export function GithubNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "github-logo-light.svg";
}
return "github-logo-dark.svg";
}, [environment]);
switch (notification.details?.type) {
case "GithubPullRequest":
return (
<GithubPullRequestNotificationListItem
icon={icon}
notification={notification}
githubPullRequest={notification.details.content}
mutate={mutate}
@@ -25,7 +15,6 @@ export function GithubNotificationListItem({ notification, mutate }: Notificatio
case "GithubDiscussion":
return (
<GithubDiscussionNotificationListItem
icon={icon}
notification={notification}
githubDiscussion={notification.details.content}
mutate={mutate}

View File

@@ -16,14 +16,12 @@ import { MutatePromise } from "@raycast/utils";
import { Page } from "../../../types";
interface GithubPullRequestNotificationListItemProps {
icon: string;
notification: Notification;
githubPullRequest: GithubPullRequest;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function GithubPullRequestNotificationListItem({
icon,
notification,
githubPullRequest,
mutate,
@@ -64,7 +62,7 @@ export function GithubPullRequestNotificationListItem({
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
icon={{ source: { light: "github-logo-dark.svg", dark: "github-logo-light.svg" } }}
accessories={accessories}
subtitle={subtitle}
actions={

View File

@@ -9,7 +9,7 @@ interface GithubDiscussionPreviewProps {
}
export function GithubDiscussionPreview({ notification, githubDiscussion }: GithubDiscussionPreviewProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
@@ -18,7 +18,7 @@ export function GithubDiscussionPreview({ notification, githubDiscussion }: Gith
markdown={`# ${githubDiscussion.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>

View File

@@ -9,7 +9,7 @@ interface GithubPullRequestPreviewProps {
}
export function GithubPullRequestPreview({ notification, githubPullRequest }: GithubPullRequestPreviewProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
@@ -18,7 +18,7 @@ export function GithubPullRequestPreview({ notification, githubPullRequest }: Gi
markdown={`# ${githubPullRequest.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>

View File

@@ -1,21 +1,11 @@
import { GoogleMailThreadListItem } from "./GoogleMailThreadListItem";
import { NotificationListItemProps } from "../../../notification";
import { environment } from "@raycast/api";
import { useMemo } from "react";
export function GoogleMailNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "google-mail-logo-light.svg";
}
return "google-mail-logo-dark.svg";
}, [environment]);
if (notification.metadata.type !== "GoogleMail") return null;
return (
<GoogleMailThreadListItem
icon={icon}
notification={notification}
googleMailThread={notification.metadata.content}
mutate={mutate}

View File

@@ -8,18 +8,12 @@ import { GoogleMailThread } from "../types";
import { Page } from "../../../types";
interface GoogleMailThreadListItemProps {
icon: string;
notification: Notification;
googleMailThread: GoogleMailThread;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function GoogleMailThreadListItem({
icon,
notification,
googleMailThread,
mutate,
}: GoogleMailThreadListItemProps) {
export function GoogleMailThreadListItem({ notification, googleMailThread, mutate }: GoogleMailThreadListItemProps) {
const isStarred = googleMailThread.messages.some((message) => message.labelIds?.includes("STARRED"));
const isImportant = googleMailThread.messages.some((message) => message.labelIds?.includes("IMPORTANT"));
const fromAddress = googleMailThread.messages[0].payload.headers.find((header) => header.name === "From")?.value;
@@ -50,7 +44,7 @@ export function GoogleMailThreadListItem({
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
icon={{ source: { light: "google-mail-logo-dark.svg", dark: "google-mail-logo-light.svg" } }}
accessories={accessories}
subtitle={subtitle}
actions={

View File

@@ -9,7 +9,7 @@ interface GoogleMailThreadPreviewProps {
}
export function GoogleMailThreadPreview({ notification }: GoogleMailThreadPreviewProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
@@ -18,7 +18,7 @@ export function GoogleMailThreadPreview({ notification }: GoogleMailThreadPrevie
markdown={`# ${notification.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>

View File

@@ -1,10 +1,11 @@
import { Icon, Image, List } from "@raycast/api";
import { getAvatarIcon } from "@raycast/utils";
import { LinearUser } from "./types";
export function getLinearUserAccessory(user?: LinearUser): List.Item.Accessory {
if (user) {
return {
icon: user.avatar_url ? { source: user.avatar_url, mask: Image.Mask.Circle } : Icon.Person,
icon: user.avatar_url ? { source: user.avatar_url, mask: Image.Mask.Circle } : getAvatarIcon(user.name),
tooltip: user.name,
};
}

View File

@@ -9,14 +9,12 @@ import { List } from "@raycast/api";
import { match } from "ts-pattern";
interface LinearIssueNotificationListItemProps {
icon: string;
notification: Notification;
linearIssueNotification: LinearIssueNotification;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function LinearIssueNotificationListItem({
icon,
notification,
linearIssueNotification,
mutate,
@@ -39,7 +37,7 @@ export function LinearIssueNotificationListItem({
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
icon={{ source: { light: "linear-logo-dark.svg", dark: "linear-logo-light.svg" } }}
accessories={accessories}
subtitle={subtitle}
actions={

View File

@@ -1,24 +1,14 @@
import { LinearProjectNotificationListItem } from "./LinearProjectNotificationListItem";
import { LinearIssueNotificationListItem } from "./LinearIssueNotificationListItem";
import { NotificationListItemProps } from "../../../notification";
import { environment } from "@raycast/api";
import { useMemo } from "react";
export function LinearNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "linear-logo-light.svg";
}
return "linear-logo-dark.svg";
}, [environment]);
if (notification.metadata.type !== "Linear") return null;
switch (notification.metadata.content.type) {
case "IssueNotification":
return (
<LinearIssueNotificationListItem
icon={icon}
notification={notification}
linearIssueNotification={notification.metadata.content.content}
mutate={mutate}
@@ -27,7 +17,6 @@ export function LinearNotificationListItem({ notification, mutate }: Notificatio
case "ProjectNotification":
return (
<LinearProjectNotificationListItem
icon={icon}
notification={notification}
linearProjectNotification={notification.metadata.content.content}
mutate={mutate}

View File

@@ -1,30 +1,31 @@
import { LinearProjectNotification, LinearProjectState, LinearProject } from "../types";
import { NotificationActions } from "../../../action/NotificationActions";
import { LinearProjectPreview } from "../preview/LinearProjectPreview";
import { getLinearUserAccessory } from "../accessories";
import { Notification } from "../../../notification";
import { LinearProjectNotification } from "../types";
import { MutatePromise } from "@raycast/utils";
import { List, Color } from "@raycast/api";
import { Page } from "../../../types";
import { List } from "@raycast/api";
import { match } from "ts-pattern";
interface LinearProjectNotificationListItemProps {
icon: string;
notification: Notification;
linearProjectNotification: LinearProjectNotification;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function LinearProjectNotificationListItem({
icon,
notification,
linearProjectNotification,
mutate,
}: LinearProjectNotificationListItemProps) {
const subtitle = linearProjectNotification.project.name;
const state = getLinearProjectStateAccessory(linearProjectNotification.project);
const lead = getLinearUserAccessory(linearProjectNotification.project.lead);
const accessories: List.Item.Accessory[] = [
state,
lead,
{
date: new Date(linearProjectNotification.updated_at),
@@ -36,7 +37,7 @@ export function LinearProjectNotificationListItem({
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
icon={{ source: { light: "linear-logo-dark.svg", dark: "linear-logo-light.svg" } }}
accessories={accessories}
subtitle={subtitle}
actions={
@@ -51,3 +52,29 @@ export function LinearProjectNotificationListItem({
/>
);
}
export function getLinearProjectStateAccessory(project: LinearProject): List.Item.Accessory {
return {
icon: match(project)
.with({ state: LinearProjectState.Planned }, () => {
return { source: "linear-project-planned.svg", tintColor: Color.SecondaryText };
})
.with({ state: LinearProjectState.Backlog }, () => {
return { source: "linear-project-backlog.svg", tintColor: Color.PrimaryText };
})
.with({ state: LinearProjectState.Started }, () => {
return { source: "linear-project-started.svg", tintColor: Color.Blue };
})
.with({ state: LinearProjectState.Paused }, () => {
return { source: "linear-project-paused.svg", tintColor: Color.PrimaryText };
})
.with({ state: LinearProjectState.Completed }, () => {
return { source: "linear-project-completed.svg", tintColor: Color.Magenta };
})
.with({ state: LinearProjectState.Canceled }, () => {
return { source: "linear-project-canceled.svg", tintColor: Color.SecondaryText };
})
.exhaustive(),
tooltip: project.state,
};
}

View File

@@ -9,7 +9,7 @@ interface LinearIssuePreviewProps {
}
export function LinearIssuePreview({ notification, linearIssue }: LinearIssuePreviewProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
@@ -18,7 +18,7 @@ export function LinearIssuePreview({ notification, linearIssue }: LinearIssuePre
markdown={`# ${linearIssue.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>

View File

@@ -9,7 +9,7 @@ interface LinearProjectPreviewProps {
}
export function LinearProjectPreview({ notification, linearProject }: LinearProjectPreviewProps) {
const notification_html_url = useMemo(() => {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
@@ -18,7 +18,7 @@ export function LinearProjectPreview({ notification, linearProject }: LinearProj
markdown={`# ${linearProject.name}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>

View File

@@ -1,29 +0,0 @@
import { NotificationTaskActions } from "../../action/NotificationTaskActions";
import { NotificationListItemProps } from "../../notification";
import { Detail, List, environment } from "@raycast/api";
import { useMemo } from "react";
export function TodoistNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "todoist-icon-light.svg";
}
return "todoist-icon-dark.svg";
}, [environment]);
return (
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
subtitle={`#${notification.source_id}`}
actions={
<NotificationTaskActions
notification={notification}
detailsTarget={<Detail markdown="# To be implemented 👋" />}
mutate={mutate}
/>
}
/>
);
}

View File

@@ -0,0 +1,52 @@
import { NotificationTaskActions } from "../../../action/NotificationTaskActions";
import { TodoistTaskPreview } from "../preview/TodoistTaskPreview";
import { NotificationListItemProps } from "../../../notification";
import { Icon, List, Color } from "@raycast/api";
import { TaskPriority } from "../../../task";
import { match } from "ts-pattern";
import dayjs from "dayjs";
export function TodoistNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const dueAt = notification.task?.due_at?.content;
const subtitle = dueAt ? dayjs(dueAt).format("YYYY-MM-DD") : undefined;
const color = match(notification)
.with({ task: { priority: TaskPriority.P1 } }, () => Color.Red)
.with({ task: { priority: TaskPriority.P2 } }, () => Color.Orange)
.with({ task: { priority: TaskPriority.P3 } }, () => Color.Yellow)
.otherwise(() => null);
const accessories: List.Item.Accessory[] = [
{
icon: { source: Icon.Circle, tintColor: color },
},
{
date: new Date(notification.updated_at),
tooltip: `Updated at ${notification.updated_at}`,
},
];
const task = notification.task;
if (task) {
for (const tag of task.tags) {
accessories.unshift({ tag: { value: tag } });
}
}
return (
<List.Item
key={notification.id}
title={notification.title}
icon={{ source: { light: "todoist-logo-dark.svg", dark: "todoist-logo-light.svg" } }}
subtitle={subtitle}
accessories={accessories}
actions={
<NotificationTaskActions
notification={notification}
detailsTarget={<TodoistTaskPreview notification={notification} />}
mutate={mutate}
/>
}
/>
);
}

View File

@@ -0,0 +1,24 @@
import { Notification, getNotificationHtmlUrl } from "../../../notification";
import { Detail, ActionPanel, Action } from "@raycast/api";
import { useMemo } from "react";
interface TodoistTaskPreviewProps {
notification: Notification;
}
export function TodoistTaskPreview({ notification }: TodoistTaskPreviewProps) {
const notificationHtmlUrl = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
return (
<Detail
markdown={`# ${notification.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notificationHtmlUrl} />
</ActionPanel>
}
/>
);
}

View File

@@ -64,7 +64,7 @@ export function getNotificationHtmlUrl(notification: Notification) {
(googleMailThread) =>
`https://mail.google.com/mail/u/${googleMailThread.user_email_address}/#inbox/${googleMailThread.id}`,
)
.with({ metadata: { type: "Todoist", content: P.select() } }, () => "")
.with({ metadata: { type: "Todoist" } }, () => `https://todoist.com/showTask?id=${notification.source_id}`)
.with({ metadata: { type: "Github" } }, () => "https://github.com")
.exhaustive();
}