Skip to content

Commit

Permalink
[WEB-3096] feat: stickies page (#6380)
Browse files Browse the repository at this point in the history
* feat: added independent stickies page

* chore: randomized sticky color

* chore: search in stickies

* feat: dnd

* fix: quick links

* fix: stickies abrupt rendering

* fix: handled edge cases for dnd

* fix: empty states

* fix: build and lint

* fix: handled new sticky when last sticky is emoty

* fix: new sticky condition

* refactor: stickies empty states, store

* chore: update stickies empty states

* fix: random sticky color

* fix: header

* refactor: better error handling

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
  • Loading branch information
3 people authored Jan 16, 2025
1 parent d2c9b43 commit fd7eedc
Show file tree
Hide file tree
Showing 56 changed files with 1,347 additions and 574 deletions.
6 changes: 3 additions & 3 deletions apiserver/plane/app/views/workspace/sticky.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ def create(self, request, slug):
)
def list(self, request, slug):
query = request.query_params.get("query", False)
stickies = self.get_queryset()
stickies = self.get_queryset().order_by("-sort_order")
if query:
stickies = stickies.filter(name__icontains=query)
stickies = stickies.filter(description_stripped__icontains=query)

return self.paginate(
request=request,
queryset=(stickies),
on_results=lambda stickies: StickySerializer(stickies, many=True).data,
default_per_page=20,
)

@allow_permission(allowed_roles=[], creator=True, model=Sticky, level="WORKSPACE")
def partial_update(self, request, *args, **kwargs):
return super().partial_update(request, *args, **kwargs)
Expand Down
9 changes: 9 additions & 0 deletions apiserver/plane/db/models/sticky.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
# Module imports
from .base import BaseModel

# Third party imports
from plane.utils.html_processor import strip_tags


class Sticky(BaseModel):
name = models.TextField(null=True, blank=True)
Expand Down Expand Up @@ -33,6 +36,12 @@ class Meta:
ordering = ("-created_at",)

def save(self, *args, **kwargs):
# Strip the html tags using html parser
self.description_stripped = (
None
if (self.description_html == "" or self.description_html is None)
else strip_tags(self.description_html)
)
if self._state.adding:
# Get the maximum sequence value from the database
last_id = Sticky.objects.filter(workspace=self.workspace).aggregate(
Expand Down
1 change: 1 addition & 0 deletions packages/constants/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./state";
export * from "./swr";
export * from "./user";
export * from "./workspace";
export * from "./stickies";
1 change: 1 addition & 0 deletions packages/constants/src/stickies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const STICKIES_PER_PAGE = 30;
2 changes: 1 addition & 1 deletion packages/editor/src/styles/editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
position: relative;
-webkit-appearance: none;
appearance: none;
background-color: rgb(var(--color-background-100));
background-color: transparent;
margin: 0;
cursor: pointer;
width: 0.8rem;
Expand Down
38 changes: 0 additions & 38 deletions packages/editor/src/styles/variables.css
Original file line number Diff line number Diff line change
@@ -1,41 +1,3 @@
:root {
/* text colors */
--editor-colors-gray-text: #5c5e63;
--editor-colors-peach-text: #ff5b59;
--editor-colors-pink-text: #f65385;
--editor-colors-orange-text: #fd9038;
--editor-colors-green-text: #0fc27b;
--editor-colors-light-blue-text: #17bee9;
--editor-colors-dark-blue-text: #266df0;
--editor-colors-purple-text: #9162f9;
/* end text colors */
}

/* text background colors */
[data-theme="light"],
[data-theme="light-contrast"] {
--editor-colors-gray-background: #d6d6d8;
--editor-colors-peach-background: #ffd5d7;
--editor-colors-pink-background: #fdd4e3;
--editor-colors-orange-background: #ffe3cd;
--editor-colors-green-background: #c3f0de;
--editor-colors-light-blue-background: #c5eff9;
--editor-colors-dark-blue-background: #c9dafb;
--editor-colors-purple-background: #e3d8fd;
}
[data-theme="dark"],
[data-theme="dark-contrast"] {
--editor-colors-gray-background: #404144;
--editor-colors-peach-background: #593032;
--editor-colors-pink-background: #562e3d;
--editor-colors-orange-background: #583e2a;
--editor-colors-green-background: #1d4a3b;
--editor-colors-light-blue-background: #1f495c;
--editor-colors-dark-blue-background: #223558;
--editor-colors-purple-background: #3d325a;
}
/* end text background colors */

.editor-container {
/* font sizes and line heights */
&.large-font {
Expand Down
16 changes: 12 additions & 4 deletions packages/types/src/stickies.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { TLogoProps } from "./common";

export type TSticky = {
created_at?: string | undefined;
created_by?: string | undefined;
background_color?: string | null | undefined;
description?: object | undefined;
description_html?: string | undefined;
id: string;
logo_props: TLogoProps | undefined;
name?: string;
description_html?: string;
color?: string;
createdAt?: Date;
updatedAt?: Date;
sort_order: number | undefined;
updated_at?: string | undefined;
updated_by?: string | undefined;
workspace: string | undefined;
};
59 changes: 59 additions & 0 deletions web/app/[workspaceSlug]/(projects)/stickies/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";

import { observer } from "mobx-react";
// ui
import { useParams } from "next/navigation";
import { Breadcrumbs, Button, Header, RecentStickyIcon } from "@plane/ui";
// components
import { BreadcrumbLink } from "@/components/common";

// hooks
import { StickySearch } from "@/components/stickies/modal/search";
import { useStickyOperations } from "@/components/stickies/sticky/use-operations";
// plane-web
import { useSticky } from "@/hooks/use-stickies";

export const WorkspaceStickyHeader = observer(() => {
const { workspaceSlug } = useParams();
// hooks
const { creatingSticky, toggleShowNewSticky } = useSticky();
const { stickyOperations } = useStickyOperations({ workspaceSlug: workspaceSlug?.toString() });

return (
<>
<Header>
<Header.LeftItem>
<div className="flex items-center gap-2.5">
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<BreadcrumbLink
label={`Stickies`}
icon={<RecentStickyIcon className="size-5 rotate-90 text-custom-text-200" />}
/>
}
/>
</Breadcrumbs>
</div>
</Header.LeftItem>

<Header.RightItem>
<StickySearch />
<Button
variant="primary"
size="sm"
className="items-center gap-1"
onClick={() => {
toggleShowNewSticky(true);
stickyOperations.create();
}}
loading={creatingSticky}
>
Add sticky
</Button>
</Header.RightItem>
</Header>
</>
);
});
13 changes: 13 additions & 0 deletions web/app/[workspaceSlug]/(projects)/stickies/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import { AppHeader, ContentWrapper } from "@/components/core";
import { WorkspaceStickyHeader } from "./header";

export default function WorkspaceStickiesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<WorkspaceStickyHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}
16 changes: 16 additions & 0 deletions web/app/[workspaceSlug]/(projects)/stickies/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

// components
import { PageHead } from "@/components/core";
import { StickiesInfinite } from "@/components/stickies";

export default function WorkspaceStickiesPage() {
return (
<>
<PageHead title="Your stickies" />
<div className="relative h-full w-full overflow-hidden overflow-y-auto">
<StickiesInfinite />
</div>
</>
);
}
24 changes: 14 additions & 10 deletions web/core/components/core/content-overflow-HOC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface IContentOverflowWrapper {
buttonClassName?: string;
containerClassName?: string;
fallback?: ReactNode;
customButton?: ReactNode;
}

export const ContentOverflowWrapper = observer((props: IContentOverflowWrapper) => {
Expand All @@ -18,6 +19,7 @@ export const ContentOverflowWrapper = observer((props: IContentOverflowWrapper)
buttonClassName = "text-sm font-medium text-custom-primary-100",
containerClassName,
fallback = null,
customButton,
} = props;

// states
Expand Down Expand Up @@ -131,16 +133,18 @@ export const ContentOverflowWrapper = observer((props: IContentOverflowWrapper)
pointerEvents: isTransitioning ? "none" : "auto",
}}
>
<button
className={cn(
"gap-1 w-full text-custom-primary-100 text-sm font-medium transition-opacity duration-300",
buttonClassName
)}
onClick={handleToggle}
disabled={isTransitioning}
>
{showAll ? "Show less" : "Show all"}
</button>
{customButton || (
<button
className={cn(
"gap-1 w-full text-custom-primary-100 text-sm font-medium transition-opacity duration-300",
buttonClassName
)}
onClick={handleToggle}
disabled={isTransitioning}
>
{showAll ? "Show less" : "Show all"}
</button>
)}
</div>
)}
</div>
Expand Down
78 changes: 78 additions & 0 deletions web/core/components/editor/sticky-editor/color-palette.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { TSticky } from "@plane/types";

