diff --git a/frontend/src/Components/MiddleTruncate.tsx b/frontend/src/Components/MiddleTruncate.tsx new file mode 100644 index 0000000000..f635b0bc9c --- /dev/null +++ b/frontend/src/Components/MiddleTruncate.tsx @@ -0,0 +1,63 @@ +import React, { useEffect, useRef, useState } from 'react'; +import useMeasure from 'Helpers/Hooks/useMeasure'; + +interface MiddleTruncateProps { + text: string; +} + +function getTruncatedText(text: string, length: number) { + return `${text.slice(0, length)}...${text.slice(text.length - length)}`; +} + +function MiddleTruncate({ text }: MiddleTruncateProps) { + const [containerRef, { width: containerWidth }] = useMeasure(); + const [textRef, { width: textWidth }] = useMeasure(); + const [truncatedText, setTruncatedText] = useState(text); + const truncatedTextRef = useRef(text); + + useEffect(() => { + setTruncatedText(text); + }, [text]); + + useEffect(() => { + if (!containerWidth || !textWidth) { + return; + } + + if (textWidth <= containerWidth) { + return; + } + + const characterLength = textWidth / text.length; + const charactersToRemove = + Math.ceil(text.length - containerWidth / characterLength) + 3; + let length = Math.ceil(text.length / 2 - charactersToRemove / 2); + + let updatedText = getTruncatedText(text, length); + + // Make sure if the text is still too long, we keep reducing the length + // each time we re-run this. + while ( + updatedText.length >= truncatedTextRef.current.length && + length > 10 + ) { + length--; + updatedText = getTruncatedText(text, length); + } + + // Store the value in the ref so we can compare it in the next render, + // without triggering this effect every time we change the text. + truncatedTextRef.current = updatedText; + setTruncatedText(updatedText); + }, [text, truncatedTextRef, containerWidth, textWidth]); + + return ( +
+
+ {truncatedText} +
+
+ ); +} + +export default MiddleTruncate; diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css similarity index 100% rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css.d.ts b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css.d.ts similarity index 100% rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.css.d.ts rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.css.d.ts diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx similarity index 91% rename from frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx rename to frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx index c2ad9f4b8f..58a7bd13fa 100644 --- a/frontend/src/Settings/Profiles/Release/ReleaseProfileRow.tsx +++ b/frontend/src/Settings/Profiles/Release/ReleaseProfileItem.tsx @@ -3,6 +3,7 @@ import { useDispatch } from 'react-redux'; import { Tag } from 'App/State/TagsAppState'; import Card from 'Components/Card'; import Label from 'Components/Label'; +import MiddleTruncate from 'Components/MiddleTruncate'; import ConfirmModal from 'Components/Modal/ConfirmModal'; import TagList from 'Components/TagList'; import useModalOpenState from 'Helpers/Hooks/useModalOpenState'; @@ -12,14 +13,14 @@ import Indexer from 'typings/Indexer'; import ReleaseProfile from 'typings/Settings/ReleaseProfile'; import translate from 'Utilities/String/translate'; import EditReleaseProfileModal from './EditReleaseProfileModal'; -import styles from './ReleaseProfileRow.css'; +import styles from './ReleaseProfileItem.css'; interface ReleaseProfileProps extends ReleaseProfile { tagList: Tag[]; indexerList: Indexer[]; } -function ReleaseProfileRow(props: ReleaseProfileProps) { +function ReleaseProfileItem(props: ReleaseProfileProps) { const { id, name, @@ -69,7 +70,7 @@ function ReleaseProfileRow(props: ReleaseProfileProps) { return ( ); })} @@ -83,7 +84,7 @@ function ReleaseProfileRow(props: ReleaseProfileProps) { return ( ); })} @@ -127,4 +128,4 @@ function ReleaseProfileRow(props: ReleaseProfileProps) { ); } -export default ReleaseProfileRow; +export default ReleaseProfileItem; diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css index 43f17b9dc7..c8ec63e78f 100644 --- a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css +++ b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.css @@ -4,7 +4,7 @@ } .addReleaseProfile { - composes: releaseProfile from '~./ReleaseProfileRow.css'; + composes: releaseProfile from '~./ReleaseProfileItem.css'; background-color: var(--cardAlternateBackgroundColor); color: var(--gray); diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx index bf0b47a586..c0a34a46ce 100644 --- a/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx +++ b/frontend/src/Settings/Profiles/Release/ReleaseProfiles.tsx @@ -8,13 +8,13 @@ import Icon from 'Components/Icon'; import PageSectionContent from 'Components/Page/PageSectionContent'; import useModalOpenState from 'Helpers/Hooks/useModalOpenState'; import { icons } from 'Helpers/Props'; -import ReleaseProfileRow from 'Settings/Profiles/Release/ReleaseProfileRow'; import { fetchIndexers } from 'Store/Actions/Settings/indexers'; import { fetchReleaseProfiles } from 'Store/Actions/Settings/releaseProfiles'; import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector'; import createTagsSelector from 'Store/Selectors/createTagsSelector'; import translate from 'Utilities/String/translate'; import EditReleaseProfileModal from './EditReleaseProfileModal'; +import ReleaseProfileItem from './ReleaseProfileItem'; import styles from './ReleaseProfiles.css'; function ReleaseProfiles() { @@ -59,7 +59,7 @@ function ReleaseProfiles() { {items.map((item) => { return ( -