Skip to content
Draft
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
3 changes: 3 additions & 0 deletions apps/frontend/public/icons/received.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions apps/frontend/public/icons/sent.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions apps/frontend/src/components/icons/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IoMdRemove as Remove } from "react-icons/io";
import { FaRegCalendar as Calendar } from "react-icons/fa";
import { IoMenu as Menu } from "react-icons/io5";
import { IoIosCloseCircle as CloseLocation } from "react-icons/io";
import { LuHourglass as Hourglass } from "react-icons/lu";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Icons: Record<string, any> = {
Expand All @@ -29,6 +30,41 @@ export const Icons: Record<string, any> = {
Calendar,
Menu,
CloseLocation,
Hourglass,
// @ts-ignore
Job: (props: any) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="19"
height="18"
viewBox="0 0 19 18"
fill="none"
{...props}
>
<path
d="M16.249 9.94157C14.1646 10.7853 11.8861 11.25 9.49903 11.25C7.112 11.25 4.83349 10.7853 2.74902 9.94157M12.499 4.5V3C12.499 2.17157 11.8275 1.5 10.999 1.5H7.99902C7.1706 1.5 6.49902 2.17157 6.49902 3V4.5M9.49902 9H9.50652M4.24902 15H14.749C15.5775 15 16.249 14.3284 16.249 13.5V6C16.249 5.17157 15.5775 4.5 14.749 4.5H4.24902C3.4206 4.5 2.74902 5.17157 2.74902 6V13.5C2.74902 14.3284 3.4206 15 4.24902 15Z"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
// @ts-ignore
Star: (props: any) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
{...props}
>
<path
d="M8.04895 2.92664C8.34833 2.00538 9.65167 2.00538 9.95104 2.92664L10.7963 5.52768C10.9302 5.93967 11.3141 6.21861 11.7473 6.21863L14.4822 6.21873C15.4509 6.21877 15.8537 7.45832 15.07 8.02773L12.8575 9.63536C12.507 9.89 12.3604 10.3413 12.4942 10.7533L13.3392 13.3544C13.6385 14.2757 12.5841 15.0418 11.8004 14.4725L9.58776 12.865C9.23728 12.6104 8.76272 12.6104 8.41225 12.865L6.19958 14.4725C5.41588 15.0418 4.36145 14.2757 4.66076 13.3544L5.5058 10.7533C5.63965 10.3413 5.493 9.89 5.14255 9.63536L2.93 8.02773C2.14634 7.45832 2.54909 6.21877 3.51778 6.21873L6.25271 6.21863C6.68591 6.21861 7.06984 5.93967 7.20372 5.52768L8.04895 2.92664Z"
stroke="currentColor"
/>
</svg>
),
Checked: () => (
<svg
className="w-4 h-4 text-gray-900"
Expand Down
10 changes: 9 additions & 1 deletion apps/frontend/src/components/ui/CircleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import Image from "next/image";
import type * as Classed from "@tw-classed/react";
import { IconCircle } from "./FeedContent";

type CardIconType = "person" | "location" | "proof" | "overlap";
type CardIconType =
| "person"
| "location"
| "proof"
| "overlap"
| "received"
| "sent";

type CardIconVariants = Classed.VariantProps<typeof IconCircle>;

Expand All @@ -11,6 +17,8 @@ const CardIconMapping: Record<CardIconType, string> = {
location: "/icons/location.svg",
proof: "/icons/proof.svg",
overlap: "/icons/overlap.svg",
received: "/icons/received.svg",
sent: "/icons/sent.svg",
};

interface CircleCardProps extends CardIconVariants {
Expand Down
27 changes: 21 additions & 6 deletions apps/frontend/src/components/ui/FeedContent.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { cn } from "@/lib/frontend/util";
import { classed } from "@tw-classed/react";

interface FeedContentProps {
className?: string;
title: React.ReactNode;
titleOverride?: boolean;
description: string;
description: React.ReactNode;
icon: React.ReactNode;
color?: string;
}
export const IconCircle = classed.div(
"flex justify-center items-center h-6 w-6 rounded-full text-label-primary",
{
variants: {
color: {
primary: "bg-button-secondary",
transparent: "bg-transparent",
},
border: {
true: "",
Expand All @@ -30,11 +34,18 @@ export const FeedContent = ({
description,
titleOverride,
icon,
className = "",
color = "primary",
}: FeedContentProps) => {
return (
<div className="grid grid-cols-[1fr_60px] items-center justify-between py-1 gap-4">
<div
className={cn(
"grid grid-cols-[1fr_60px] items-center justify-between py-1 gap-4",
className
)}
>
<div className="grid grid-cols-[24px_1fr] items-center gap-2 truncate">
<IconCircle>{icon}</IconCircle>
<IconCircle color={color as any}>{icon}</IconCircle>
{titleOverride === true ? (
<CardTitleOverride className="truncate text-label-primary font-sans font-normal">
{title}
Expand All @@ -45,9 +56,13 @@ export const FeedContent = ({
</span>
)}
</div>
<span className="text-xs font-medium leading-4 text-label-tertiary font-sans ">
{description}
</span>
{typeof description === "string" ? (
<span className="text-xs font-medium leading-4 text-label-tertiary font-sans ">
{description}
</span>
) : (
description
)}
</div>
);
};
10 changes: 10 additions & 0 deletions apps/frontend/src/components/ui/NavTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { classed } from "@tw-classed/react";

export const NavTab = classed.button("text-sm duration-200", {
variants: {
active: {
true: "font-semibold underline underline-offset-8 text-label-primary",
false: "font-normal text-label-quaternary",
},
},
});
7 changes: 4 additions & 3 deletions apps/frontend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const FRONTEND_URL =
export const BASE_API_URL =
process.env.NEXT_PUBLIC_API_URL || "http://localhost:8080/api";

export const BASE_API_WS = process.env.NEXT_PUBLIC_API_WS || "ws://localhost:8080";
export const BASE_API_WS =
process.env.NEXT_PUBLIC_API_WS || "ws://localhost:8080";

export const OAUTH_APP_DETAILS: Record<DataImportSource, OAuthAppDetails> = {
strava: {
Expand Down Expand Up @@ -83,8 +84,8 @@ export const ROUTER_ITEMS: RouterItem[] = [
iconSize: 20,
},
{
label: "Narrowcast",
href: "/narrowcast",
label: "Digital pheromones",
href: "/pheromones",
icon: Icons.NarrowCast,
iconSize: 20,
},
Expand Down
52 changes: 0 additions & 52 deletions apps/frontend/src/pages/narrowcast/index.tsx

This file was deleted.

3 changes: 3 additions & 0 deletions apps/frontend/src/pages/pheromones/cv/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function CvPage() {
return <>Cv page</>;
}
90 changes: 90 additions & 0 deletions apps/frontend/src/pages/pheromones/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { NavTab } from "@/components/ui/NavTab";
import AppLayout from "@/layouts/AppLayout";
import { useState } from "react";
import { PheromonesCreate } from "./sections/PheromonesCreate";
import { PheromonesMatches } from "./sections/PheromonesMatches";
import { PheromonesSent } from "./sections/PheromonesSent";
import { PheromonesReceived } from "./sections/PheromonesReceived";

enum ActiveTab {
CREATE,
SENT,
RECEIVED,
MATCHES,
}

export default function PheromonesPage() {
const [activeTab, setActiveTab] = useState(ActiveTab.CREATE);

const ViewMapping: Record<ActiveTab, any> = {
[ActiveTab.CREATE]: PheromonesCreate,
[ActiveTab.SENT]: PheromonesSent,
[ActiveTab.RECEIVED]: PheromonesReceived,
[ActiveTab.MATCHES]: PheromonesMatches,
};

return (
<AppLayout
seoTitle="Digital pheromones"
header={
<div className="flex flex-col">
<span className="text-label-primary text-xl leading-none font-bold tracking-[-0.1px] py-4">
Digital pheromones
</span>
<div className="py-3 flex gap-6">
<NavTab
active={activeTab === ActiveTab.CREATE}
onClick={() => {
setActiveTab(ActiveTab.CREATE);
}}
>
Create
</NavTab>
<NavTab
active={activeTab === ActiveTab.SENT}
onClick={() => {
setActiveTab(ActiveTab.SENT);
}}
>
Sent
</NavTab>
<NavTab
active={activeTab === ActiveTab.RECEIVED}
onClick={() => {
setActiveTab(ActiveTab.RECEIVED);
}}
>
Received
</NavTab>
<NavTab
active={activeTab === ActiveTab.MATCHES}
onClick={() => {
setActiveTab(ActiveTab.MATCHES);
}}
>
Matches
</NavTab>
</div>
<div
className="absolute left-0 right-0 bottom-0 h-[2px]"
style={{
background: `linear-gradient(90deg, #7A74BC 0%, #FF9DF8 39%, #FB5D42 71%, #F00 100%)`,
}}
></div>
</div>
}
withContainer={false}
>
<div className="flex flex-col items-center justify-center px-3">
<span className="text-sm font-sans text-label-quaternary font-medium p-2">
Multi-party computation enables{" "}
<span className="font-bold">digital pheromones</span>, the ability to
coordinate in a p2p way using lightweight, privacy-preserving signals.
</span>
<div className="flex flex-col py-4 w-full">
{ViewMapping?.[activeTab]?.() ?? null}
</div>
</div>
</AppLayout>
);
}
3 changes: 3 additions & 0 deletions apps/frontend/src/pages/pheromones/jobs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function JobsPage() {
return null;
}
Loading