export const STICKY_COLORS_LIST: {
key: string;
label: string;
backgroundColor: string;
}[] = [
{
key: "gray",
label: "Gray",
backgroundColor: "var(--editor-colors-gray-background)",
},
{
key: "peach",
label: "Peach",
backgroundColor: "var(--editor-colors-peach-background)",
},
{
key: "pink",
label: "Pink",
backgroundColor: "var(--editor-colors-pink-background)",
},
{
key: "orange",
label: "Orange",
backgroundColor: "var(--editor-colors-orange-background)",
},
{
key: "green",
label: "Green",
backgroundColor: "var(--editor-colors-green-background)",
},
{
key: "light-blue",
label: "Light blue",
backgroundColor: "var(--editor-colors-light-blue-background)",
},
{
key: "dark-blue",
label: "Dark blue",
backgroundColor: "var(--editor-colors-dark-blue-background)",
},
{
key: "purple",
label: "Purple",
backgroundColor: "var(--editor-colors-purple-background)",
},
];

type TProps = {
handleUpdate: (data: Partial<TSticky>) => Promise<void>;
};

export const ColorPalette = (props: TProps) => {
const { handleUpdate } = props;
return (
<div className="absolute z-10 bottom-5 left-0 w-56 shadow p-2 rounded-md bg-custom-background-100 mb-2">
<div className="text-sm font-semibold text-custom-text-400 mb-2">Background colors</div>
<div className="flex flex-wrap gap-2">
{STICKY_COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
onClick={() => {
handleUpdate({
background_color: color.key,
});
}}
className="h-6 w-6 rounded-md hover:ring-2 hover:ring-custom-primary focus:outline-none focus:ring-2 focus:ring-custom-primary transition-all"
style={{
backgroundColor: color.backgroundColor,
}}
/>
))}
</div>
</div>
);
};
36 changes: 0 additions & 36 deletions web/core/components/editor/sticky-editor/color-pallete.tsx

This file was deleted.

Loading

0 comments on commit fd7eedc

Please sign in to comment.