diff --git a/src/app.tsx b/src/app.tsx index 92936f47..9002eaf7 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -35,8 +35,8 @@ import FeedCacheContainer from './components/feed-cache-container'; import ReplyModal from './components/reply-modal'; import PostForm from './components/post-form'; import BoardBlotter from './components/board-blotter'; -import TopBar from './components/topbar'; -import TopbarEditModal from './components/topbar-edit-modal'; +import BoardsBar from './components/boardsbar'; +import BoardsBarEditModal from './components/boardsbar-edit-modal'; import DirectoryModal from './components/directory-modal'; import DisclaimerModal from './components/disclaimer-modal'; import SettingsModal from './components/settings-modal'; @@ -96,9 +96,9 @@ const BoardLayout = () => { return (
- + - + diff --git a/src/components/board-buttons/board-buttons.tsx b/src/components/board-buttons/board-buttons.tsx index 239712e0..fac1c350 100644 --- a/src/components/board-buttons/board-buttons.tsx +++ b/src/components/board-buttons/board-buttons.tsx @@ -32,7 +32,7 @@ interface BoardButtonsProps { isTopbar?: boolean; } -const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => { +export const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => { const { t } = useTranslation(); const params = useParams(); const directories = useDirectories(); @@ -68,7 +68,7 @@ const SubscribeButton = ({ address }: BoardButtonsProps) => { ); }; -const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView, isInModQueueView }: BoardButtonsProps) => { +export const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView, isInModQueueView }: BoardButtonsProps) => { const { t } = useTranslation(); const params = useParams(); const directories = useDirectories(); @@ -133,7 +133,7 @@ const RefreshButton = () => { ); }; -const UpdateButton = () => { +export const UpdateButton = () => { const { t } = useTranslation(); const reset = useFeedResetStore((state) => state.reset); return ( @@ -143,7 +143,7 @@ const UpdateButton = () => { ); }; -const AutoButton = () => { +export const AutoButton = () => { const { t } = useTranslation(); const isMobile = useIsMobile(); const handleAutoClick = () => { @@ -181,6 +181,18 @@ const BottomButton = () => { ); }; +export const TopButton = () => { + const { t } = useTranslation(); + const handleClick = () => { + window.scrollTo({ top: 0, left: 0, behavior: 'instant' }); + }; + return ( + + ); +}; + const SortOptions = () => { const { t } = useTranslation(); const { sortType, setSortType } = useSortingStore(); @@ -442,7 +454,7 @@ export const MobileBoardButtons = () => { ); }; -const PostPageStats = () => { +export const PostPageStats = () => { const { t } = useTranslation(); const params = useParams(); diff --git a/src/components/board-buttons/index.ts b/src/components/board-buttons/index.ts index 067ee43b..7cbc008b 100644 --- a/src/components/board-buttons/index.ts +++ b/src/components/board-buttons/index.ts @@ -1 +1 @@ -export { MobileBoardButtons, DesktopBoardButtons } from './board-buttons'; +export { MobileBoardButtons, DesktopBoardButtons, PostPageStats, ReturnButton, CatalogButton, UpdateButton, AutoButton, TopButton } from './board-buttons'; diff --git a/src/components/board-pagination/board-pagination.module.css b/src/components/board-pagination/board-pagination.module.css index 24b35289..c5ae676e 100644 --- a/src/components/board-pagination/board-pagination.module.css +++ b/src/components/board-pagination/board-pagination.module.css @@ -34,3 +34,21 @@ font-weight: bold; color: var(--button-desktop-text-color-hover); } + +/* Footer-style compact pagination (layout in footer-first-row.module.css) */ +.footerPageLink { + padding: 2px 6px; + font-size: 12px; + text-decoration: var(--button-text-decoration); + color: var(--button-desktop-text-color); +} + +.footerPageLink:hover { + color: var(--button-desktop-text-color-hover); + text-decoration: var(--button-text-decoration); +} + +.footerPageCurrent { + font-weight: bold; + color: var(--button-desktop-text-color-hover); +} diff --git a/src/components/board-pagination/board-pagination.tsx b/src/components/board-pagination/board-pagination.tsx index 7c93a8ad..09ec0bfa 100644 --- a/src/components/board-pagination/board-pagination.tsx +++ b/src/components/board-pagination/board-pagination.tsx @@ -1,24 +1,75 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; +import StyleSelector from '../style-selector/style-selector'; +import footerStyles from '../footer-first-row/footer-first-row.module.css'; import styles from './board-pagination.module.css'; export interface BoardPaginationProps { basePath: string; currentPage: number; totalPages: number; + /** When true, renders compact footer-style row with [1] [2] ... [10] Next Catalog + Style select */ + footerStyle?: boolean; } -const BoardPagination = ({ basePath, currentPage, totalPages }: BoardPaginationProps) => { +const BoardPagination = ({ basePath, currentPage, totalPages, footerStyle = false }: BoardPaginationProps) => { const { t } = useTranslation(); const pageHref = (page: number) => (page === 1 ? basePath : `${basePath}/${page}`); const prevHref = currentPage > 1 ? pageHref(currentPage - 1) : undefined; const nextHref = currentPage < totalPages ? pageHref(currentPage + 1) : undefined; + const catalogHref = `${basePath}/catalog`; - if (totalPages <= 1) { + if (totalPages <= 1 && !footerStyle) { return null; } + if (footerStyle) { + const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1); + const ellipsisThreshold = 7; + const showEllipsis = totalPages > ellipsisThreshold; + const visiblePages = showEllipsis ? [1, 2, currentPage, totalPages].filter((p, i, arr) => arr.indexOf(p) === i).sort((a, b) => a - b) : pageNumbers; + + return ( +
+
+ {visiblePages.map((page, idx) => { + const isCurrent = page === currentPage; + const prevPage = visiblePages[idx - 1]; + const showLeadingEllipsis = showEllipsis && prevPage !== undefined && page - prevPage > 1; + return ( + + {showLeadingEllipsis && ... } + {isCurrent ? ( + [{page}] + ) : ( + + [{page}] + + )} + + ); + })} + {nextHref && ( + <> + {' '} + + {t('next')} + + + )}{' '} + + {t('catalog')} + +
+
+ {t('style')}: + +
+
+ ); + } + const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1); return ( diff --git a/src/components/topbar-edit-modal/topbar-edit-modal.module.css b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.module.css similarity index 97% rename from src/components/topbar-edit-modal/topbar-edit-modal.module.css rename to src/components/boardsbar-edit-modal/boardsbar-edit-modal.module.css index 078c1847..fc806fc7 100644 --- a/src/components/topbar-edit-modal/topbar-edit-modal.module.css +++ b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.module.css @@ -8,7 +8,7 @@ z-index: 999; } -.topbarEditDialog { +.boardsbarEditDialog { position: absolute; width: 400px; max-height: 80vh; @@ -31,7 +31,7 @@ } @media (max-width: 600px) { - .topbarEditDialog { + .boardsbarEditDialog { width: calc(100% - 20px); margin-left: -50%; left: 50%; @@ -154,7 +154,7 @@ text-decoration: var(--post-content-link-text-decoration-hover); } -.topbarEditFooter { +.boardsbarEditFooter { padding: 0; margin: 0; text-align: center; diff --git a/src/components/topbar-edit-modal/topbar-edit-modal.tsx b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.tsx similarity index 71% rename from src/components/topbar-edit-modal/topbar-edit-modal.tsx rename to src/components/boardsbar-edit-modal/boardsbar-edit-modal.tsx index 3b7d29b3..2dbcbdab 100644 --- a/src/components/topbar-edit-modal/topbar-edit-modal.tsx +++ b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.tsx @@ -1,10 +1,10 @@ import { useState, useMemo } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { useAccount } from '@plebbit/plebbit-react-hooks'; -import useTopbarEditModalStore from '../../stores/use-topbar-edit-modal-store'; -import useTopbarVisibilityStore from '../../stores/use-topbar-visibility-store'; +import useBoardsBarEditModalStore from '../../stores/use-boardsbar-edit-modal-store'; +import useBoardsBarVisibilityStore from '../../stores/use-boardsbar-visibility-store'; import { getAllBoardCodes } from '../../constants/board-codes'; -import styles from './topbar-edit-modal.module.css'; +import styles from './boardsbar-edit-modal.module.css'; const directoriesToString = (dirs: Set): string => Array.from(dirs).sort().join(' '); @@ -18,20 +18,20 @@ const stringToDirectories = (str: string): Set => { }; // Form component keyed by store values so it remounts with fresh state when modal reopens -const TopbarEditModalForm = ({ +const BoardsBarEditModalForm = ({ visibleDirectories, - showSubscriptionsInTopbar, + showSubscriptionsInBoardsBar, setDirectoryVisibility, - setShowSubscriptionsInTopbar, - closeTopbarEditModal, + setShowSubscriptionsInBoardsBar, + closeBoardsBarEditModal, subscriptions, location, }: { visibleDirectories: Set; - showSubscriptionsInTopbar: boolean; + showSubscriptionsInBoardsBar: boolean; setDirectoryVisibility: (code: string, visible: boolean) => void; - setShowSubscriptionsInTopbar: (show: boolean) => void; - closeTopbarEditModal: () => void; + setShowSubscriptionsInBoardsBar: (show: boolean) => void; + closeBoardsBarEditModal: () => void; subscriptions: string[]; location: { pathname: string }; }) => { @@ -39,7 +39,7 @@ const TopbarEditModalForm = ({ const allVisible = allBoardCodes.every((code) => visibleDirectories.has(code)); const [localDirectoryInput, setLocalDirectoryInput] = useState(() => (allVisible ? '' : directoriesToString(visibleDirectories))); - const [showSubscriptions, setShowSubscriptions] = useState(() => showSubscriptionsInTopbar); + const [showSubscriptions, setShowSubscriptions] = useState(() => showSubscriptionsInBoardsBar); const handleSave = () => { if (localDirectoryInput.trim() === '') { @@ -48,8 +48,8 @@ const TopbarEditModalForm = ({ const inputDirectories = stringToDirectories(localDirectoryInput); allBoardCodes.forEach((code) => setDirectoryVisibility(code, inputDirectories.has(code))); } - setShowSubscriptionsInTopbar(showSubscriptions); - closeTopbarEditModal(); + setShowSubscriptionsInBoardsBar(showSubscriptions); + closeBoardsBarEditModal(); }; return ( @@ -76,7 +76,7 @@ const TopbarEditModalForm = ({ className={styles.editSubscriptionsLink} onClick={(e) => { e.stopPropagation(); - closeTopbarEditModal(); + closeBoardsBarEditModal(); }} > edit subscriptions @@ -86,16 +86,16 @@ const TopbarEditModalForm = ({
)} -
+
); }; -const TopbarEditModal = () => { - const { showModal, closeTopbarEditModal } = useTopbarEditModalStore(); - const { visibleDirectories, showSubscriptionsInTopbar, setDirectoryVisibility, setShowSubscriptionsInTopbar } = useTopbarVisibilityStore(); +const BoardsBarEditModal = () => { + const { showModal, closeBoardsBarEditModal } = useBoardsBarEditModalStore(); + const { visibleDirectories, showSubscriptionsInBoardsBar, setDirectoryVisibility, setShowSubscriptionsInBoardsBar } = useBoardsBarVisibilityStore(); const account = useAccount(); const subscriptions = useMemo(() => account?.subscriptions || [], [account?.subscriptions]); const location = useLocation(); @@ -106,27 +106,27 @@ const TopbarEditModal = () => { const handleBackdropClick = (e: React.MouseEvent) => { if (e.target === e.currentTarget) { - closeTopbarEditModal(); + closeBoardsBarEditModal(); } }; - const formKey = `${directoriesToString(visibleDirectories)}-${showSubscriptionsInTopbar}`; + const formKey = `${directoriesToString(visibleDirectories)}-${showSubscriptionsInBoardsBar}`; return (
-
+

Custom Board List

-
- @@ -136,4 +136,4 @@ const TopbarEditModal = () => { ); }; -export default TopbarEditModal; +export default BoardsBarEditModal; diff --git a/src/components/topbar-edit-modal/topbar-edit-modal.types.ts b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.types.ts similarity index 81% rename from src/components/topbar-edit-modal/topbar-edit-modal.types.ts rename to src/components/boardsbar-edit-modal/boardsbar-edit-modal.types.ts index f215e160..0682959d 100644 --- a/src/components/topbar-edit-modal/topbar-edit-modal.types.ts +++ b/src/components/boardsbar-edit-modal/boardsbar-edit-modal.types.ts @@ -1,4 +1,4 @@ -// Types for topbar edit modal component +// Types for boardsbar edit modal component export interface BoardCodeCheckbox { code: string; diff --git a/src/components/boardsbar-edit-modal/index.ts b/src/components/boardsbar-edit-modal/index.ts new file mode 100644 index 00000000..ce2ac21f --- /dev/null +++ b/src/components/boardsbar-edit-modal/index.ts @@ -0,0 +1 @@ +export { default } from './boardsbar-edit-modal'; diff --git a/src/components/topbar/topbar.module.css b/src/components/boardsbar/boardsbar.module.css similarity index 61% rename from src/components/topbar/topbar.module.css rename to src/components/boardsbar/boardsbar.module.css index 17d00e8a..dac588fb 100644 --- a/src/components/topbar/topbar.module.css +++ b/src/components/boardsbar/boardsbar.module.css @@ -1,29 +1,29 @@ .boardNavDesktop { - font-size: var(--topbar-font-size); - color: var(--topbar-separator-color); + font-size: var(--boardsbar-font-size); + color: var(--boardsbar-separator-color); position: relative; } .checkingSubscriptions { - font-size: var(--topbar-font-size); - color: var(--topbar-desktop-link-text-color); + font-size: var(--boardsbar-font-size); + color: var(--boardsbar-desktop-link-text-color); text-transform: lowercase; } .boardNavDesktop a, .navTopRight span { - color: var(--topbar-desktop-link-text-color); - text-decoration: var(--topbar-desktop-link-text-decoration); + color: var(--boardsbar-desktop-link-text-color); + text-decoration: var(--boardsbar-desktop-link-text-decoration); } .boardNavDesktop a:hover, .navTopRight span:hover { - color: var(--topbar-desktop-link-text-color-hover); - text-decoration: var(--topbar-desktop-link-text-decoration-hover); + color: var(--boardsbar-desktop-link-text-color-hover); + text-decoration: var(--boardsbar-desktop-link-text-decoration-hover); cursor: pointer; } .placeholder { - color: var(--topbar-separator-color); + color: var(--boardsbar-separator-color); } .navTopRight { @@ -42,14 +42,14 @@ } .temporaryButton { - color: var(--topbar-desktop-link-text-color); - text-decoration: var(--topbar-desktop-link-text-decoration); + color: var(--boardsbar-desktop-link-text-color); + text-decoration: var(--boardsbar-desktop-link-text-decoration); text-transform: capitalize; } .temporaryButton:hover { - color: var(--topbar-desktop-link-text-color-hover); - text-decoration: var(--topbar-desktop-link-text-decoration-hover); + color: var(--boardsbar-desktop-link-text-color-hover); + text-decoration: var(--boardsbar-desktop-link-text-decoration-hover); cursor: pointer; } @@ -63,9 +63,9 @@ .boardNavMobile { padding: 2px 4px; - background-color: var(--topbar-mobile-background-color); - border-bottom: var(--topbar-mobile-border-bottom); - font-size: var(--topbar-mobile-font-size); + background-color: var(--boardsbar-mobile-background-color); + border-bottom: var(--boardsbar-mobile-border-bottom); + font-size: var(--boardsbar-mobile-font-size); position: fixed; width: 100%; z-index: 3; @@ -77,7 +77,7 @@ } .boardNavMobile .pageJump a, .boardNavMobile .pageJump span { - color: var(--topbar-mobile-button-text-color); + color: var(--boardsbar-mobile-button-text-color); text-decoration: var(--button-text-decoration-mobile); } @@ -91,7 +91,7 @@ } .boardNavMobile select { - font-size: var(--topbar-mobile-font-size); + font-size: var(--boardsbar-mobile-font-size); } .boardSelect { @@ -120,4 +120,4 @@ .boardNavMobile { display: none; } -} \ No newline at end of file +} diff --git a/src/components/topbar/topbar.tsx b/src/components/boardsbar/boardsbar.tsx similarity index 93% rename from src/components/topbar/topbar.tsx rename to src/components/boardsbar/boardsbar.tsx index d73f9040..33c6610b 100644 --- a/src/components/topbar/topbar.tsx +++ b/src/components/boardsbar/boardsbar.tsx @@ -9,11 +9,11 @@ import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories' import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address'; import { getBoardPath, extractDirectoryFromTitle } from '../../lib/utils/route-utils'; import useCreateBoardModalStore from '../../stores/use-create-board-modal-store'; -import useTopbarEditModalStore from '../../stores/use-topbar-edit-modal-store'; -import useTopbarVisibilityStore from '../../stores/use-topbar-visibility-store'; +import useBoardsBarEditModalStore from '../../stores/use-boardsbar-edit-modal-store'; +import useBoardsBarVisibilityStore from '../../stores/use-boardsbar-visibility-store'; import useDirectoryModalStore from '../../stores/use-directory-modal-store'; import { BOARD_CODE_GROUPS, getAllBoardCodes } from '../../constants/board-codes'; -import styles from './topbar.module.css'; +import styles from './boardsbar.module.css'; import capitalize from 'lodash/capitalize'; import debounce from 'lodash/debounce'; import lowerCase from 'lodash/lowerCase'; @@ -87,7 +87,7 @@ const findBoardAddressByCode = (code: string, directories: DirectoryCommunity[]) return entry?.address || null; }; -const TopBarDesktop = () => { +const BoardsBarDesktop = () => { const { t } = useTranslation(); const location = useLocation(); const params = useParams(); @@ -95,9 +95,9 @@ const TopBarDesktop = () => { const [showSearchBar, setShowSearchBar] = useState(false); const [showAllTemporarily, setShowAllTemporarily] = useState(false); const { openCreateBoardModal } = useCreateBoardModalStore(); - const { openTopbarEditModal } = useTopbarEditModalStore(); + const { openBoardsBarEditModal } = useBoardsBarEditModalStore(); const { openDirectoryModal } = useDirectoryModalStore(); - const { visibleDirectories, showSubscriptionsInTopbar } = useTopbarVisibilityStore(); + const { visibleDirectories, showSubscriptionsInBoardsBar } = useBoardsBarVisibilityStore(); const directories = useDirectories(); // Memoize allBoardCodes since it's derived from a constant @@ -129,7 +129,7 @@ const TopBarDesktop = () => { ); // Show all subscriptions when enabled; no separate per-address tracking (avoids drift when subscribing from board-buttons) - const visibleSubscriptionAddresses = showSubscriptionsInTopbar ? subscriptions : []; + const visibleSubscriptionAddresses = showSubscriptionsInBoardsBar ? subscriptions : []; // Check if any directories are hidden const hasHiddenDirectories = useMemo(() => { @@ -146,7 +146,7 @@ const TopBarDesktop = () => { // Initialize visibility store on mount useEffect(() => { - useTopbarVisibilityStore.getState().initialize(); + useBoardsBarVisibilityStore.getState().initialize(); }, []); // Render a board code link or placeholder @@ -229,7 +229,7 @@ const TopBarDesktop = () => { <>[{visibleSubscriptionAddresses.map((address: string, index: number) => renderSubscription(address, index, visibleSubscriptionAddresses.length))}] )} [ - openTopbarEditModal()} style={{ cursor: 'pointer' }}> + openBoardsBarEditModal()} style={{ cursor: 'pointer' }}> {capitalize(t('edit'))} ] [ @@ -247,7 +247,7 @@ const TopBarDesktop = () => { ); }; -const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => { +const BoardsBarMobile = ({ subplebbitAddress }: { subplebbitAddress?: string }) => { const { t } = useTranslation(); const navigate = useNavigate(); const directories = useDirectories(); @@ -302,7 +302,7 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => { {directoryBoards.map((board, index) => { const directoryCode = extractDirectoryFromTitle(board.title!); return ( - ); @@ -344,7 +344,7 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => { ); }; -const TopBar = () => { +const BoardsBar = () => { const params = useParams(); const commentIndex = params?.accountCommentIndex ? parseInt(params.accountCommentIndex) : undefined; const accountComment = useAccountComment({ commentIndex }); @@ -353,10 +353,10 @@ const TopBar = () => { return ( <> - - + + ); }; -export default TopBar; +export default BoardsBar; diff --git a/src/components/boardsbar/index.ts b/src/components/boardsbar/index.ts new file mode 100644 index 00000000..7a4e1192 --- /dev/null +++ b/src/components/boardsbar/index.ts @@ -0,0 +1 @@ +export { default } from './boardsbar'; diff --git a/src/components/catalog-footer-first-row/catalog-footer-first-row.tsx b/src/components/catalog-footer-first-row/catalog-footer-first-row.tsx new file mode 100644 index 00000000..9df6f278 --- /dev/null +++ b/src/components/catalog-footer-first-row/catalog-footer-first-row.tsx @@ -0,0 +1,20 @@ +import { useTranslation } from 'react-i18next'; +import StyleSelector from '../style-selector/style-selector'; +import styles from '../footer-first-row/footer-first-row.module.css'; + +/** Catalog footer first row: Style selector on right only (no pagination; catalog shows all pages at once). */ +const CatalogFooterFirstRow = () => { + const { t } = useTranslation(); + + return ( +
+
+
+ {t('style')}: + +
+
+ ); +}; + +export default CatalogFooterFirstRow; diff --git a/src/components/catalog-footer-first-row/index.ts b/src/components/catalog-footer-first-row/index.ts new file mode 100644 index 00000000..46fb1a18 --- /dev/null +++ b/src/components/catalog-footer-first-row/index.ts @@ -0,0 +1 @@ +export { default } from './catalog-footer-first-row'; diff --git a/src/components/footer-first-row/footer-first-row.module.css b/src/components/footer-first-row/footer-first-row.module.css new file mode 100644 index 00000000..7724873e --- /dev/null +++ b/src/components/footer-first-row/footer-first-row.module.css @@ -0,0 +1,27 @@ +/* Shared footer first-row layout styles (catalog footer, board pagination footer mode) */ +.footerRow { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 8px; + width: 100%; +} + +.footerLeft { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.footerRight { + display: flex; + align-items: center; + gap: 6px; +} + +.styleLabel { + font-size: 12px; + text-transform: capitalize; +} diff --git a/src/components/page-footer-desktop/index.ts b/src/components/page-footer-desktop/index.ts new file mode 100644 index 00000000..56b45e60 --- /dev/null +++ b/src/components/page-footer-desktop/index.ts @@ -0,0 +1,2 @@ +export { default } from './page-footer-desktop'; +export type { PageFooterDesktopProps } from './page-footer-desktop'; diff --git a/src/components/page-footer-desktop/page-footer-desktop.module.css b/src/components/page-footer-desktop/page-footer-desktop.module.css new file mode 100644 index 00000000..158841cd --- /dev/null +++ b/src/components/page-footer-desktop/page-footer-desktop.module.css @@ -0,0 +1,38 @@ +.footer { + margin-top: 16px; + padding-bottom: 24px; +} + +.footer hr { + width: 90%; + margin: 16px auto; + border: none; + border-top: 1px solid var(--border-color, #ccc); +} + +.firstRow { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 8px; + padding: 8px 0; + text-align: center; +} + +.boardsBarRow { + padding: 8px 0; +} + +.legalMeta { + padding: 12px 0 0; + font-size: 11px; + color: var(--body-font-color); + text-align: center; +} + +@media (max-width: 640px) { + .footer { + display: none; + } +} diff --git a/src/components/page-footer-desktop/page-footer-desktop.tsx b/src/components/page-footer-desktop/page-footer-desktop.tsx new file mode 100644 index 00000000..789af537 --- /dev/null +++ b/src/components/page-footer-desktop/page-footer-desktop.tsx @@ -0,0 +1,25 @@ +import BoardsBar from '../boardsbar'; +import SiteLegalMeta from '../site-legal-meta'; +import styles from './page-footer-desktop.module.css'; + +export interface PageFooterDesktopProps { + /** Mode-specific first row content (e.g. board pagination or thread controls) */ + firstRow: React.ReactNode; +} + +const PageFooterDesktop = ({ firstRow }: PageFooterDesktopProps) => { + return ( +
+
+
{firstRow}
+
+ +
+
+ +
+
+ ); +}; + +export default PageFooterDesktop; diff --git a/src/components/settings-modal/interface-settings/__tests__/interface-settings.test.tsx b/src/components/settings-modal/interface-settings/__tests__/interface-settings.test.tsx index 0a114a84..66de998b 100644 --- a/src/components/settings-modal/interface-settings/__tests__/interface-settings.test.tsx +++ b/src/components/settings-modal/interface-settings/__tests__/interface-settings.test.tsx @@ -16,22 +16,10 @@ vi.mock('react-i18next', () => ({ }), })); -vi.mock('../../../../hooks/use-theme', () => ({ - default: () => ['yotsuba', vi.fn()], -})); - vi.mock('../../../../stores/use-expanded-media-store', () => ({ default: () => ({ fitExpandedImagesToScreen: false, setFitExpandedImagesToScreen: vi.fn() }), })); -vi.mock('../../../../stores/use-special-theme-store', () => ({ - default: () => ({ isEnabled: false, setIsEnabled: vi.fn() }), -})); - -vi.mock('../../../../lib/utils/time-utils', () => ({ - isChristmas: () => false, -})); - vi.mock('../../version', () => ({ default: () => null, })); diff --git a/src/components/settings-modal/interface-settings/interface-settings.tsx b/src/components/settings-modal/interface-settings/interface-settings.tsx index a372833b..87e3aa89 100644 --- a/src/components/settings-modal/interface-settings/interface-settings.tsx +++ b/src/components/settings-modal/interface-settings/interface-settings.tsx @@ -1,13 +1,10 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import useTheme from '../../../hooks/use-theme'; import packageJson from '../../../../package.json'; import styles from './interface-settings.module.css'; import capitalize from 'lodash/capitalize'; import useExpandedMediaStore from '../../../stores/use-expanded-media-store'; import useFeedViewSettingsStore from '../../../stores/use-feed-view-settings-store'; -import useSpecialThemeStore from '../../../stores/use-special-theme-store'; -import { isChristmas } from '../../../lib/utils/time-utils'; import Version from '../../version'; const commitRef = process.env.VITE_COMMIT_REF; @@ -68,36 +65,6 @@ const CheckForUpdates = () => { ); }; -const Style = () => { - const [theme, setTheme] = useTheme(); - const { isEnabled, setIsEnabled } = useSpecialThemeStore(); - const isChristmasTime = isChristmas(); - - const handleThemeChange = (e: React.ChangeEvent) => { - const newTheme = e.target.value; - - if (newTheme === 'special') { - setIsEnabled(true); - setTheme('tomorrow'); - } else { - setIsEnabled(false); - setTheme(newTheme); - } - }; - - return ( - - ); -}; - // prettier-ignore const availableLanguages = ['ar', 'bn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fil', 'fr', 'he', 'hi', 'hu', 'id', 'it', 'ja', 'ko', 'mr', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sq', 'sv', 'te', 'th', 'tr', 'uk', 'ur', 'vi', 'zh']; @@ -135,9 +102,6 @@ const InterfaceSettings = () => {
{capitalize(t('update'))}:
-
- {capitalize(t('style'))}: