mirror of
https://github.com/TautvydasDerzinskas/Thingport.git
synced 2026-10-19 05:10:01 -05:00
feat(collections): add sync indicator to collection toolbar
This commit is contained in:
1 parent
ef9152df6c
commit
2ac5a4cd04
3 files changed
+83
-6
No files matched your search
@@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next";
|
||||
import Box from "@mui/material/Box";
|
||||
import ButtonBase from "@mui/material/ButtonBase";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import SyncIcon from "@mui/icons-material/Sync";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import type { CollectionSync } from "../api/collections";
|
||||
import { importProviderInfo } from "../constants/importProviders";
|
||||
import { ProviderLogo, type ProviderId } from "./Layout/ConfigurationDialog/providerLogos";
|
||||
@@ -52,12 +52,12 @@ export default function CollectionSyncBadge({ sync, size = 30, onClick }: Props)
|
||||
width: bubble,
|
||||
height: bubble,
|
||||
borderRadius: "50%",
|
||||
bgcolor: "success.main",
|
||||
bgcolor: "primary.main",
|
||||
color: "#fff",
|
||||
boxShadow: (theme) => `0 0 0 2px ${theme.palette.background.paper}`,
|
||||
}}
|
||||
>
|
||||
<SyncIcon sx={{ fontSize: Math.round(bubble * 0.75) }} />
|
||||
<CheckIcon sx={{ fontSize: Math.round(bubble * 0.75) }} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
@@ -79,7 +79,7 @@ export default function CollectionSyncBadge({ sync, size = 30, onClick }: Props)
|
||||
e.stopPropagation();
|
||||
onClick();
|
||||
}}
|
||||
sx={{ ...frame, "&:hover": { borderColor: "success.main" } }}
|
||||
sx={{ ...frame, "&:hover": { borderColor: "primary.main" } }}
|
||||
>
|
||||
{content}
|
||||
</ButtonBase>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Box from "@mui/material/Box";
|
||||
import ButtonBase from "@mui/material/ButtonBase";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import type { CollectionSync } from "../api/collections";
|
||||
import { importProviderInfo } from "../constants/importProviders";
|
||||
import { ProviderLogo, type ProviderId } from "./Layout/ConfigurationDialog/providerLogos";
|
||||
|
||||
const ICON_SIZE = 18;
|
||||
const BUBBLE_SIZE = 10;
|
||||
const LOGO_PROVIDERS = new Set<string>(["makerworld", "thingiverse", "printables"]);
|
||||
|
||||
/** The provider's logo with a small green tick, slim enough for a toolbar row. Opens the
|
||||
* collection's sync configuration. */
|
||||
export default function CollectionSyncIndicator({ sync, onClick }: { sync: CollectionSync; onClick: () => void }) {
|
||||
const { t } = useTranslation("models");
|
||||
const provider = importProviderInfo(sync.provider)?.label ?? sync.provider;
|
||||
const label = sync.likes_of
|
||||
? t("collections.sync.badgeLikes", { user: sync.likes_of })
|
||||
: t("collections.sync.badge", { provider });
|
||||
return (
|
||||
<Tooltip title={label}>
|
||||
<ButtonBase
|
||||
aria-label={`${label}. ${t("collections.sync.title")}`}
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
p: 0.5,
|
||||
// The padding is only for the hover background: cancelled out, the indicator takes no more
|
||||
// room than its icon, so the toolbar row it sits in doesn't grow.
|
||||
m: -0.5,
|
||||
borderRadius: "6px",
|
||||
transition: "background-color 150ms",
|
||||
"&:hover": { bgcolor: "action.hover" },
|
||||
"&:focus-visible": { outline: "2px solid", outlineColor: "primary.main", outlineOffset: 1 },
|
||||
}}
|
||||
>
|
||||
<Box sx={{ position: "relative", width: ICON_SIZE, height: ICON_SIZE }}>
|
||||
{LOGO_PROVIDERS.has(sync.provider) && <ProviderLogo id={sync.provider as ProviderId} size={ICON_SIZE} />}
|
||||
<Box
|
||||
aria-hidden
|
||||
sx={{
|
||||
position: "absolute",
|
||||
right: -BUBBLE_SIZE / 3,
|
||||
bottom: -BUBBLE_SIZE / 3,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
width: BUBBLE_SIZE,
|
||||
height: BUBBLE_SIZE,
|
||||
borderRadius: "50%",
|
||||
bgcolor: "primary.main",
|
||||
color: "#fff",
|
||||
// A ring in the page's colour keeps the tick readable over the logo.
|
||||
boxShadow: (theme) => `0 0 0 1.5px ${theme.palette.background.default}`,
|
||||
}}
|
||||
>
|
||||
<CheckIcon sx={{ fontSize: 8 }} />
|
||||
</Box>
|
||||
</Box>
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import ModelCard from "../ModelsPage/ModelCard";
|
||||
import SortTabs from "../ModelsPage/SortTabs";
|
||||
import CollectionActionsMenu from "./CollectionActionsMenu";
|
||||
import CollectionBookmarkButton from "./CollectionBookmarkButton";
|
||||
import CollectionSyncDialog from "./CollectionSyncDialog";
|
||||
import CollectionSyncIndicator from "../../components/CollectionSyncIndicator";
|
||||
|
||||
const PAGE_SIZE = 24;
|
||||
|
||||
@@ -40,6 +42,7 @@ export default function CollectionDetailPage({
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation(["models", "common"]);
|
||||
const [collection, setCollection] = useState<Collection | null>(null);
|
||||
const [syncOpen, setSyncOpen] = useState(false);
|
||||
const [notFound, setNotFound] = useState(false);
|
||||
const [items, setItems] = useState<Print[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -173,9 +176,20 @@ export default function CollectionDetailPage({
|
||||
{collection.description}
|
||||
</Typography>
|
||||
)}
|
||||
<Box sx={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<SortTabs value={sortMode} onChange={setSortMode} />
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||
{collection.sync && <CollectionSyncIndicator sync={collection.sync} onClick={() => setSyncOpen(true)} />}
|
||||
<Box sx={{ ml: "auto" }}>
|
||||
<SortTabs value={sortMode} onChange={setSortMode} />
|
||||
</Box>
|
||||
</Box>
|
||||
{syncOpen && collection.sync && (
|
||||
<CollectionSyncDialog
|
||||
collection={{ ...collection, sync: collection.sync }}
|
||||
onClose={() => setSyncOpen(false)}
|
||||
onUpdated={setCollection}
|
||||
onUnauthorized={onUnauthorized}
|
||||
/>
|
||||
)}
|
||||
{items.length ? (
|
||||
<Stack spacing={2}>
|
||||
<Box
|
||||
|
||||
Reference in new issue
Block a user