Add static class names to UI elements for easier customization (#4421)

* Initial plan

* Add static class names to UI elements for easier customization

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Add unique DOM element IDs for easier customization targeting

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Remove duplicate class names, keep only IDs for UI element targeting

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Revert chat input field ID to original value

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Remove unnecessary nested spans and revert Button ID to original value

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Standardize ID names to follow owncast-{element-description}-{type} pattern

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gabek <414923+gabek@users.noreply.github.com>
Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
Copilot
2025-08-07 19:12:28 -07:00
committed by GitHub
co-authored by gabek copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Gabe Kangas
parent 8b623f4c1a
commit 84eaa60ec9
7 changed files with 25 additions and 8 deletions
@@ -9,6 +9,10 @@ export type ChatActionMessageProps = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const ChatActionMessage: FC<ChatActionMessageProps> = ({ body }) => (
<div className={styles.chatActionPadding}>
<div dangerouslySetInnerHTML={{ __html: body }} className={styles.chatAction} />
<div
id="owncast-chat-action-message-text"
dangerouslySetInnerHTML={{ __html: body }}
className={styles.chatAction}
/>
</div>
);
@@ -27,7 +27,10 @@ export const ChatNameChangeMessage: FC<ChatNameChangeMessageProps> = ({ message
</div>
<div className={styles.nameChangeText}>
<span style={{ color }}>{oldName}</span>
<span className={styles.plain}> is now known as </span>
<span className={styles.plain} id="owncast-name-change-is-now-known-text">
{' '}
is now known as{' '}
</span>
<span style={{ color }}>{displayName}</span>
</div>
</div>
@@ -283,6 +283,7 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
<button
type="button"
aria-label="Emoji picker"
id="owncast-emoji-picker-button"
className={styles.emojiButton}
title="Emoji picker button"
>
@@ -292,6 +293,7 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
<button
type="button"
aria-label="Send message"
id="owncast-send-message-button"
className={styles.sendButton}
title="Send message Button"
onClick={sendMessage}
@@ -86,7 +86,9 @@ export const NameChangeModal: FC<NameChangeModalProps> = ({ closeModal }) => {
return (
<div>
<div id="owncast-name-change-description-text">
Your chat display name is what people see when you send chat messages.
</div>
<Form onSubmitCapture={handleNameChange} className={styles.form}>
<Input.Search
enterButton={saveButton}
@@ -114,8 +116,10 @@ export const NameChangeModal: FC<NameChangeModalProps> = ({ closeModal }) => {
))}
</Select>
</Form.Item>
<div id="owncast-name-change-auth-info-text">
You can also authenticate an IndieAuth or Fediverse account via the &quot;Authenticate&quot;
menu.
</div>
</div>
);
};
+1 -1
View File
@@ -13,7 +13,7 @@ export const Footer: FC = () => {
const { t } = useTranslation();
return (
<footer className={styles.footer} id="footer">
<span>
<span id="owncast-powered-by-text">
<Translation
translationKey={Localization.Common.poweredByOwncastVersion}
vars={{ versionNumber }}
+3 -1
View File
@@ -64,7 +64,9 @@ export const Header: FC<HeaderComponentProps> = ({ name, chatAvailable, chatDisa
title={t('Chat will be available when the stream is live.')}
placement="left"
>
<span className={styles.chatOfflineText}>{t('Chat is offline')}</span>
<span className={styles.chatOfflineText} id="owncast-chat-offline-text">
{t('Chat is offline')}
</span>
</Tooltip>
)}
</header>
@@ -111,7 +111,9 @@ export const OfflineBanner: FC<OfflineBannerProps> = ({
{lastLive && (
<div className={styles.lastLiveDate}>
<ClockCircleOutlined className={styles.clockIcon} />
<span id="owncast-offline-last-live-text">
{`${t('Last live ago', { timeAgo: formatDistanceToNow(new Date(lastLive)) })}`}
</span>
</div>
)}
</div>