Compare commits

..

8 Commits

Author SHA1 Message Date
Henry
ea92dcd2ed feat: add basic white labelling (#146) 2025-08-15 15:20:07 +01:00
Henry
d51600aba8 refactor: improve card layout and scrollbar styling (#143) 2025-08-14 22:10:45 +01:00
Henry
c3ed2e5e7f fix: missing translation for editor placeholder (#142) 2025-08-14 21:36:43 +01:00
Henry
13b10471ec feat: card checklists (#141)
* feat: setup checklist schema

* feat: scaffold checklist router

* feat: add create new checklist modal

* feat: create new checklist item

* feat: toggle checklist item completed state

* feat: update checklist name

* feat: delete checklist

* feat: show checklists progress on cards

* feat: tweak light mode styling

* feat: focus item form on creation of new checklist

* feat: tweak new checklist item form styling

* feat: add checklist activity

* feat: show checklist progress on public board page

* feat: display checklist items on public card modal

* chore: add translations
2025-08-14 19:59:36 +01:00
Cyber
80d1c5f805 fix: check if POSTGRES_URL env variable is set before starting the migration script (if external db) (#139) 2025-08-14 19:58:26 +01:00
Ridham Khandar
8079345546 feat: tagging members in description (#140)
* feat: tagging members in description

* chore: tiptap mention package

* feat: avatar before names in members dropdown
2025-08-14 19:57:35 +01:00
Ridham Khandar
4a67afdd3a fix: add new created label to selected label (#136) 2025-08-09 20:35:29 +01:00
Cyber
d555546782 feat: add pglite support (#138) 2025-08-09 20:32:13 +01:00
33 changed files with 626 additions and 307 deletions

View File

@@ -3,6 +3,8 @@
# Required environment variables
NEXT_PUBLIC_BASE_URL= # e.g. https://kan.bn
BETTER_AUTH_SECRET= # Random 32+ char string (can gen with: openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)
# Fill if you want to use an external database
POSTGRES_URL= # e.g. postgresql://kan:your_password@your_host:5432/kan
# Only required if deploying from compose

3
.gitignore vendored
View File

@@ -50,3 +50,6 @@ docker-compose.override.yml
# runtime env
__ENV.js
i18n.cache
# pgdata
/apps/web/pgdata

View File

@@ -138,36 +138,37 @@ pnpm dev
## Environment Variables 🔐
| Variable | Description | Required | Example |
| -------------------------------- | -------------------------------------------------------- | ------------------ | --------------------------------------------- |
| `POSTGRES_URL` | PostgreSQL connection URL | Yes | `postgres://user:pass@localhost:5432/db` |
| `EMAIL_FROM` | Sender email address | For Email | `"Kan <hello@mail.kan.bn>"` |
| `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` |
| `SMTP_PORT` | SMTP server port | For Email | `465` |
| `SMTP_USER` | SMTP username/email | No | `resend` |
| `SMTP_PASSWORD` | SMTP password/token | No | `re_xxxx` |
| `SMTP_SECURE` | Use secure SMTP connection (defaults to true if not set) | For Email | `true` |
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | For Google login | `xxx.apps.googleusercontent.com` |
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | For Google login | `xxx` |
| `DISCORD_CLIENT_ID` | Discord OAuth client ID | For Discord login | `xxx` |
| `DISCORD_CLIENT_SECRET` | Discord OAuth client secret | For Discord login | `xxx` |
| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | For GitHub login | `xxx` |
| `GITHUB_CLIENT_SECRET` | GitHub OAuth client secret | For GitHub login | `xxx` |
| `TRELLO_APP_API_KEY` | Trello app API key | For Trello import | `xxx` |
| `TRELLO_APP_API_SECRET` | Trello app API secret | For Trello import | `xxx` |
| `S3_REGION` | S3 storage region | For file uploads | `WEUR` |
| `S3_ENDPOINT` | S3 endpoint URL | For file uploads | `https://xxx.r2.cloudflarestorage.com` |
| `S3_ACCESS_KEY_ID` | S3 access key | For file uploads | `xxx` |
| `S3_SECRET_ACCESS_KEY` | S3 secret key | For file uploads | `xxx` |
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
| `NEXT_PUBLIC_DISABLE_SIGN_UP` | Disable sign up | For authentication | `false` |
| Variable | Description | Required | Example |
| ----------------------------------------- | -------------------------------------------------------- | ------------------------ | --------------------------------------------- |
| `POSTGRES_URL` | PostgreSQL connection URL | To use external database | `postgres://user:pass@localhost:5432/db` |
| `EMAIL_FROM` | Sender email address | For Email | `"Kan <hello@mail.kan.bn>"` |
| `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` |
| `SMTP_PORT` | SMTP server port | For Email | `465` |
| `SMTP_USER` | SMTP username/email | No | `resend` |
| `SMTP_PASSWORD` | SMTP password/token | No | `re_xxxx` |
| `SMTP_SECURE` | Use secure SMTP connection (defaults to true if not set) | For Email | `true` |
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | For Google login | `xxx.apps.googleusercontent.com` |
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | For Google login | `xxx` |
| `DISCORD_CLIENT_ID` | Discord OAuth client ID | For Discord login | `xxx` |
| `DISCORD_CLIENT_SECRET` | Discord OAuth client secret | For Discord login | `xxx` |
| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | For GitHub login | `xxx` |
| `GITHUB_CLIENT_SECRET` | GitHub OAuth client secret | For GitHub login | `xxx` |
| `TRELLO_APP_API_KEY` | Trello app API key | For Trello import | `xxx` |
| `TRELLO_APP_API_SECRET` | Trello app API secret | For Trello import | `xxx` |
| `S3_REGION` | S3 storage region | For file uploads | `WEUR` |
| `S3_ENDPOINT` | S3 endpoint URL | For file uploads | `https://xxx.r2.cloudflarestorage.com` |
| `S3_ACCESS_KEY_ID` | S3 access key | For file uploads | `xxx` |
| `S3_SECRET_ACCESS_KEY` | S3 secret key | For file uploads | `xxx` |
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
| `NEXT_PUBLIC_DISABLE_SIGN_UP` | Disable sign up | For authentication | `false` |
| `NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY` | Hide “Powered by kan.bn” on public boards (self-host) | For white labelling | `true` |
See `.env.example` for a complete list of supported environment variables.

View File

@@ -81,5 +81,4 @@ ARG PORT=3000
ENV PORT=${PORT}
EXPOSE ${PORT}
CMD ["sh", "-c", "cd /app && pnpm db:migrate && cd /app/apps/web && pnpm start"]
CMD ["sh", "-c", "if [ -n \"$POSTGRES_URL\" ]; then cd /app && pnpm db:migrate && cd /app/apps/web; fi && pnpm start"]

View File

@@ -15,7 +15,7 @@ checksums:
Add%20a%20comment.../singular: c28cfccc0cc69a2a2487e37eb9988028
Add%20an%20item.../singular: f8e7993980420698700b07f56b3a38af
Add%20checklist/singular: 05d73200b56cfea75fb3a0f94c9bfb74
Add%20description...%20(type%20'%2F'%20to%20open%20commands)/singular: df99ea599521682e9ad0a90716955dc6
Add%20description...%20(type%20'%2F'%20to%20open%20commands%20or%20'%40'%20to%20mention)/singular: c6eb35a796dd7ac0e3dbc66244b71248
Add%20details.../singular: 2f42547fd5d199f173aa7a88c8a9b19a
Add%20label/singular: 0be732d46df263265935fda342097a08
Add%20member/singular: 11979625770516ca287e929381778e02

View File

@@ -33,6 +33,7 @@
"@tailwindcss/typography": "^0.5.16",
"@tanstack/react-query": "catalog:",
"@tiptap/extension-link": "^2.22.2",
"@tiptap/extension-mention": "^3.0.9",
"@tiptap/extension-placeholder": "^2.14.0",
"@tiptap/pm": "^2.14.0",
"@tiptap/react": "^2.14.0",

View File

@@ -12,11 +12,14 @@ export function DeleteLabelConfirmation({
labelPublicId: string;
refetch: () => void;
}) {
const { closeModal } = useModal();
const { closeModal, closeModals } = useModal();
const { showPopup } = usePopup();
const deleteLabelMutation = api.label.delete.useMutation({
onSuccess: () => refetch(),
onSuccess: () => {
refetch();
closeModals(2);
},
onError: () =>
showPopup({
header: t`Error deleting label`,
@@ -26,7 +29,6 @@ export function DeleteLabelConfirmation({
});
const handleDeleteLabel = () => {
closeModal();
deleteLabelMutation.mutate({
labelPublicId,
});

View File

@@ -39,6 +39,9 @@ import {
} from "react-icons/hi2";
import { twMerge } from "tailwind-merge";
import tippy from "tippy.js";
import Mention from "@tiptap/extension-mention";
import Avatar from "./Avatar";
import { getAvatarUrl } from "~/utils/helpers";
declare module "@tiptap/core" {
interface Commands<ReturnType> {
@@ -74,6 +77,16 @@ export interface RenderSuggestionsProps {
command: (item: SlashCommandItem) => void;
}
export type WorkspaceMember = {
publicId: string;
user: {
id: string;
name: string | null;
image: string | null;
} | null;
email: string;
};
const CommandsList = forwardRef<
{ onKeyDown: (props: SuggestionKeyDownProps) => boolean },
{
@@ -187,6 +200,125 @@ const RenderSuggestions = () => {
};
};
type MentionItem = { id: string; label: string; image: string | null };
const MentionList = forwardRef<
{ onKeyDown: (props: SuggestionKeyDownProps) => boolean },
{
items: MentionItem[];
command: (item: MentionItem) => void;
}
>(({ items, command }, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0);
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }: SuggestionKeyDownProps) => {
if (event.key === "ArrowUp") {
setSelectedIndex((selectedIndex + items.length - 1) % items.length);
return true;
}
if (event.key === "ArrowDown") {
setSelectedIndex((selectedIndex + 1) % items.length);
return true;
}
if (event.key === "Enter") {
const item = items[selectedIndex];
if (item) {
command(item);
}
return true;
}
return false;
},
}));
return (
<div className="w-56 rounded-md border-[1px] border-light-200 bg-light-50 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-500 dark:bg-dark-200">
<div className="max-h-[350px] overflow-y-auto p-1 scrollbar-thin scrollbar-thumb-light-200 dark:scrollbar-thumb-dark-300">
{items.length > 0 ? items.map((item, index) => (
<button
key={item.id}
onClick={() => command(item)}
className={twMerge(
"group flex w-full items-center rounded-[5px] p-2 hover:bg-light-200 dark:hover:bg-dark-300",
index === selectedIndex && "bg-light-200 dark:bg-dark-300",
)}
>
<Avatar
size="xs"
name={item.label}
imageUrl={
item.image ? getAvatarUrl(item.image) : undefined
}
email={item.label}
/>
<span className="ml-3 text-[12px] font-medium text-dark-900 dark:text-dark-1000">
{item.label}
</span>
</button>
)) : (
<div className="flex items-center justify-start p-2">
<span className="text-dark-900 text-[12px] dark:text-dark-1000">No results</span>
</div>
)}
</div>
</div>
);
});
MentionList.displayName = "MentionList";
const renderMentionSuggestions = () => {
let reactRenderer: ReactRenderer;
let popup: TippyInstance[];
return {
onStart: (props: any) => {
reactRenderer = new ReactRenderer(MentionList, {
props,
editor: props.editor,
});
if (!props.clientRect) return;
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () => document.body,
content: reactRenderer.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onUpdate(props: any) {
reactRenderer.updateProps(props);
if (!props.clientRect) return;
popup[0]?.setProps({ getReferenceClientRect: props.clientRect });
},
onKeyDown(props: SuggestionKeyDownProps) {
if (props.event.key === "Escape") {
popup[0]?.hide();
return true;
}
return (
(
reactRenderer.ref as {
onKeyDown?: (props: SuggestionKeyDownProps) => boolean;
}
).onKeyDown?.(props) ?? false
);
},
onExit() {
popup[0]?.destroy();
reactRenderer.destroy();
},
};
};
const SlashCommands = Extension.create<SlashCommandsOptions>({
name: "slash-commands",
addOptions() {
@@ -290,11 +422,13 @@ export default function Editor({
onChange,
onBlur,
readOnly = false,
workspaceMembers,
}: {
content: string | null;
onChange?: (value: string) => void;
onBlur?: () => void;
readOnly?: boolean;
workspaceMembers: WorkspaceMember[];
}) {
const containerRef = useRef<HTMLDivElement>(null);
@@ -305,7 +439,7 @@ export default function Editor({
Placeholder.configure({
placeholder: readOnly
? ""
: t`Add description... (type '/' to open commands)`,
: t`Add description... (type '/' to open commands or '@' to mention)`,
}),
Link.configure({
openOnClick: true,
@@ -326,6 +460,38 @@ export default function Editor({
char: "/",
},
}),
Mention.configure({
HTMLAttributes: {
class: 'mention',
},
suggestion: {
char: "@",
items: ({ query }: { query: string }) => {
const all: MentionItem[] = workspaceMembers.map((member: WorkspaceMember) => ({
id: member.publicId,
label: member?.user?.name ?? member.email,
image: member?.user?.image ?? null,
}));
const q = query.toLowerCase();
return all.filter((u) => u.label.toLowerCase().includes(q));
},
command: ({ editor, range, props }: any) => {
const mentionHTML = `<span data-type="mention" data-id="${props.id}" data-label="${props.label}">@${props.label}</span>&nbsp;`;
editor
.chain()
.focus()
.deleteRange(range)
.insertContent(mentionHTML)
.focus()
.run();
},
render: renderMentionSuggestions,
},
renderText({ options, node }) {
return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`;
},
}),
],
content,
onUpdate: ({ editor }) => onChange?.(editor.getHTML()),
@@ -374,6 +540,14 @@ export default function Editor({
.tiptap p {
margin: 0 0 1rem 0 !important;
}
.tiptap .mention {
background-color: rgba(59, 130, 246, 0.1);
border-radius: 0.25rem;
padding: 0.125rem 0.25rem;
color: rgb(59, 130, 246);
text-decoration: none;
font-weight: 500;
}
`}</style>
{!readOnly && editor && <EditorBubbleMenu editor={editor} />}
<EditorContent

View File

@@ -32,7 +32,7 @@ export function LabelForm({
refetch: () => void;
isEdit?: boolean;
}) {
const { closeModal, entityId, openModal } = useModal();
const { closeModal, entityId, openModal, setModalState } = useModal();
const label = api.label.byPublicId.useQuery(
{
@@ -57,12 +57,13 @@ export function LabelForm({
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
const createLabel = api.label.create.useMutation({
onSuccess: () => {
onSuccess: (newLabel) => {
const currentColourIndex = colours.findIndex(
(c) => c.code === watch("colour").code,
);
try {
refetch();
setModalState("NEW_LABEL_CREATED", newLabel.publicId);
if (!isCreateAnotherEnabled) {
closeModal();
} else {
@@ -220,6 +221,7 @@ export function LabelForm({
<div className="space-x-2">
{isEdit && (
<Button
type="button"
variant="secondary"
onClick={() => openModal("DELETE_LABEL", entityId)}
>

View File

@@ -24,7 +24,7 @@ export const env = createEnv({
s.split(",").every((l) => z.string().url().safeParse(l).success),
)
.optional(),
POSTGRES_URL: z.string().url(),
POSTGRES_URL: z.string().url().optional().or(z.literal("")),
TRELLO_APP_API_KEY: z.string().optional(),
TRELLO_APP_SECRET: z.string().optional(),
STRIPE_SECRET_KEY: z.string().optional(),
@@ -101,6 +101,13 @@ export const env = createEnv({
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
)
.optional(),
NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY: z
.string()
.transform((s) => (s === "" ? undefined : s))
.refine(
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
)
.optional(),
},
/**
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
@@ -119,6 +126,8 @@ export const env = createEnv({
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
NEXT_PUBLIC_USE_STANDALONE_OUTPUT:
process.env.NEXT_PUBLIC_USE_STANDALONE_OUTPUT,
NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY:
process.env.NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY,
},
skipValidation:
!!process.env.CI || process.env.npm_lifecycle_event === "lint",

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} Labels"
@@ -48,8 +48,8 @@ msgstr "Eine leistungsstarke, flexible Kanban-App, die dir hilft, Arbeit zu orga
msgid "Account deleted"
msgstr "Konto gelöscht"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Aktivität"
@@ -74,9 +74,9 @@ msgstr "Element hinzufügen..."
msgid "Add checklist"
msgstr "Checkliste hinzufügen"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen)"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen oder '@' um jemanden zu erwähnen)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -180,7 +180,7 @@ msgstr "Sind Sie sicher, dass Sie diese Checkliste löschen möchten?"
msgid "Are you sure you want to delete this comment?"
msgstr "Bist du sicher, dass du diesen Kommentar löschen möchtest?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "Sind Sie sicher, dass Sie dieses Label löschen möchten?"
@@ -289,7 +289,7 @@ msgstr "Fehlerbericht"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Abbrechen"
@@ -297,7 +297,7 @@ msgstr "Abbrechen"
msgid "Card not found"
msgstr "Karte nicht gefunden"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Kartentitel"
@@ -403,8 +403,8 @@ msgid "Control who can view and edit your boards."
msgstr "Kontrolliere, wer deine Boards ansehen und bearbeiten kann."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Weitere erstellen"
@@ -412,7 +412,7 @@ msgstr "Weitere erstellen"
msgid "Create board"
msgstr "Board erstellen"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Karte erstellen"
@@ -420,7 +420,7 @@ msgstr "Karte erstellen"
msgid "Create checklist"
msgstr "Checkliste erstellen"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Label erstellen"
@@ -437,7 +437,7 @@ msgid "Create new key"
msgstr "Neuen Schlüssel erstellen"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Neues Label erstellen"
@@ -477,8 +477,8 @@ msgstr "Dunkel"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Löschen"
@@ -594,7 +594,7 @@ msgstr "Board-URL bearbeiten"
msgid "Edit comment"
msgstr "Kommentar bearbeiten"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Label bearbeiten"
@@ -634,7 +634,7 @@ msgstr "Gib dein Passwort ein"
msgid "Error deleting account"
msgstr "Fehler beim Löschen des Kontos"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Fehler beim Löschen des Labels"
@@ -923,7 +923,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Beachten Sie, dass diese Aktion nicht rückgängig gemacht werden kann."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Labels"
@@ -999,7 +999,7 @@ msgstr "Mittlere Priorität"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1025,7 +1025,7 @@ msgid "moved the card to another list"
msgstr "hat die Karte in eine andere Liste verschoben"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Name"
@@ -1041,7 +1041,7 @@ msgstr "Neu"
msgid "New board"
msgstr "Neues Board"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "Neue Karte"
@@ -1053,7 +1053,7 @@ msgstr "Neue Checkliste"
msgid "New import"
msgstr "Neuer Import"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "Neues Label"
@@ -1193,10 +1193,10 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Bitte versuche es später noch einmal oder kontaktiere den Kundensupport."
@@ -1471,7 +1471,7 @@ msgstr "Sie werden keinen Zugriff mehr auf diesen Workspace haben."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
@@ -1528,7 +1528,7 @@ msgstr "Checklistenelement kann nicht hinzugefügt werden"
msgid "Unable to add comment"
msgstr "Kommentar konnte nicht hinzugefügt werden"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "Karte konnte nicht erstellt werden"
@@ -1647,7 +1647,7 @@ msgstr "Unbegrenzte listen"
msgid "Update"
msgstr "Aktualisieren"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Label aktualisieren"

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} labels"
@@ -60,8 +60,8 @@ msgstr "A powerful, flexible kanban app that helps you organise work, track prog
msgid "Account deleted"
msgstr "Account deleted"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Activity"
@@ -86,9 +86,13 @@ msgstr "Add an item..."
msgid "Add checklist"
msgstr "Add checklist"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Add description... (type '/' to open commands or '@' to mention)"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Add description... (type '/' to open commands)"
#~ msgid "Add description... (type '/' to open commands)"
#~ msgstr "Add description... (type '/' to open commands)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -200,7 +204,7 @@ msgstr "Are you sure you want to delete this checklist?"
msgid "Are you sure you want to delete this comment?"
msgstr "Are you sure you want to delete this comment?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "Are you sure you want to delete this label?"
@@ -325,7 +329,7 @@ msgstr "Bug Report"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Cancel"
@@ -333,7 +337,7 @@ msgstr "Cancel"
msgid "Card not found"
msgstr "Card not found"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Card title"
@@ -439,8 +443,8 @@ msgid "Control who can view and edit your boards."
msgstr "Control who can view and edit your boards."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Create another"
@@ -456,7 +460,7 @@ msgstr "Create another"
msgid "Create board"
msgstr "Create board"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Create card"
@@ -464,7 +468,7 @@ msgstr "Create card"
msgid "Create checklist"
msgstr "Create checklist"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Create label"
@@ -481,7 +485,7 @@ msgid "Create new key"
msgstr "Create new key"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Create new label"
@@ -521,8 +525,8 @@ msgstr "Dark"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Delete"
@@ -638,7 +642,7 @@ msgstr "Edit board URL"
msgid "Edit comment"
msgstr "Edit comment"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Edit label"
@@ -678,7 +682,7 @@ msgstr "Enter your password"
msgid "Error deleting account"
msgstr "Error deleting account"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Error deleting label"
@@ -972,7 +976,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Keep in mind that this action is irreversible."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Labels"
@@ -1048,7 +1052,7 @@ msgstr "Medium Priority"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1078,7 +1082,7 @@ msgid "moved the card to another list"
msgstr "moved the card to another list"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Name"
@@ -1094,7 +1098,7 @@ msgstr "New"
msgid "New board"
msgstr "New board"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "New card"
@@ -1106,7 +1110,7 @@ msgstr "New checklist"
msgid "New import"
msgstr "New import"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "New label"
@@ -1250,10 +1254,10 @@ msgstr "Please select a file to upload."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Please try again later, or contact customer support."
@@ -1536,7 +1540,7 @@ msgstr "They won't be able to access this workspace."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "This action can't be undone."
@@ -1597,7 +1601,7 @@ msgstr "Unable to add checklist item"
msgid "Unable to add comment"
msgstr "Unable to add comment"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "Unable to create card"
@@ -1720,7 +1724,7 @@ msgstr "Unlimited lists"
msgid "Update"
msgstr "Update"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Update label"

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} etiquetas"
@@ -48,8 +48,8 @@ msgstr "Una aplicación kanban potente y flexible que te ayuda a organizar el tr
msgid "Account deleted"
msgstr "Cuenta eliminada"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Actividad"
@@ -74,9 +74,9 @@ msgstr "Añadir un elemento..."
msgid "Add checklist"
msgstr "Añadir lista de verificación"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Añadir descripción... (escribe '/' para abrir comandos)"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Añadir descripción... (escribe '/' para abrir comandos o '@' para mencionar)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -180,7 +180,7 @@ msgstr "¿Estás seguro de que quieres eliminar esta lista de verificación?"
msgid "Are you sure you want to delete this comment?"
msgstr "¿Estás seguro de que quieres eliminar este comentario?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "¿Estás seguro de que quieres eliminar esta etiqueta?"
@@ -289,7 +289,7 @@ msgstr "Informe de error"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Cancelar"
@@ -297,7 +297,7 @@ msgstr "Cancelar"
msgid "Card not found"
msgstr "Tarjeta no encontrada"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Título de la tarjeta"
@@ -403,8 +403,8 @@ msgid "Control who can view and edit your boards."
msgstr "Controla quién puede ver y editar tus tableros."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Crear otro"
@@ -412,7 +412,7 @@ msgstr "Crear otro"
msgid "Create board"
msgstr "Crear tablero"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Crear tarjeta"
@@ -420,7 +420,7 @@ msgstr "Crear tarjeta"
msgid "Create checklist"
msgstr "Crear lista de verificación"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Crear etiqueta"
@@ -437,7 +437,7 @@ msgid "Create new key"
msgstr "Crear nueva clave"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Crear nueva etiqueta"
@@ -477,8 +477,8 @@ msgstr "Oscuro"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Eliminar"
@@ -594,7 +594,7 @@ msgstr "Editar URL del tablero"
msgid "Edit comment"
msgstr "Editar comentario"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Editar etiqueta"
@@ -634,7 +634,7 @@ msgstr "Introduce tu contraseña"
msgid "Error deleting account"
msgstr "Error al eliminar la cuenta"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Error al eliminar la etiqueta"
@@ -923,7 +923,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Ten en cuenta que esta acción es irreversible."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Etiquetas"
@@ -999,7 +999,7 @@ msgstr "Prioridad media"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1025,7 +1025,7 @@ msgid "moved the card to another list"
msgstr "movió la tarjeta a otra lista"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Nombre"
@@ -1041,7 +1041,7 @@ msgstr "Nuevo"
msgid "New board"
msgstr "Nuevo tablero"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "Nueva tarjeta"
@@ -1053,7 +1053,7 @@ msgstr "Nueva lista de verificación"
msgid "New import"
msgstr "Nueva importación"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "Nueva etiqueta"
@@ -1193,10 +1193,10 @@ msgstr "Por favor selecciona un archivo para subir."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Por favor, inténtalo de nuevo más tarde o contacta con atención al cliente."
@@ -1471,7 +1471,7 @@ msgstr "No podrán acceder a este espacio de trabajo."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "Esta acción no se puede deshacer."
@@ -1528,7 +1528,7 @@ msgstr "No se puede añadir el elemento a la lista de verificación"
msgid "Unable to add comment"
msgstr "No se puede añadir el comentario"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "No se puede crear la tarjeta"
@@ -1647,7 +1647,7 @@ msgstr "Listas ilimitadas"
msgid "Update"
msgstr "Actualizar"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Actualizar etiqueta"

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} étiquettes"
@@ -48,8 +48,8 @@ msgstr "Une application kanban puissante et flexible qui vous aide à organiser
msgid "Account deleted"
msgstr "Compte supprimé"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Activité"
@@ -74,9 +74,9 @@ msgstr "Ajouter un élément..."
msgid "Add checklist"
msgstr "Ajouter une checklist"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes)"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes ou '@' pour mentionner)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -180,7 +180,7 @@ msgstr "Êtes-vous sûr de vouloir supprimer cette checklist ?"
msgid "Are you sure you want to delete this comment?"
msgstr "Êtes-vous sûr de vouloir supprimer ce commentaire ?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "Êtes-vous sûr de vouloir supprimer cette étiquette ?"
@@ -289,7 +289,7 @@ msgstr "Rapport de bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Annuler"
@@ -297,7 +297,7 @@ msgstr "Annuler"
msgid "Card not found"
msgstr "Carte introuvable"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Titre de la carte"
@@ -403,8 +403,8 @@ msgid "Control who can view and edit your boards."
msgstr "Contrôlez qui peut voir et modifier vos tableaux."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Créer un autre"
@@ -412,7 +412,7 @@ msgstr "Créer un autre"
msgid "Create board"
msgstr "Créer un tableau"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Créer une carte"
@@ -420,7 +420,7 @@ msgstr "Créer une carte"
msgid "Create checklist"
msgstr "Créer une checklist"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Créer une étiquette"
@@ -437,7 +437,7 @@ msgid "Create new key"
msgstr "Créer une nouvelle clé"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Créer une nouvelle étiquette"
@@ -477,8 +477,8 @@ msgstr "Sombre"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Supprimer"
@@ -594,7 +594,7 @@ msgstr "Modifier l'URL du tableau"
msgid "Edit comment"
msgstr "Modifier le commentaire"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Modifier l'étiquette"
@@ -634,7 +634,7 @@ msgstr "Saisissez votre mot de passe"
msgid "Error deleting account"
msgstr "Erreur lors de la suppression du compte"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Erreur lors de la suppression de l'étiquette"
@@ -923,7 +923,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Gardez à l'esprit que cette action est irréversible."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Étiquettes"
@@ -999,7 +999,7 @@ msgstr "Priorité moyenne"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1025,7 +1025,7 @@ msgid "moved the card to another list"
msgstr "a déplacé la carte vers une autre liste"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Nom"
@@ -1041,7 +1041,7 @@ msgstr "Nouveau"
msgid "New board"
msgstr "Nouveau tableau"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "Nouvelle carte"
@@ -1053,7 +1053,7 @@ msgstr "Nouvelle checklist"
msgid "New import"
msgstr "Nouvel import"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "Nouvelle étiquette"
@@ -1193,10 +1193,10 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Veuillez réessayer plus tard ou contacter le service client."
@@ -1471,7 +1471,7 @@ msgstr "Ils ne pourront plus accéder à cet espace de travail."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "Cette action ne peut pas être annulée."
@@ -1528,7 +1528,7 @@ msgstr "Impossible d'ajouter l'élément à la liste de contrôle"
msgid "Unable to add comment"
msgstr "Impossible d'ajouter un commentaire"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "Impossible de créer la carte"
@@ -1647,7 +1647,7 @@ msgstr "Listes illimitées"
msgid "Update"
msgstr "Mettre à jour"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Mettre à jour l'étiquette"

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} etichette"
@@ -48,8 +48,8 @@ msgstr "Un'app kanban potente e flessibile che ti aiuta a organizzare il lavoro,
msgid "Account deleted"
msgstr "Account eliminato"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Attività"
@@ -74,9 +74,9 @@ msgstr "Aggiungi un elemento..."
msgid "Add checklist"
msgstr "Aggiungi checklist"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi)"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi o '@' per menzionare)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -180,7 +180,7 @@ msgstr "Sei sicuro di voler eliminare questa checklist?"
msgid "Are you sure you want to delete this comment?"
msgstr "Sei sicuro di voler eliminare questo commento?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "Sei sicuro di voler eliminare questa etichetta?"
@@ -289,7 +289,7 @@ msgstr "Segnalazione bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Annulla"
@@ -297,7 +297,7 @@ msgstr "Annulla"
msgid "Card not found"
msgstr "Carta non trovata"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Titolo della carta"
@@ -403,8 +403,8 @@ msgid "Control who can view and edit your boards."
msgstr "Controlla chi può visualizzare e modificare le tue bacheche."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Crea un altro"
@@ -412,7 +412,7 @@ msgstr "Crea un altro"
msgid "Create board"
msgstr "Crea bacheca"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Crea carta"
@@ -420,7 +420,7 @@ msgstr "Crea carta"
msgid "Create checklist"
msgstr "Crea checklist"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Crea etichetta"
@@ -437,7 +437,7 @@ msgid "Create new key"
msgstr "Crea nuova chiave"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Crea nuova etichetta"
@@ -477,8 +477,8 @@ msgstr "Scuro"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Elimina"
@@ -594,7 +594,7 @@ msgstr "Modifica URL della bacheca"
msgid "Edit comment"
msgstr "Modifica commento"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Modifica etichetta"
@@ -634,7 +634,7 @@ msgstr "Inserisci la tua password"
msgid "Error deleting account"
msgstr "Errore durante l'eliminazione dell'account"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Errore durante l'eliminazione dell'etichetta"
@@ -923,7 +923,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Tieni presente che questa azione è irreversibile."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Etichette"
@@ -999,7 +999,7 @@ msgstr "Media priorità"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1025,7 +1025,7 @@ msgid "moved the card to another list"
msgstr "ha spostato la scheda in un'altra lista"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Nome"
@@ -1041,7 +1041,7 @@ msgstr "Nuovo"
msgid "New board"
msgstr "Nuova bacheca"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "Nuova carta"
@@ -1053,7 +1053,7 @@ msgstr "Nuova checklist"
msgid "New import"
msgstr "Nuova importazione"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "Nuova etichetta"
@@ -1193,10 +1193,10 @@ msgstr "Seleziona un file da caricare."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Riprova più tardi o contatta l'assistenza clienti."
@@ -1471,7 +1471,7 @@ msgstr "Non potranno accedere a questo spazio di lavoro."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "Questa azione non può essere annullata."
@@ -1528,7 +1528,7 @@ msgstr "Impossibile aggiungere l'elemento della checklist"
msgid "Unable to add comment"
msgstr "Impossibile aggiungere il commento"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "Impossibile creare la scheda"
@@ -1647,7 +1647,7 @@ msgstr "Liste illimitate"
msgid "Update"
msgstr "Aggiorna"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Aggiorna etichetta"

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ msgid "{0} | {1}"
msgstr "{0} | {1}"
#. placeholder {0}: labelPublicIds.length
#: src/views/board/components/NewCardForm.tsx:392
#: src/views/board/components/NewCardForm.tsx:432
msgid "{0} labels"
msgstr "{0} labels"
@@ -48,8 +48,8 @@ msgstr "Een krachtige, flexibele kanban-app die je helpt werk te organiseren, vo
msgid "Account deleted"
msgstr "Account verwijderd"
#: src/views/public/board/CardModal.tsx:136
#: src/views/card/index.tsx:287
#: src/views/public/board/CardModal.tsx:140
#: src/views/card/index.tsx:288
msgid "Activity"
msgstr "Activiteit"
@@ -74,9 +74,9 @@ msgstr "Voeg een item toe..."
msgid "Add checklist"
msgstr "Checklist toevoegen"
#: src/components/Editor.tsx:308
msgid "Add description... (type '/' to open commands)"
msgstr "Voeg beschrijving toe... (typ '/' om commando's te openen)"
#: src/components/Editor.tsx:442
msgid "Add description... (type '/' to open commands or '@' to mention)"
msgstr "Beschrijving toevoegen... (typ '/' om commando's te openen of '@' om te vermelden)"
#: src/views/card/components/ChecklistItemRow.tsx:172
msgid "Add details..."
@@ -180,7 +180,7 @@ msgstr "Weet je zeker dat je deze checklist wilt verwijderen?"
msgid "Are you sure you want to delete this comment?"
msgstr "Weet je zeker dat je deze opmerking wilt verwijderen?"
#: src/components/DeleteLabelConfirmation.tsx:39
#: src/components/DeleteLabelConfirmation.tsx:41
msgid "Are you sure you want to delete this label?"
msgstr "Weet je zeker dat je dit label wilt verwijderen?"
@@ -289,7 +289,7 @@ msgstr "Bugrapport"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCardConfirmation.tsx:86
#: src/views/card/components/Comment.tsx:158
#: src/components/DeleteLabelConfirmation.tsx:47
#: src/components/DeleteLabelConfirmation.tsx:49
msgid "Cancel"
msgstr "Annuleren"
@@ -297,7 +297,7 @@ msgstr "Annuleren"
msgid "Card not found"
msgstr "Kaart niet gevonden"
#: src/views/board/components/NewCardForm.tsx:278
#: src/views/board/components/NewCardForm.tsx:307
msgid "Card title"
msgstr "Kaarttitel"
@@ -403,8 +403,8 @@ msgid "Control who can view and edit your boards."
msgstr "Bepaal wie je borden kan bekijken en bewerken."
#: src/views/board/components/NewListForm.tsx:140
#: src/views/board/components/NewCardForm.tsx:418
#: src/components/LabelForm.tsx:212
#: src/views/board/components/NewCardForm.tsx:458
#: src/components/LabelForm.tsx:213
msgid "Create another"
msgstr "Maak nog een"
@@ -412,7 +412,7 @@ msgstr "Maak nog een"
msgid "Create board"
msgstr "Maak bord"
#: src/views/board/components/NewCardForm.tsx:428
#: src/views/board/components/NewCardForm.tsx:468
msgid "Create card"
msgstr "Maak kaart"
@@ -420,7 +420,7 @@ msgstr "Maak kaart"
msgid "Create checklist"
msgstr "Checklist maken"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Create label"
msgstr "Maak label"
@@ -437,7 +437,7 @@ msgid "Create new key"
msgstr "Nieuwe sleutel aanmaken"
#: src/views/card/components/LabelSelector.tsx:98
#: src/views/board/components/NewCardForm.tsx:354
#: src/views/board/components/NewCardForm.tsx:394
msgid "Create new label"
msgstr "Maak nieuw label"
@@ -477,8 +477,8 @@ msgstr "Donker"
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
#: src/views/card/components/DeleteCardConfirmation.tsx:92
#: src/components/LabelForm.tsx:226
#: src/components/DeleteLabelConfirmation.tsx:49
#: src/components/LabelForm.tsx:228
#: src/components/DeleteLabelConfirmation.tsx:51
msgid "Delete"
msgstr "Verwijderen"
@@ -594,7 +594,7 @@ msgstr "Board URL bewerken"
msgid "Edit comment"
msgstr "Reactie bewerken"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "Edit label"
msgstr "Label bewerken"
@@ -634,7 +634,7 @@ msgstr "Voer je wachtwoord in"
msgid "Error deleting account"
msgstr "Fout bij verwijderen account"
#: src/components/DeleteLabelConfirmation.tsx:22
#: src/components/DeleteLabelConfirmation.tsx:25
msgid "Error deleting label"
msgstr "Fout bij het verwijderen van label"
@@ -923,7 +923,7 @@ msgid "Keep in mind that this action is irreversible."
msgstr "Houd er rekening mee dat deze actie onomkeerbaar is."
#: src/views/card/index.tsx:118
#: src/views/board/components/NewCardForm.tsx:358
#: src/views/board/components/NewCardForm.tsx:398
#: src/views/board/components/Filters.tsx:101
msgid "Labels"
msgstr "Labels"
@@ -999,7 +999,7 @@ msgstr "Gemiddelde prioriteit"
#: src/views/members/index.tsx:161
#: src/views/card/index.tsx:126
#: src/views/board/components/NewCardForm.tsx:317
#: src/views/board/components/NewCardForm.tsx:357
#: src/views/board/components/Filters.tsx:93
#: src/components/SideNavigation.tsx:73
msgid "Members"
@@ -1025,7 +1025,7 @@ msgid "moved the card to another list"
msgstr "heeft de kaart naar een andere lijst verplaatst"
#: src/views/boards/components/NewBoardForm.tsx:99
#: src/components/LabelForm.tsx:134
#: src/components/LabelForm.tsx:135
msgid "Name"
msgstr "Naam"
@@ -1041,7 +1041,7 @@ msgstr "Nieuw"
msgid "New board"
msgstr "Nieuw bord"
#: src/views/board/components/NewCardForm.tsx:261
#: src/views/board/components/NewCardForm.tsx:290
msgid "New card"
msgstr "Nieuwe kaart"
@@ -1053,7 +1053,7 @@ msgstr "Nieuwe checklist"
msgid "New import"
msgstr "Nieuwe import"
#: src/components/LabelForm.tsx:118
#: src/components/LabelForm.tsx:119
msgid "New label"
msgstr "Nieuw label"
@@ -1193,10 +1193,10 @@ msgstr "Selecteer een bestand om te uploaden."
#: src/views/board/components/VisibilityButton.tsx:53
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
#: src/views/board/components/NewListForm.tsx:78
#: src/views/board/components/NewCardForm.tsx:145
#: src/views/board/components/NewCardForm.tsx:174
#: src/components/NewWorkspaceForm.tsx:41
#: src/components/FeedbackModal.tsx:41
#: src/components/DeleteLabelConfirmation.tsx:23
#: src/components/DeleteLabelConfirmation.tsx:26
msgid "Please try again later, or contact customer support."
msgstr "Probeer het later opnieuw of neem contact op met de klantenservice."
@@ -1471,7 +1471,7 @@ msgstr "Ze zullen geen toegang meer hebben tot deze werkruimte."
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
#: src/views/card/components/DeleteCardConfirmation.tsx:78
#: src/components/DeleteLabelConfirmation.tsx:42
#: src/components/DeleteLabelConfirmation.tsx:44
msgid "This action can't be undone."
msgstr "Deze actie kan niet ongedaan worden gemaakt."
@@ -1528,7 +1528,7 @@ msgstr "Kan checklistitem niet toevoegen"
msgid "Unable to add comment"
msgstr "Kan geen reactie toevoegen"
#: src/views/board/components/NewCardForm.tsx:142
#: src/views/board/components/NewCardForm.tsx:171
msgid "Unable to create card"
msgstr "Kan kaart niet aanmaken"
@@ -1647,7 +1647,7 @@ msgstr "Onbeperkt aantal lijsten"
msgid "Update"
msgstr "Bijwerken"
#: src/components/LabelForm.tsx:236
#: src/components/LabelForm.tsx:238
msgid "Update label"
msgstr "Label bijwerken"

File diff suppressed because one or more lines are too long

View File

@@ -18,6 +18,8 @@ interface ModalContextType {
entityLabel?: string,
) => void;
closeModal: () => void;
closeModals: (count: number) => void;
clearAllModals: () => void;
modalContentType: string;
entityId: string;
entityLabel: string;
@@ -58,6 +60,17 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
});
};
const closeModals = (count: number) => {
setModalStack(prev => {
const newLength = Math.max(0, prev.length - count);
return prev.slice(0, newLength);
});
};
const clearAllModals = () => {
setModalStack([]);
};
const setModalState = (modalType: string, state: any) => {
setModalStates((prev) => ({
...prev,
@@ -87,6 +100,8 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
isOpen,
openModal,
closeModal,
closeModals,
clearAllModals,
modalContentType,
entityId,
entityLabel,

View File

@@ -14,7 +14,7 @@ import { generateUID } from "@kan/shared/utils";
import Avatar from "~/components/Avatar";
import Button from "~/components/Button";
import CheckboxDropdown from "~/components/CheckboxDropdown";
import Editor from "~/components/Editor";
import Editor, { WorkspaceMember } from "~/components/Editor";
import Input from "~/components/Input";
import LabelIcon from "~/components/LabelIcon";
import Toggle from "~/components/Toggle";
@@ -46,7 +46,7 @@ export function NewCardForm({
queryParams,
}: NewCardFormProps) {
const { showPopup } = usePopup();
const { closeModal, openModal } = useModal();
const { closeModal, openModal, modalStates, clearModalState } = useModal();
const utils = api.useUtils();
@@ -85,10 +85,39 @@ export function NewCardForm({
return () => subscription.unsubscribe();
}, [watch, saveFormState]);
const { data: boardData } = api.board.byId.useQuery(queryParams, {
enabled: !!boardPublicId,
});
// this adds the new created label to selected labels
useEffect(() => {
const newLabelId = modalStates["NEW_LABEL_CREATED"];
if (newLabelId !== undefined && !labelPublicIds.includes(newLabelId)) {
setValue("labelPublicIds", [...labelPublicIds, newLabelId]);
}
}, [modalStates, labelPublicIds]);
// this removes the deleted label from selected labels if it is selected
useEffect(() => {
if (boardData?.labels) {
const availableLabelIds = boardData.labels.map(label => label.publicId);
const newLabelId = modalStates["NEW_LABEL_CREATED"];
if (newLabelId && availableLabelIds.includes(newLabelId)) {
clearModalState("NEW_LABEL_CREATED");
}
const validLabelIds = labelPublicIds.filter(id =>
availableLabelIds.includes(id) || id === newLabelId
);
if (validLabelIds.length !== labelPublicIds.length) {
setValue("labelPublicIds", validLabelIds);
}
}
}, [boardData?.labels, labelPublicIds, modalStates["NEW_LABEL_CREATED"]]);
const createCard = api.card.create.useMutation({
onMutate: async (args) => {
await utils.board.byId.cancel();
@@ -293,6 +322,17 @@ export function NewCardForm({
setValue("description", value);
saveFormState({ ...formState, description: value });
}}
workspaceMembers={
boardData?.workspace.members?.map((member): WorkspaceMember => ({
publicId: member.publicId,
email: member.email,
user: member.user ? {
id: member.publicId,
name: member.user.name,
image: member.user.image ?? null,
} : null,
})) ?? []
}
/>
</div>
</div>

View File

@@ -29,7 +29,6 @@ import LabelSelector from "./components/LabelSelector";
import ListSelector from "./components/ListSelector";
import MemberSelector from "./components/MemberSelector";
import { NewChecklistForm } from "./components/NewChecklistForm";
import NewChecklistItemForm from "./components/NewChecklistItemForm";
import NewCommentForm from "./components/NewCommentForm";
interface FormValues {
@@ -213,93 +212,96 @@ export default function CardPage() {
<PageHead
title={t`${card?.title ?? "Card"} | ${board?.name ?? "Board"}`}
/>
<div className="flex h-full flex-1 flex-row">
<div className="m-auto flex h-full w-full max-w-[800px] flex-col overflow-hidden">
<div className="h-full max-h-[calc(100dvh-3rem)] overflow-y-auto p-6 md:max-h-[calc(100dvh-4rem)] md:p-8">
<div className="mb-8 flex w-full items-center justify-between md:mt-6">
{!card && isLoading && (
<div className="flex space-x-2">
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
<div className="h-[2.3rem] w-[300px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
</div>
)}
<div className="flex h-full flex-1 flex-row overflow-hidden">
<div className="scrollbar-thumb-rounded-[4px] scrollbar-track-rounded-[4px] w-full flex-1 overflow-y-auto scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 hover:scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300 dark:hover:scrollbar-thumb-dark-300">
<div className="p-auto mx-auto flex h-full w-full max-w-[800px] flex-col">
<div className="p-6 md:p-8">
<div className="mb-8 flex w-full items-center justify-between md:mt-6">
{!card && isLoading && (
<div className="flex space-x-2">
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
<div className="h-[2.3rem] w-[300px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
</div>
)}
{card && (
<>
<Link
className="whitespace-nowrap font-bold leading-[2.3rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1.2rem]"
href={`/boards/${board?.publicId}`}
>
{board?.name}
</Link>
<IoChevronForwardSharp
size={18}
className="mx-2 text-light-900 dark:text-dark-900"
/>
<form
onSubmit={handleSubmit(onSubmit)}
className="w-full space-y-6"
>
<div>
<input
type="text"
id="title"
{...register("title")}
onBlur={handleSubmit(onSubmit)}
className="block w-full border-0 bg-transparent p-0 py-0 font-bold tracking-tight text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
/>
</div>
</form>
<div className="flex">
<Dropdown />
</div>
</>
)}
{!card && !isLoading && (
<p className="block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
{t`Card not found`}
</p>
)}
</div>
{card && (
<>
<Link
className="whitespace-nowrap font-bold leading-[2.3rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1.2rem]"
href={`/boards/${board?.publicId}`}
>
{board?.name}
</Link>
<IoChevronForwardSharp
size={18}
className="mx-2 text-light-900 dark:text-dark-900"
<div className="mb-10 flex w-full max-w-2xl flex-col justify-between">
<form
onSubmit={handleSubmit(onSubmit)}
className="w-full space-y-6"
>
<div className="mt-2">
<Editor
content={card.description}
onChange={(e) => setValue("description", e)}
onBlur={() => handleSubmit(onSubmit)()}
workspaceMembers={board?.workspace.members ?? []}
/>
</div>
</form>
</div>
<Checklists
checklists={card.checklists}
cardPublicId={cardId}
activeChecklistForm={activeChecklistForm}
setActiveChecklistForm={setActiveChecklistForm}
/>
<form
onSubmit={handleSubmit(onSubmit)}
className="w-full space-y-6"
>
<div className="border-t-[1px] border-light-300 pt-12 dark:border-dark-300">
<h2 className="text-md pb-4 font-medium text-light-1000 dark:text-dark-1000">
{t`Activity`}
</h2>
<div>
<input
type="text"
id="title"
{...register("title")}
onBlur={handleSubmit(onSubmit)}
className="block w-full border-0 bg-transparent p-0 py-0 font-bold tracking-tight text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
<ActivityList
cardPublicId={cardId}
activities={activities ?? []}
isLoading={!card}
isAdmin={workspace.role === "admin"}
/>
</div>
</form>
<div className="flex">
<Dropdown />
<div className="mt-6">
<NewCommentForm cardPublicId={cardId} />
</div>
</div>
</>
)}
{!card && !isLoading && (
<p className="block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
{t`Card not found`}
</p>
)}
</div>
{card && (
<>
<div className="mb-10 flex w-full max-w-2xl flex-col justify-between">
<form
onSubmit={handleSubmit(onSubmit)}
className="w-full space-y-6"
>
<div className="mt-2">
<Editor
content={card.description}
onChange={(e) => setValue("description", e)}
onBlur={() => handleSubmit(onSubmit)()}
/>
</div>
</form>
</div>
<Checklists
checklists={card.checklists}
cardPublicId={cardId}
activeChecklistForm={activeChecklistForm}
setActiveChecklistForm={setActiveChecklistForm}
/>
<div className="border-t-[1px] border-light-300 pt-12 dark:border-dark-300">
<h2 className="text-md pb-4 font-medium text-light-1000 dark:text-dark-1000">
{t`Activity`}
</h2>
<div>
<ActivityList
cardPublicId={cardId}
activities={activities ?? []}
isLoading={!card}
isAdmin={workspace.role === "admin"}
/>
</div>
<div className="mt-6">
<NewCommentForm cardPublicId={cardId} />
</div>
</div>
</>
)}
</div>
</div>

View File

@@ -120,7 +120,11 @@ export function CardModal({
{data?.description && (
<div className="mb-10 flex w-full max-w-2xl justify-between">
<div className="mt-2">
<Editor content={data.description} readOnly />
<Editor
content={data.description}
readOnly
workspaceMembers={data?.list.board.workspace.members ?? []}
/>
</div>
</div>
)}

View File

@@ -2,6 +2,7 @@ import Link from "next/link";
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import { keepPreviousData } from "@tanstack/react-query";
import { env } from "next-runtime-env";
import { useEffect, useState } from "react";
import { HiLink, HiOutlineLockClosed } from "react-icons/hi2";
@@ -19,6 +20,10 @@ import Card from "~/views/board/components/Card";
import Filters from "~/views/board/components/Filters";
import { CardModal } from "./CardModal";
const IS_CLOUD = env("NEXT_PUBLIC_KAN_ENV") === "cloud";
const HIDE_POWERED_BY =
env("NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY") === "true";
export default function PublicBoardView() {
const router = useRouter();
const { showPopup } = usePopup();
@@ -194,12 +199,26 @@ export default function PublicBoardView() {
<CopyBoardLink />
</div>
<Link
className="text-lg font-bold tracking-tight text-neutral-900 dark:text-dark-1000"
href="/"
>
kan.bn
</Link>
{IS_CLOUD && (
<Link
className="text-lg font-bold tracking-tight text-neutral-900 dark:text-dark-1000"
href="/"
>
kan.bn
</Link>
)}
{!IS_CLOUD && !HIDE_POWERED_BY && (
<a
href="https://kan.bn"
target="_blank"
rel="noreferrer noopener"
className="absolute right-[1rem] inline-flex items-center gap-[0.175rem] rounded-full border border-light-300 bg-light-50 px-3 py-1 text-[11px] font-medium text-light-950 shadow-sm transition-colors hover:bg-light-100 dark:border-dark-300 dark:bg-dark-50 dark:text-dark-900 dark:hover:bg-dark-100"
>
<span>{`Powered by`}</span>
<span className="font-semibold">kan.bn</span>
</a>
)}
</div>
</div>
<Popup />

View File

@@ -35,6 +35,9 @@ services:
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
# White label
- NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY=${NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY}
# Auth config (optional)
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}

View File

@@ -1,4 +1,4 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";--> statement-breakpoint
CREATE TYPE "public"."board_visibility" AS ENUM('private', 'public');--> statement-breakpoint
CREATE TYPE "public"."card_activity_type" AS ENUM('card.created', 'card.updated.title', 'card.updated.description', 'card.updated.index', 'card.updated.list', 'card.updated.label.added', 'card.updated.label.removed', 'card.updated.member.added', 'card.updated.member.removed', 'card.updated.comment.added', 'card.updated.comment.updated', 'card.updated.comment.deleted', 'card.archived');--> statement-breakpoint

View File

@@ -39,6 +39,7 @@
"with-env": "dotenv -e ../../.env --"
},
"dependencies": {
"@electric-sql/pglite": "^0.3.7",
"@kan/shared": "workspace:^",
"drizzle-orm": "^0.42.0",
"drizzle-zod": "^0.5.1",

View File

@@ -1,8 +1,12 @@
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import { drizzle as drizzlePgLite } from "drizzle-orm/pglite";
import { uuid_ossp } from "@electric-sql/pglite/contrib/uuid_ossp";
import { drizzle as drizzlePg } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";
import { PGlite } from "@electric-sql/pglite";
import { migrate } from "drizzle-orm/pglite/migrator";
export type dbClient = NodePgDatabase<typeof schema> & {
$client: Pool;
@@ -12,7 +16,14 @@ export const createDrizzleClient = (): dbClient => {
const connectionString = process.env.POSTGRES_URL;
if (!connectionString) {
throw new Error("POSTGRES_URL environment variable is not set");
console.log("POSTGRES_URL environment variable is not set, using PGLite");
const client = new PGlite({ dataDir: "./pgdata", extensions: { uuid_ossp }});
const db = drizzlePgLite(client, { schema });
migrate(db, { migrationsFolder: "../../packages/db/migrations" });
return db as unknown as dbClient;
}
const pool = new Pool({

36
pnpm-lock.yaml generated
View File

@@ -123,6 +123,9 @@ importers:
'@tiptap/extension-link':
specifier: ^2.22.2
version: 2.22.2(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
'@tiptap/extension-mention':
specifier: ^3.0.9
version: 3.0.9(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)(@tiptap/suggestion@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0))
'@tiptap/extension-placeholder':
specifier: ^2.14.0
version: 2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
@@ -360,15 +363,18 @@ importers:
packages/db:
dependencies:
'@electric-sql/pglite':
specifier: ^0.3.7
version: 0.3.7
'@kan/shared':
specifier: workspace:^
version: link:../shared
drizzle-orm:
specifier: ^0.42.0
version: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
version: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
drizzle-zod:
specifier: ^0.5.1
version: 0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0)
version: 0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0)
pg:
specifier: ^8.11.3
version: 8.13.1
@@ -888,6 +894,9 @@ packages:
'@drizzle-team/brocli@0.10.2':
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
'@electric-sql/pglite@0.3.7':
resolution: {integrity: sha512-5c3mybVrhxu5s47zFZtIGdG8YHkKCBENOmqxnNBjY53ZoDhADY/c5UqBDl159b7qtkzNPtbbb893wL9zi1kAuw==}
'@emnapi/runtime@1.3.1':
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
@@ -2770,6 +2779,13 @@ packages:
peerDependencies:
'@tiptap/core': ^2.7.0
'@tiptap/extension-mention@3.0.9':
resolution: {integrity: sha512-DTQNAQkHZ+7Enlt3KvjqN6eECINlqPpET4Drzwj8Mmz9kMILc87cz3G2cwEKRrS9A1Xn3H3VpWvElWE2Wq9JHw==}
peerDependencies:
'@tiptap/core': ^3.0.9
'@tiptap/pm': ^3.0.9
'@tiptap/suggestion': ^3.0.9
'@tiptap/extension-ordered-list@2.14.0':
resolution: {integrity: sha512-QUZcyuW9AKvSfpFHcGmbyRCqxcpY0VNf0xipEtogxbA+JDDw3ZSPqU1dUgz9wk00RahPTwNDdY5aVjdQ5N4N9Q==}
peerDependencies:
@@ -6484,6 +6500,7 @@ packages:
source-map@0.8.0-beta.0:
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
engines: {node: '>= 8'}
deprecated: The work that was done in this beta branch won't be included in future versions
space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
@@ -7852,6 +7869,8 @@ snapshots:
'@drizzle-team/brocli@0.10.2': {}
'@electric-sql/pglite@0.3.7': {}
'@emnapi/runtime@1.3.1':
dependencies:
tslib: 2.8.1
@@ -9612,6 +9631,12 @@ snapshots:
dependencies:
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
'@tiptap/extension-mention@3.0.9(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)(@tiptap/suggestion@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0))':
dependencies:
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
'@tiptap/pm': 2.14.0
'@tiptap/suggestion': 2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
'@tiptap/extension-ordered-list@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))':
dependencies:
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
@@ -10845,8 +10870,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5):
drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5):
optionalDependencies:
'@electric-sql/pglite': 0.3.7
'@neondatabase/serverless': 0.10.4
'@types/pg': 8.11.6
'@vercel/postgres': 0.10.0(utf-8-validate@6.0.3)
@@ -10854,9 +10880,9 @@ snapshots:
pg: 8.13.1
postgres: 3.4.5
drizzle-zod@0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0):
drizzle-zod@0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0):
dependencies:
drizzle-orm: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
drizzle-orm: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
zod: 3.24.0
dunder-proto@1.0.0:

View File

@@ -93,6 +93,7 @@
"SMTP_PASSWORD",
"SMTP_SECURE",
"NEXT_PUBLIC_KAN_ENV",
"NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY",
"STRIPE_SECRET_KEY",
"STRIPE_WEBHOOK_SECRET",
"STRIPE_PRO_PLAN_PRICE_ID",