diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..34682730c1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "daily-apps", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "daily-apps", + "dependencies": { + "postcss-rem-to-responsive-pixel": "^6.0.2" + } + }, + "node_modules/postcss-rem-to-responsive-pixel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-rem-to-responsive-pixel/-/postcss-rem-to-responsive-pixel-6.1.0.tgz", + "integrity": "sha512-rttz/ThJWKpmhS134NcQCZQBE4CUJIAJAMx9DB0YudIeTH4fNp/hhhjxo14RnGF/OGdBpX9PQw1bnPZ56H0E1Q==", + "license": "MIT", + "engines": { + "node": ">=16.6.0" + } + } + } +} diff --git a/packages/shared/src/components/post/freeform/write/WriteFreeformContent.tsx b/packages/shared/src/components/post/freeform/write/WriteFreeformContent.tsx index f2f0573ba8..fd1243d3ca 100644 --- a/packages/shared/src/components/post/freeform/write/WriteFreeformContent.tsx +++ b/packages/shared/src/components/post/freeform/write/WriteFreeformContent.tsx @@ -19,6 +19,7 @@ import type { MergedWriteObject, WriteForm } from '../../../../contexts'; import { useWritePostContext } from '../../../../contexts'; import { defaultMarkdownCommands } from '../../../../hooks/input'; import { WriteFooter } from '../../write'; +import { MAX_POST_TITLE_LENGTH } from '../../../../constants/post'; export const generateWritePostKey = (reference = 'create'): string => `write:post:${reference}`; @@ -34,7 +35,6 @@ export const checkSavedProperty = ( const defaultFilename = 'thumbnail.png'; // Shared constants - remember to update them in daily-api -const MAX_TITLE_LENGTH = 250; const MAX_CONTENT_LENGTH = 10_000; interface WriteFreeformContentProps { @@ -154,7 +154,7 @@ export function WriteFreeformContent({ required defaultValue={draft?.title ?? fetchedPost?.title} onInput={onFormUpdate} - maxLength={MAX_TITLE_LENGTH} + maxLength={MAX_POST_TITLE_LENGTH} /> push(squad?.permalink), }); + // Character limit state + const commentaryLength = commentary?.length ?? 0; + const isCommentaryTooLong = commentaryLength > MAX_POST_COMMENTARY_LENGTH; + const onUpdateSubmit: FormEventHandler = async (e) => { if (!fetchedPost?.id || !squad) { return null; @@ -169,9 +175,16 @@ export function ShareLink({ enabledCommand={{ mention: true }} showMarkdownGuide={false} onValueUpdate={setCommentary} + maxInputLength={MAX_POST_COMMENTARY_LENGTH} /> + {isCommentaryTooLong && ( +

+ Maximum length is {MAX_POST_COMMENTARY_LENGTH} characters +

+ )} ); diff --git a/packages/shared/src/components/post/write/WriteFooter.tsx b/packages/shared/src/components/post/write/WriteFooter.tsx index 0ace97b77e..6d8043420d 100644 --- a/packages/shared/src/components/post/write/WriteFooter.tsx +++ b/packages/shared/src/components/post/write/WriteFooter.tsx @@ -11,12 +11,14 @@ interface WriteFooterProps { isLoading?: boolean; className?: string; isPoll?: boolean; + disabled?: boolean; } export function WriteFooter({ isLoading, className, isPoll, + disabled, }: WriteFooterProps): ReactElement { const { sidebarRendered } = useSidebarRendered(); const { shouldShowCta, isEnabled, onToggle, onSubmitted } = @@ -54,7 +56,7 @@ export function WriteFooter({ 'ml-auto hidden w-full tablet:mt-0 tablet:w-32 laptop:flex', shouldShowCta && 'mt-6', )} - disabled={isLoading} + disabled={isLoading || disabled} loading={isLoading} onClick={onSubmitted} > diff --git a/packages/shared/src/constants/README.md b/packages/shared/src/constants/README.md new file mode 100644 index 0000000000..8a7e80362e --- /dev/null +++ b/packages/shared/src/constants/README.md @@ -0,0 +1,38 @@ +# Post Constants + +Single source of truth for post-related character limits. + +## Constants + +### `MAX_POST_TITLE_LENGTH = 250` + +Maximum characters for post titles. + +**Used in:** `WriteFreeformContent.tsx` (title field) + +```typescript +import { MAX_POST_TITLE_LENGTH } from '../../../../constants/post'; + + +``` + +### `MAX_POST_COMMENTARY_LENGTH = 250` + +Maximum characters for link commentary/descriptions. + +**Used in:** `ShareLink.tsx` (commentary field + validation) + +```typescript +import { MAX_POST_COMMENTARY_LENGTH } from '../../../constants/post'; + +// Validation +if (commentary.length > MAX_POST_COMMENTARY_LENGTH) return null; + +// Component + +``` + +## Notes + +- **Backend sync required:** Keep these in sync with `daily-api` validation +- **Naming pattern:** `MAX_POST_[FIELD]_LENGTH` diff --git a/packages/shared/src/constants/post.ts b/packages/shared/src/constants/post.ts new file mode 100644 index 0000000000..494543ebe2 --- /dev/null +++ b/packages/shared/src/constants/post.ts @@ -0,0 +1,2 @@ +export const MAX_POST_TITLE_LENGTH = 250; +export const MAX_POST_COMMENTARY_LENGTH = 250;