mirror of
https://github.com/XFox111/TabsAsideExtension.git
synced 2026-04-22 07:58:01 +03:00
feat: Minor 3.3.0 (#222)
* feat: add ability to hide collections #211 (#213) * feat: add ability to hide collections #211 * fix: hide/unhide collection label is swapped * fix: missing useCallback dependency * fix: add selected tabs to existing collection adds all tabs in current window #215 (#216) * fix: add selected tabs to existing collection adds all tabs in current window #215 * fix: force selected tabs only for adding tabs to groups * feat: compact collection view (#214) * feat: compact collection view #201 * loc: compact view localization * fix(loc): missing "color" translation in edit dialog * feat: add ability to edit saved tabs (#218) * feat: adds option to edit saved tabs #217 * loc: translations for #217 * build(deps): Bump the react group with 2 updates (#221) Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). Updates `react` from 19.2.1 to 19.2.3 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.3/packages/react) Updates `react-dom` from 19.2.1 to 19.2.3 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.3/packages/react-dom) --- updated-dependencies: - dependency-name: react dependency-version: 19.2.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react - dependency-name: react-dom dependency-version: 19.2.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): Bump the deps group with 4 updates (#220) Bumps the deps group with 4 updates: [@fluentui/react-components](https://github.com/microsoft/fluentui), [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js), [eslint](https://github.com/eslint/eslint) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `@fluentui/react-components` from 9.72.8 to 9.72.9 - [Release notes](https://github.com/microsoft/fluentui/releases) - [Commits](https://github.com/microsoft/fluentui/compare/@fluentui/react-components_v9.72.8...@fluentui/react-components_v9.72.9) Updates `@eslint/js` from 9.39.1 to 9.39.2 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v9.39.2/packages/js) Updates `eslint` from 9.39.1 to 9.39.2 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v9.39.1...v9.39.2) Updates `typescript-eslint` from 8.49.0 to 8.51.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-version: 9.72.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: deps - dependency-name: "@eslint/js" dependency-version: 9.39.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: deps - dependency-name: eslint dependency-version: 9.39.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: deps - dependency-name: typescript-eslint dependency-version: 8.51.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: deps ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: Bump version from 3.2.3 to 3.3.0 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,11 @@ export const useStyles_CollectionView = makeStyles({
|
||||
"&:hover":
|
||||
{
|
||||
boxShadow: tokens.shadow4
|
||||
},
|
||||
|
||||
"&:not(:focus-within) .compact":
|
||||
{
|
||||
display: "none"
|
||||
}
|
||||
},
|
||||
color:
|
||||
|
||||
@@ -12,7 +12,12 @@ import { useStyles_CollectionView } from "./CollectionView.styles";
|
||||
import GroupView from "./GroupView";
|
||||
import TabView from "./TabView";
|
||||
|
||||
export default function CollectionView({ collection, index: collectionIndex, dragOverlay }: CollectionViewProps): ReactElement
|
||||
export default function CollectionView({
|
||||
collection,
|
||||
index: collectionIndex,
|
||||
dragOverlay,
|
||||
compact
|
||||
}: CollectionViewProps): ReactElement
|
||||
{
|
||||
const { tilesView } = useCollections();
|
||||
const {
|
||||
@@ -53,12 +58,12 @@ export default function CollectionView({ collection, index: collectionIndex, dra
|
||||
{ (!activeItem || activeItem.item.type !== "collection") && !dragOverlay &&
|
||||
<>
|
||||
{ collection.items.length < 1 ?
|
||||
<div className={ cls.empty }>
|
||||
<div className={ mergeClasses(cls.empty, compact === true && "compact") }>
|
||||
<CollectionsRegular fontSize={ 32 } />
|
||||
<Body1Strong>{ i18n.t("collections.empty") }</Body1Strong>
|
||||
</div>
|
||||
:
|
||||
<div className={ mergeClasses(cls.list, !tilesView && cls.verticalList) }>
|
||||
<div className={ mergeClasses(cls.list, !tilesView && cls.verticalList, compact === true && "compact") }>
|
||||
<SortableContext
|
||||
items={ collection.items.map((_, index) => [collectionIndex, index].join("/")) }
|
||||
strategy={ tilesView ? horizontalListSortingStrategy : verticalListSortingStrategy }
|
||||
@@ -66,9 +71,12 @@ export default function CollectionView({ collection, index: collectionIndex, dra
|
||||
{ collection.items.map((i, index) =>
|
||||
i.type === "group" ?
|
||||
<GroupView
|
||||
key={ index } group={ i } indices={ [collectionIndex, index] } />
|
||||
key={ index } group={ i } indices={ [collectionIndex, index] }
|
||||
collectionId={ collection.timestamp } />
|
||||
:
|
||||
<TabView key={ index } tab={ i } indices={ [collectionIndex, index] } />
|
||||
<TabView
|
||||
key={ index } tab={ i } indices={ [collectionIndex, index] }
|
||||
collectionId={ collection.timestamp } />
|
||||
) }
|
||||
</SortableContext>
|
||||
</div>
|
||||
@@ -85,4 +93,5 @@ export type CollectionViewProps =
|
||||
collection: CollectionItem;
|
||||
index: number;
|
||||
dragOverlay?: boolean;
|
||||
compact?: boolean | null;
|
||||
};
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function EditDialog(props: GroupEditDialogProps): ReactElement
|
||||
value={ color === "pinned" ? i18n.t("groups.pinned") : title }
|
||||
onChange={ (_, e) => setTitle(e.value) } />
|
||||
</fui.Field>
|
||||
<fui.Field label="Color">
|
||||
<fui.Field label={ i18n.t("dialogs.edit.color") }>
|
||||
<div className={ cls.colorPicker } { ...horizontalNavigationAttributes }>
|
||||
{ (props.type === "group" && (!props.hidePinned || props.group?.pinned)) &&
|
||||
<fui.ToggleButton
|
||||
|
||||
@@ -14,7 +14,7 @@ import GroupMoreMenu from "./collections/GroupMoreMenu";
|
||||
import { useStyles_GroupView } from "./GroupView.styles";
|
||||
import TabView from "./TabView";
|
||||
|
||||
export default function GroupView({ group, indices, dragOverlay }: GroupViewProps): ReactElement
|
||||
export default function GroupView({ group, indices, dragOverlay, collectionId }: GroupViewProps): ReactElement
|
||||
{
|
||||
const [alwaysShowToolbars] = useSettings("alwaysShowToolbars");
|
||||
const { tilesView } = useCollections();
|
||||
@@ -101,7 +101,9 @@ export default function GroupView({ group, indices, dragOverlay }: GroupViewProp
|
||||
strategy={ !tilesView ? verticalListSortingStrategy : horizontalListSortingStrategy }
|
||||
>
|
||||
{ group.items.map((i, index) =>
|
||||
<TabView key={ index } tab={ i } indices={ [...indices, index] } />
|
||||
<TabView
|
||||
key={ index } tab={ i } indices={ [...indices, index] }
|
||||
collectionId={ collectionId } />
|
||||
) }
|
||||
</SortableContext>
|
||||
</div>
|
||||
@@ -117,4 +119,5 @@ export type GroupViewProps =
|
||||
group: GroupItem;
|
||||
indices: number[];
|
||||
dragOverlay?: boolean;
|
||||
collectionId: number;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { track } from "@/features/analytics";
|
||||
import { TabItem } from "@/models/CollectionModels";
|
||||
import { Button, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Field, Input, makeStyles, tokens } from "@fluentui/react-components";
|
||||
|
||||
export default function TabEditDialog({ tab, onSave }: TabEditDialogProps): React.ReactElement
|
||||
{
|
||||
const cls = useStyles();
|
||||
|
||||
const [title, setTitle] = useState(tab.title ?? "");
|
||||
const [url, setUrl] = useState(tab.url);
|
||||
const isValid = useMemo(() => url.trim().length > 0, [url]);
|
||||
|
||||
const onSubmit = (e: React.FormEvent<HTMLFormElement>) =>
|
||||
{
|
||||
e.preventDefault();
|
||||
track("item_edited", { type: "tab" });
|
||||
onSave({
|
||||
...tab,
|
||||
title: title.trim().length > 0 ? title : undefined,
|
||||
url: url.trim()
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogSurface>
|
||||
<form onSubmit={ onSubmit }>
|
||||
<DialogBody>
|
||||
<DialogTitle>{ i18n.t("dialogs.edit.title.edit_tab") }</DialogTitle>
|
||||
<DialogContent className={ cls.content }>
|
||||
<Input
|
||||
value={ title } onChange={ (_, e) => setTitle(e.value) }
|
||||
placeholder={ i18n.t("dialogs.edit.collection_title") } />
|
||||
<Field validationMessage={ isValid ? undefined : i18n.t("dialogs.edit.url_error") }>
|
||||
<Input
|
||||
value={ url } onChange={ (_, e) => setUrl(e.value) }
|
||||
placeholder="URL" />
|
||||
</Field>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<DialogTrigger disableButtonEnhancement>
|
||||
<Button disabled={ !isValid } appearance="primary" as="button" type="submit">
|
||||
{ i18n.t("common.actions.save") }
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogTrigger disableButtonEnhancement>
|
||||
<Button appearance="subtle">{ i18n.t("common.actions.cancel") }</Button>
|
||||
</DialogTrigger>
|
||||
</DialogActions>
|
||||
</DialogBody>
|
||||
</form>
|
||||
</DialogSurface>
|
||||
);
|
||||
}
|
||||
|
||||
const useStyles = makeStyles({
|
||||
content:
|
||||
{
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
gap: tokens.spacingVerticalMNudge
|
||||
}
|
||||
});
|
||||
|
||||
export type TabEditDialogProps =
|
||||
{
|
||||
tab: TabItem;
|
||||
onSave: (updatedTab: TabItem) => void;
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useDangerStyles } from "@/hooks/useDangerStyles";
|
||||
import { Button, Menu, MenuItem, MenuList, MenuPopover, MenuTrigger, Tooltip } from "@fluentui/react-components";
|
||||
import { bundleIcon, Delete20Filled, Delete20Regular, Edit20Filled, Edit20Regular, MoreHorizontal20Regular } from "@fluentui/react-icons";
|
||||
import { ButtonHTMLAttributes } from "react";
|
||||
|
||||
export default function TabMoreButton({ onEdit, onDelete, ...props }: TabMoreButtonProps): React.ReactElement
|
||||
{
|
||||
const EditIcon = bundleIcon(Edit20Filled, Edit20Regular);
|
||||
const DeleteIcon = bundleIcon(Delete20Filled, Delete20Regular);
|
||||
const dangerCls = useDangerStyles();
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<Tooltip relationship="label" content={ i18n.t("common.tooltips.more") }>
|
||||
<MenuTrigger>
|
||||
<Button
|
||||
appearance="subtle" icon={ <MoreHorizontal20Regular /> }
|
||||
onClick={ ev => ev.stopPropagation() }
|
||||
{ ...props } />
|
||||
</MenuTrigger>
|
||||
</Tooltip>
|
||||
|
||||
<MenuPopover onClick={ ev => ev.stopPropagation() }>
|
||||
<MenuList>
|
||||
<MenuItem icon={ <EditIcon /> } onClick={ onEdit }>
|
||||
{ i18n.t("dialogs.edit.title.edit_tab") }
|
||||
</MenuItem>
|
||||
<MenuItem icon={ <DeleteIcon /> } className={ dangerCls.menuItem } onClick={ onDelete }>
|
||||
{ i18n.t("tabs.delete") }
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</MenuPopover>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
export type TabMoreButtonProps =
|
||||
ButtonHTMLAttributes<HTMLButtonElement> &
|
||||
{
|
||||
onDelete?: () => void;
|
||||
onEdit?: () => void;
|
||||
};
|
||||
@@ -4,16 +4,17 @@ import { useDialog } from "@/contexts/DialogProvider";
|
||||
import { useCollections } from "@/entrypoints/sidepanel/contexts/CollectionsProvider";
|
||||
import useDndItem from "@/entrypoints/sidepanel/hooks/useDndItem";
|
||||
import useSettings from "@/hooks/useSettings";
|
||||
import { TabItem } from "@/models/CollectionModels";
|
||||
import { Button, Caption1, Link, mergeClasses, Tooltip } from "@fluentui/react-components";
|
||||
import { Dismiss20Regular } from "@fluentui/react-icons";
|
||||
import { CollectionItem, GroupItem, TabItem } from "@/models/CollectionModels";
|
||||
import { Caption1, Link, mergeClasses, Tooltip } from "@fluentui/react-components";
|
||||
import { MouseEventHandler, ReactElement } from "react";
|
||||
import { useStyles_TabView } from "./TabView.styles";
|
||||
import CollectionContext, { CollectionContextType } from "../contexts/CollectionContext";
|
||||
import TabMoreButton from "./TabMoreButton";
|
||||
import TabEditDialog from "./TabEditDialog";
|
||||
|
||||
export default function TabView({ tab, indices, dragOverlay }: TabViewProps): ReactElement
|
||||
export default function TabView({ tab, indices, dragOverlay, collectionId }: TabViewProps): ReactElement
|
||||
{
|
||||
const { removeItem, graphics, tilesView } = useCollections();
|
||||
const { removeItem, graphics, tilesView, collections, updateCollection } = useCollections();
|
||||
const { collection } = useContext<CollectionContextType>(CollectionContext);
|
||||
const {
|
||||
setNodeRef, setActivatorNodeRef,
|
||||
@@ -26,11 +27,8 @@ export default function TabView({ tab, indices, dragOverlay }: TabViewProps): Re
|
||||
|
||||
const cls = useStyles_TabView();
|
||||
|
||||
const handleDelete: MouseEventHandler<HTMLButtonElement> = (args) =>
|
||||
const handleDelete = (): void =>
|
||||
{
|
||||
args.preventDefault();
|
||||
args.stopPropagation();
|
||||
|
||||
const removeIndex: number[] = [collection.timestamp, ...indices.slice(1)];
|
||||
|
||||
if (deletePrompt)
|
||||
@@ -45,6 +43,26 @@ export default function TabView({ tab, indices, dragOverlay }: TabViewProps): Re
|
||||
removeItem(...removeIndex);
|
||||
};
|
||||
|
||||
const handleEdit = (): void =>
|
||||
{
|
||||
if (collectionId < 0)
|
||||
return;
|
||||
|
||||
const updateTab = async (updatedTab: TabItem): Promise<void> =>
|
||||
{
|
||||
const collection: CollectionItem = collections!.find(i => i.timestamp === collectionId)!;
|
||||
|
||||
if (indices.length > 2)
|
||||
(collection.items[indices[1]] as GroupItem).items[indices[2]] = updatedTab;
|
||||
else
|
||||
collection.items[indices[1]] = updatedTab;
|
||||
|
||||
await updateCollection(collection, collection.timestamp);
|
||||
};
|
||||
|
||||
dialog.pushCustom(<TabEditDialog tab={ tab } onSave={ updateTab } />);
|
||||
};
|
||||
|
||||
const handleClick: MouseEventHandler<HTMLAnchorElement> = (args) =>
|
||||
{
|
||||
args.preventDefault();
|
||||
@@ -91,12 +109,10 @@ export default function TabView({ tab, indices, dragOverlay }: TabViewProps): Re
|
||||
</Caption1>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip relationship="label" content={ i18n.t("tabs.delete") }>
|
||||
<Button
|
||||
className={ mergeClasses(cls.deleteButton, showToolbar === true && cls.showDeleteButton) }
|
||||
appearance="subtle" icon={ <Dismiss20Regular /> }
|
||||
onClick={ handleDelete } />
|
||||
</Tooltip>
|
||||
<TabMoreButton
|
||||
className={ mergeClasses(cls.deleteButton, showToolbar === true && cls.showDeleteButton) }
|
||||
onEdit={ handleEdit }
|
||||
onDelete={ handleDelete } />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
@@ -107,4 +123,5 @@ export type TabViewProps =
|
||||
tab: TabItem;
|
||||
indices: number[];
|
||||
dragOverlay?: boolean;
|
||||
collectionId: number;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { getCollectionTitle } from "@/entrypoints/sidepanel/utils/getCollectionT
|
||||
import useSettings from "@/hooks/useSettings";
|
||||
import { TabItem } from "@/models/CollectionModels";
|
||||
import { Button, Caption1, makeStyles, mergeClasses, Subtitle2, tokens, Tooltip } from "@fluentui/react-components";
|
||||
import { Add20Filled, Add20Regular, bundleIcon } from "@fluentui/react-icons";
|
||||
import { Add20Filled, Add20Regular, bundleIcon, EyeOff16Regular } from "@fluentui/react-icons";
|
||||
import CollectionContext, { CollectionContextType } from "../../contexts/CollectionContext";
|
||||
import { useCollections } from "../../contexts/CollectionsProvider";
|
||||
import CollectionMoreButton from "./CollectionMoreButton";
|
||||
@@ -23,7 +23,7 @@ export default function CollectionHeader({ dragHandleRef, dragHandleProps }: Col
|
||||
|
||||
const handleAddSelected = async () =>
|
||||
{
|
||||
const [newTabs, skipCount] = await getTabsToSaveAsync();
|
||||
const [newTabs, skipCount] = await getTabsToSaveAsync(true);
|
||||
|
||||
if (newTabs.length > 0)
|
||||
await updateCollection({
|
||||
@@ -45,9 +45,12 @@ export default function CollectionHeader({ dragHandleRef, dragHandleProps }: Col
|
||||
content={ getCollectionTitle(collection) }
|
||||
positioning="above-start"
|
||||
>
|
||||
<Subtitle2 truncate wrap={ false } className={ cls.titleText }>
|
||||
{ getCollectionTitle(collection) }
|
||||
</Subtitle2>
|
||||
<div className={ cls.titleContainer }>
|
||||
{ collection.hidden && <EyeOff16Regular /> }
|
||||
<Subtitle2 truncate wrap={ false } className={ cls.titleText }>
|
||||
{ getCollectionTitle(collection) }
|
||||
</Subtitle2>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<Caption1>
|
||||
@@ -112,5 +115,11 @@ const useStyles = makeStyles({
|
||||
showToolbar:
|
||||
{
|
||||
display: "flex"
|
||||
},
|
||||
titleContainer:
|
||||
{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: tokens.spacingHorizontalS
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,6 +22,8 @@ export default function CollectionMoreButton({ onAddSelected, onOpenChange }: Co
|
||||
const EditIcon = ic.bundleIcon(ic.Edit20Filled, ic.Edit20Regular);
|
||||
const DeleteIcon = ic.bundleIcon(ic.Delete20Filled, ic.Delete20Regular);
|
||||
const BookmarkIcon = ic.bundleIcon(ic.BookmarkAdd20Filled, ic.BookmarkAdd20Regular);
|
||||
const ShowIcon = ic.bundleIcon(ic.Eye20Filled, ic.Eye20Regular);
|
||||
const HideIcon = ic.bundleIcon(ic.EyeOff20Filled, ic.EyeOff20Regular);
|
||||
|
||||
const dangerCls = useDangerStyles();
|
||||
|
||||
@@ -39,6 +41,11 @@ export default function CollectionMoreButton({ onAddSelected, onOpenChange }: Co
|
||||
removeItem(collection.timestamp);
|
||||
};
|
||||
|
||||
const toggleHidden = () =>
|
||||
{
|
||||
updateCollection({ ...collection, hidden: !collection.hidden }, collection.timestamp);
|
||||
};
|
||||
|
||||
const handleEdit = () =>
|
||||
dialog.pushCustom(
|
||||
<EditDialog
|
||||
@@ -82,6 +89,9 @@ export default function CollectionMoreButton({ onAddSelected, onOpenChange }: Co
|
||||
<MenuItem icon={ <EditIcon /> } onClick={ handleEdit }>
|
||||
{ i18n.t("collections.menu.edit") }
|
||||
</MenuItem>
|
||||
<MenuItem icon={ collection.hidden ? <ShowIcon /> : <HideIcon /> } onClick={ toggleHidden }>
|
||||
{ collection.hidden ? i18n.t("collections.menu.unhide") : i18n.t("collections.menu.hide") }
|
||||
</MenuItem>
|
||||
<MenuItem icon={ <DeleteIcon /> } className={ dangerCls.menuItem } onClick={ handleDelete }>
|
||||
{ i18n.t("collections.menu.delete") }
|
||||
</MenuItem>
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function GroupMoreMenu(): ReactElement
|
||||
|
||||
const handleAddSelected = async () =>
|
||||
{
|
||||
const [newTabs, skipCount] = await getTabsToSaveAsync();
|
||||
const [newTabs, skipCount] = await getTabsToSaveAsync(true);
|
||||
|
||||
if (newTabs.length > 0)
|
||||
await updateGroup({
|
||||
|
||||
@@ -51,5 +51,9 @@ export const useStyles_CollectionListView = makeStyles({
|
||||
{
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(360px, 1fr))"
|
||||
}
|
||||
},
|
||||
compactList:
|
||||
{
|
||||
alignItems: "baseline"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,10 +18,10 @@ import CollectionContext from "../../contexts/CollectionContext";
|
||||
import { useCollections } from "../../contexts/CollectionsProvider";
|
||||
import applyReorder from "../../utils/dnd/applyReorder";
|
||||
import { collisionDetector } from "../../utils/dnd/collisionDetector";
|
||||
import { snapHandleToCursor } from "../../utils/dnd/snapHandleToCursor";
|
||||
import { useStyles_CollectionListView } from "./CollectionListView.styles";
|
||||
import SearchBar from "./SearchBar";
|
||||
import StorageCapacityIssueMessage from "./messages/StorageCapacityIssueMessage";
|
||||
import { snapHandleToCursor } from "../../utils/dnd/snapHandleToCursor";
|
||||
|
||||
export default function CollectionListView(): ReactElement
|
||||
{
|
||||
@@ -30,17 +30,19 @@ export default function CollectionListView(): ReactElement
|
||||
const [sortMode, setSortMode] = useSettings("sortMode");
|
||||
const [query, setQuery] = useState<string>("");
|
||||
const [colors, setColors] = useState<CollectionFilterType["colors"]>([]);
|
||||
const [showHidden, setShowHidden] = useState<boolean>(false);
|
||||
const [compactView] = useSettings("compactView");
|
||||
|
||||
const [active, setActive] = useState<DndItem | null>(null);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(MouseSensor, { activationConstraint: { delay: 10, tolerance: 20 } }),
|
||||
useSensor(MouseSensor, { activationConstraint: { delay: 150, tolerance: 20 } }),
|
||||
useSensor(TouchSensor, { activationConstraint: { delay: 300, tolerance: 20 } })
|
||||
);
|
||||
|
||||
const resultList = useMemo(
|
||||
() => sortCollections(filterCollections(collections, { query, colors }), sortMode),
|
||||
[query, colors, sortMode, collections]
|
||||
() => sortCollections(filterCollections(collections, { query, colors, showHidden }), sortMode),
|
||||
[query, colors, sortMode, collections, showHidden]
|
||||
);
|
||||
|
||||
const cls = useStyles_CollectionListView();
|
||||
@@ -49,6 +51,13 @@ export default function CollectionListView(): ReactElement
|
||||
{
|
||||
setQuery("");
|
||||
setColors([]);
|
||||
setShowHidden(false);
|
||||
}, []);
|
||||
|
||||
const updateFilter = useCallback((newColors: CollectionFilterType["colors"], newShowHidden: boolean) =>
|
||||
{
|
||||
setColors(newColors);
|
||||
setShowHidden(newShowHidden);
|
||||
}, []);
|
||||
|
||||
const handleDragStart = (event: DragStartEvent): void =>
|
||||
@@ -87,8 +96,9 @@ export default function CollectionListView(): ReactElement
|
||||
<article className={ cls.root }>
|
||||
<SearchBar
|
||||
query={ query } onQueryChange={ setQuery }
|
||||
filter={ colors } onFilterChange={ setColors }
|
||||
filter={ colors } onFilterChange={ updateFilter }
|
||||
sort={ sortMode } onSortChange={ setSortMode }
|
||||
showHidden={ showHidden }
|
||||
onReset={ resetFilter } />
|
||||
|
||||
<CtaMessage className={ cls.msgBar } />
|
||||
@@ -105,7 +115,7 @@ export default function CollectionListView(): ReactElement
|
||||
</Button>
|
||||
</div>
|
||||
:
|
||||
<section className={ mergeClasses(cls.collectionList, !tilesView && cls.listView) }>
|
||||
<section className={ mergeClasses(cls.collectionList, !tilesView && cls.listView, !!(!tilesView && compactView) && cls.compactList) }>
|
||||
<DndContext
|
||||
sensors={ sensors }
|
||||
collisionDetection={ collisionDetector(!tilesView) }
|
||||
@@ -118,7 +128,7 @@ export default function CollectionListView(): ReactElement
|
||||
strategy={ tilesView ? verticalListSortingStrategy : rectSortingStrategy }
|
||||
>
|
||||
{ resultList.map((collection, index) =>
|
||||
<CollectionView key={ index } collection={ collection } index={ index } />
|
||||
<CollectionView key={ index } collection={ collection } index={ index } compact={ compactView } />
|
||||
) }
|
||||
</SortableContext>
|
||||
|
||||
@@ -135,9 +145,9 @@ export default function CollectionListView(): ReactElement
|
||||
} }
|
||||
>
|
||||
{ active.item.type === "group" ?
|
||||
<GroupView group={ active.item } indices={ [-1] } dragOverlay />
|
||||
<GroupView group={ active.item } indices={ [-1] } collectionId={ -1 } dragOverlay />
|
||||
:
|
||||
<TabView tab={ active.item } indices={ [-1] } dragOverlay />
|
||||
<TabView tab={ active.item } indices={ [-1] } collectionId={ -1 } dragOverlay />
|
||||
}
|
||||
</CollectionContext.Provider>
|
||||
:
|
||||
|
||||
@@ -3,32 +3,48 @@ import * as fui from "@fluentui/react-components";
|
||||
import * as ic from "@fluentui/react-icons";
|
||||
import { CollectionFilterType } from "../../utils/filterCollections";
|
||||
|
||||
export default function FilterCollectionsButton({ value, onChange }: FilterCollectionsButtonProps): React.ReactElement
|
||||
export default function FilterCollectionsButton({ value, onChange, showHidden }: FilterCollectionsButtonProps): React.ReactElement
|
||||
{
|
||||
const cls = useStyles();
|
||||
const colorCls = useGroupColors();
|
||||
|
||||
const ColorFilterIcon = ic.bundleIcon(ic.Color20Filled, ic.Color20Regular);
|
||||
const FilterIcon = ic.bundleIcon(ic.Filter20Filled, ic.Filter20Regular);
|
||||
const ColorIcon = ic.bundleIcon(ic.Circle20Filled, ic.CircleHalfFill20Regular);
|
||||
const NoColorIcon = ic.bundleIcon(ic.CircleOffFilled, ic.CircleOffRegular);
|
||||
const AnyColorIcon = ic.bundleIcon(ic.PhotoFilter20Filled, ic.PhotoFilter20Regular);
|
||||
const HiddenIcon = ic.bundleIcon(ic.EyeOff20Filled, ic.EyeOff20Regular);
|
||||
|
||||
const values: Record<string, string[]> = useMemo(() => ({
|
||||
default: !value || value.length < 1 ? ["any"] : [],
|
||||
colors: value || [],
|
||||
hidden: showHidden ? ["show"] : []
|
||||
}), [value, showHidden]);
|
||||
|
||||
const onCheckedValueChange = useCallback((_: fui.MenuCheckedValueChangeEvent, e: fui.MenuCheckedValueChangeData) =>
|
||||
{
|
||||
if (e.name === "hidden")
|
||||
onChange?.(value ?? [], e.checkedItems.includes("show"));
|
||||
else
|
||||
onChange?.(e.checkedItems.includes("any") ? [] : e.checkedItems as CollectionFilterType["colors"], showHidden ?? false);
|
||||
}, [onChange, showHidden, value]);
|
||||
|
||||
return (
|
||||
<fui.Menu
|
||||
checkedValues={ !value || value.length < 1 ? { default: ["any"] } : { colors: value } }
|
||||
onCheckedValueChange={ (_, e) =>
|
||||
onChange?.(e.checkedItems.includes("any") ? [] : e.checkedItems as CollectionFilterType["colors"])
|
||||
}
|
||||
checkedValues={ values }
|
||||
onCheckedValueChange={ onCheckedValueChange }
|
||||
>
|
||||
|
||||
<fui.Tooltip relationship="label" content={ i18n.t("main.list.searchbar.filter") }>
|
||||
<fui.MenuTrigger disableButtonEnhancement>
|
||||
<fui.Button appearance="subtle" icon={ <ColorFilterIcon /> } />
|
||||
<fui.Button appearance="subtle" icon={ <FilterIcon /> } />
|
||||
</fui.MenuTrigger>
|
||||
</fui.Tooltip>
|
||||
|
||||
<fui.MenuPopover>
|
||||
<fui.MenuList>
|
||||
<fui.MenuItemCheckbox name="hidden" value="show" icon={ <HiddenIcon /> }>
|
||||
{ i18n.t("main.list.searchbar.show_hidden") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="default" value="any" icon={ <AnyColorIcon /> }>
|
||||
{ i18n.t("colors.any") }
|
||||
</fui.MenuItemCheckbox>
|
||||
@@ -60,7 +76,8 @@ export default function FilterCollectionsButton({ value, onChange }: FilterColle
|
||||
export type FilterCollectionsButtonProps =
|
||||
{
|
||||
value?: CollectionFilterType["colors"];
|
||||
onChange?: (value: CollectionFilterType["colors"]) => void;
|
||||
showHidden?: boolean;
|
||||
onChange?: (value: CollectionFilterType["colors"], showHidden: boolean) => void;
|
||||
};
|
||||
|
||||
const useStyles = fui.makeStyles({
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function SearchBar(props: SearchBarProps): React.ReactElement
|
||||
<Button appearance="subtle" icon={ <ResetIcon /> } onClick={ props.onReset } />
|
||||
</Tooltip>
|
||||
}
|
||||
<FilterCollectionsButton value={ props.filter } onChange={ props.onFilterChange } />
|
||||
<FilterCollectionsButton value={ props.filter } onChange={ props.onFilterChange } showHidden={ props.showHidden } />
|
||||
<SortCollectionsButton value={ props.sort } onChange={ props.onSortChange } />
|
||||
</>
|
||||
} />
|
||||
@@ -37,8 +37,9 @@ export type SearchBarProps =
|
||||
query?: string;
|
||||
onQueryChange?: (query: string) => void;
|
||||
filter?: CollectionFilterType["colors"];
|
||||
onFilterChange?: (filter: CollectionFilterType["colors"]) => void;
|
||||
onFilterChange?: (filter: CollectionFilterType["colors"], showHidden: boolean) => void;
|
||||
sort?: CollectionSortMode;
|
||||
showHidden?: boolean;
|
||||
onSortChange?: (sort: CollectionSortMode) => void;
|
||||
onReset?: () => void;
|
||||
};
|
||||
|
||||
@@ -11,18 +11,32 @@ import { ReactElement } from "react";
|
||||
export default function MoreButton(): ReactElement
|
||||
{
|
||||
const [tilesView, setTilesView] = useSettings("tilesView");
|
||||
const [compactView, setCompactView] = useSettings("compactView");
|
||||
|
||||
const SettingsIcon: ic.FluentIcon = ic.bundleIcon(ic.Settings20Filled, ic.Settings20Regular);
|
||||
const ViewIcon: ic.FluentIcon = ic.bundleIcon(ic.GridKanban20Filled, ic.GridKanban20Regular);
|
||||
const GridIcon: ic.FluentIcon = ic.bundleIcon(ic.GridKanban20Filled, ic.GridKanban20Regular);
|
||||
const CompactIcon: ic.FluentIcon = ic.bundleIcon(ic.ArrowMinimizeVerticalFilled, ic.ArrowMinimizeVerticalRegular);
|
||||
const FeedbackIcon: ic.FluentIcon = ic.bundleIcon(ic.PersonFeedback20Filled, ic.PersonFeedback20Regular);
|
||||
const LearnIcon: ic.FluentIcon = ic.bundleIcon(ic.QuestionCircle20Filled, ic.QuestionCircle20Regular);
|
||||
const BmcIcon: ic.FluentIcon = ic.bundleIcon(BuyMeACoffee20Filled, BuyMeACoffee20Regular);
|
||||
|
||||
const checkedValues = useMemo(() => ({
|
||||
view: [
|
||||
tilesView ? "tiles" : "",
|
||||
compactView ? "compact" : ""
|
||||
]
|
||||
}), [tilesView, compactView]);
|
||||
|
||||
const onCheckedValueChange = (_: unknown, e: fui.MenuCheckedValueChangeData) =>
|
||||
{
|
||||
setTilesView(e.checkedItems.includes("tiles"));
|
||||
setCompactView(e.checkedItems.includes("compact"));
|
||||
};
|
||||
|
||||
return (
|
||||
<fui.Menu
|
||||
hasIcons hasCheckmarks
|
||||
checkedValues={ { tilesView: tilesView ? ["true"] : [] } }
|
||||
onCheckedValueChange={ (_, e) => setTilesView(e.checkedItems.length > 0) }
|
||||
checkedValues={ checkedValues } onCheckedValueChange={ onCheckedValueChange }
|
||||
>
|
||||
<fui.Tooltip relationship="label" content={ i18n.t("common.tooltips.more") }>
|
||||
<fui.MenuTrigger disableButtonEnhancement>
|
||||
@@ -36,9 +50,12 @@ export default function MoreButton(): ReactElement
|
||||
<fui.MenuItem icon={ <SettingsIcon /> } onClick={ () => browser.runtime.openOptionsPage() }>
|
||||
{ i18n.t("options_page.title") }
|
||||
</fui.MenuItem>
|
||||
<fui.MenuItemCheckbox name="tilesView" value="true" icon={ <ViewIcon /> }>
|
||||
<fui.MenuItemCheckbox name="view" value="tiles" icon={ <GridIcon /> }>
|
||||
{ i18n.t("main.header.menu.tiles_view") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="view" value="compact" icon={ <CompactIcon /> }>
|
||||
{ i18n.t("main.header.menu.compact_view") }
|
||||
</fui.MenuItemCheckbox>
|
||||
|
||||
<fui.MenuDivider />
|
||||
|
||||
|
||||
@@ -9,13 +9,16 @@ export default function filterCollections(
|
||||
if (!collections || collections.length < 1)
|
||||
return [];
|
||||
|
||||
if (!filter.query && filter.colors.length < 1)
|
||||
if (!filter.query && filter.colors.length < 1 && filter.showHidden)
|
||||
return collections;
|
||||
|
||||
const query: string = filter.query.toLocaleLowerCase();
|
||||
|
||||
return collections.filter(collection =>
|
||||
{
|
||||
if (filter.showHidden === false && collection.hidden === true)
|
||||
return false;
|
||||
|
||||
let querySatisfied: boolean = query.length < 1 ||
|
||||
getCollectionTitle(collection).toLocaleLowerCase().includes(query);
|
||||
let colorSatisfied: boolean = filter.colors.length < 1 ||
|
||||
@@ -62,4 +65,5 @@ export type CollectionFilterType =
|
||||
{
|
||||
query: string;
|
||||
colors: (`${Browser.tabGroups.Color}` | "none")[];
|
||||
showHidden: boolean;
|
||||
};
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Add empty group"
|
||||
export_bookmarks: "Export to bookmarks"
|
||||
edit: "Edit collection"
|
||||
hide: "Hide collection"
|
||||
unhide: "Unhide collection"
|
||||
|
||||
groups:
|
||||
title: "Group"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Edit collection"
|
||||
edit_group: "Edit group"
|
||||
edit_tab: "Edit tab"
|
||||
new_group: "New group"
|
||||
new_collection: "New collection"
|
||||
collection_title: "Title"
|
||||
color: "Color"
|
||||
url_error: "URL is required"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Create new collection"
|
||||
menu:
|
||||
tiles_view: "Tiles view"
|
||||
compact_view: "Compact view"
|
||||
changelog: "What's new?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Search"
|
||||
filter: "Filter"
|
||||
show_hidden: "Show hidden"
|
||||
sort:
|
||||
title: "Sort"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Agregar grupo vacío"
|
||||
export_bookmarks: "Exportar a marcadores"
|
||||
edit: "Editar colección"
|
||||
hide: "Ocultar colección"
|
||||
unhide: "Mostrar colección"
|
||||
|
||||
groups:
|
||||
title: "Grupo"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Editar colección"
|
||||
edit_group: "Editar grupo"
|
||||
edit_tab: "Editar pestaña"
|
||||
new_group: "Nuevo grupo"
|
||||
new_collection: "Nueva colección"
|
||||
collection_title: "Título"
|
||||
color: "Color"
|
||||
url_error: "La URL es obligatoria"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Crear nueva colección"
|
||||
menu:
|
||||
tiles_view: "Vista de mosaicos"
|
||||
compact_view: "Vista compacta"
|
||||
changelog: "¿Qué hay de nuevo?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Buscar"
|
||||
filter: "Filtrar"
|
||||
show_hidden: "Mostrar ocultas"
|
||||
sort:
|
||||
title: "Ordenar"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Aggiungi gruppo vuoto"
|
||||
export_bookmarks: "Esporta nei segnalibri"
|
||||
edit: "Modifica collezione"
|
||||
hide: "Nascondi collezione"
|
||||
unhide: "Mostra collezione"
|
||||
|
||||
groups:
|
||||
title: "Gruppo"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Modifica collezione"
|
||||
edit_group: "Modifica gruppo"
|
||||
edit_tab: "Modifica scheda"
|
||||
new_group: "Nuovo gruppo"
|
||||
new_collection: "Nuova collezione"
|
||||
collection_title: "Titolo"
|
||||
color: "Colore"
|
||||
url_error: "L'URL è obbligatorio"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Crea nuova collezione"
|
||||
menu:
|
||||
tiles_view: "Vista a riquadri"
|
||||
compact_view: "Vista compatta"
|
||||
changelog: "Cosa c'è di nuovo?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Cerca"
|
||||
filter: "Filtra"
|
||||
show_hidden: "Mostra nascoste"
|
||||
sort:
|
||||
title: "Ordina"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Dodaj pustą grupę"
|
||||
export_bookmarks: "Eksportuj do zakładek"
|
||||
edit: "Edytuj kolekcję"
|
||||
hide: "Ukryj kolekcję"
|
||||
unhide: "Pokaż kolekcję"
|
||||
|
||||
groups:
|
||||
title: "Grupa"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Edytuj kolekcję"
|
||||
edit_group: "Edytuj grupę"
|
||||
edit_tab: "Edytuj zakładkę"
|
||||
new_group: "Nowa grupa"
|
||||
new_collection: "Nowa kolekcja"
|
||||
collection_title: "Nazwij"
|
||||
color: "Kolor"
|
||||
url_error: "URL jest wymagany"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Utwórz nową kolekcję"
|
||||
menu:
|
||||
tiles_view: "Kafelki"
|
||||
compact_view: "Widok kompaktowy"
|
||||
changelog: "Co nowego?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Szukaj"
|
||||
filter: "Filtr"
|
||||
show_hidden: "Pokaż ukryte"
|
||||
sort:
|
||||
title: "Sortowanie"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Adicionar grupo vazio"
|
||||
export_bookmarks: "Exportar para favoritos"
|
||||
edit: "Editar coleção"
|
||||
hide: "Ocultar coleção"
|
||||
unhide: "Mostrar coleção"
|
||||
|
||||
groups:
|
||||
title: "Grupo"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Editar coleção"
|
||||
edit_group: "Editar grupo"
|
||||
edit_tab: "Editar aba"
|
||||
new_group: "Novo grupo"
|
||||
new_collection: "Nova coleção"
|
||||
collection_title: "Título"
|
||||
color: "Cor"
|
||||
url_error: "A URL é obrigatória"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Criar nova coleção"
|
||||
menu:
|
||||
tiles_view: "Visualização em blocos"
|
||||
compact_view: "Visualização compacta"
|
||||
changelog: "O que há de novo?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Pesquisar"
|
||||
filter: "Filtrar"
|
||||
show_hidden: "Mostrar ocultas"
|
||||
sort:
|
||||
title: "Ordenar"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Добавить пустую группу"
|
||||
export_bookmarks: "Экспортировать в закладки"
|
||||
edit: "Редактировать коллекцию"
|
||||
hide: "Скрыть коллекцию"
|
||||
unhide: "Показать коллекцию"
|
||||
|
||||
groups:
|
||||
title: "Группа"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Редактировать коллекцию"
|
||||
edit_group: "Редактировать группу"
|
||||
edit_tab: "Редактировать вкладку"
|
||||
new_group: "Новая группа"
|
||||
new_collection: "Новая коллекция"
|
||||
collection_title: "Название"
|
||||
color: "Цвет"
|
||||
url_error: "URL является обязательным"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Создать новую коллекцию"
|
||||
menu:
|
||||
tiles_view: "Плитки"
|
||||
compact_view: "Компактный вид"
|
||||
changelog: "Что нового?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Поиск"
|
||||
filter: "Фильтр"
|
||||
show_hidden: "Показать скрытые"
|
||||
sort:
|
||||
title: "Сортировка"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "Додати порожню групу"
|
||||
export_bookmarks: "Експортувати в закладки"
|
||||
edit: "Редагувати колекцію"
|
||||
hide: "Приховати колекцію"
|
||||
unhide: "Показати колекцію"
|
||||
|
||||
groups:
|
||||
title: "Група"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "Редагувати колекцію"
|
||||
edit_group: "Редагувати групу"
|
||||
edit_tab: "Редагувати вкладку"
|
||||
new_group: "Нова група"
|
||||
new_collection: "Нова колекція"
|
||||
collection_title: "Назва"
|
||||
color: "Колір"
|
||||
url_error: "URL є обов'язковим"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "Створити нову колекцію"
|
||||
menu:
|
||||
tiles_view: "Плитки"
|
||||
compact_view: "Компактний вид"
|
||||
changelog: "Що нового?"
|
||||
list:
|
||||
searchbar:
|
||||
title: "Пошук"
|
||||
filter: "Фільтр"
|
||||
show_hidden: "Показати приховані"
|
||||
sort:
|
||||
title: "Сортування"
|
||||
options:
|
||||
|
||||
@@ -184,6 +184,8 @@ collections:
|
||||
add_group: "添加空分组"
|
||||
export_bookmarks: "导出到书签"
|
||||
edit: "编辑收藏"
|
||||
hide: "隐藏收藏"
|
||||
unhide: "显示收藏"
|
||||
|
||||
groups:
|
||||
title: "分组"
|
||||
@@ -219,21 +221,25 @@ dialogs:
|
||||
title:
|
||||
edit_collection: "编辑收藏"
|
||||
edit_group: "编辑分组"
|
||||
edit_tab: "编辑标签页"
|
||||
new_group: "新分组"
|
||||
new_collection: "新收藏"
|
||||
collection_title: "标题"
|
||||
color: "颜色"
|
||||
url_error: "需要 URL"
|
||||
|
||||
main:
|
||||
header:
|
||||
create_collection: "创建新收藏"
|
||||
menu:
|
||||
tiles_view: "平铺视图"
|
||||
compact_view: "紧凑视图"
|
||||
changelog: "更新内容"
|
||||
list:
|
||||
searchbar:
|
||||
title: "搜索"
|
||||
filter: "筛选"
|
||||
show_hidden: "显示隐藏项"
|
||||
sort:
|
||||
title: "排序"
|
||||
options:
|
||||
|
||||
@@ -30,6 +30,7 @@ export type CollectionItem =
|
||||
title?: string;
|
||||
color?: `${Browser.tabGroups.Color}`;
|
||||
items: (TabItem | GroupItem)[];
|
||||
hidden?: boolean;
|
||||
};
|
||||
|
||||
export type GraphicsStorage = Record<string, GraphicsItem>;
|
||||
|
||||
Generated
+625
-605
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tabs-aside",
|
||||
"private": true,
|
||||
"version": "3.2.3",
|
||||
"version": "3.3.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
@@ -16,27 +16,27 @@
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fluentui/react-components": "^9.72.8",
|
||||
"@fluentui/react-components": "^9.72.9",
|
||||
"@fluentui/react-icons": "^2.0.316",
|
||||
"@webext-core/messaging": "^2.3.0",
|
||||
"@wxt-dev/analytics": "^0.5.1",
|
||||
"@wxt-dev/i18n": "^0.2.4",
|
||||
"lzutf8": "^0.6.3",
|
||||
"react": "^19.2.1",
|
||||
"react-dom": "^19.2.1"
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/css": "^0.14.1",
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@eslint/json": "^0.14.0",
|
||||
"@stylistic/eslint-plugin": "^5.6.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@wxt-dev/module-react": "^1.1.5",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.49.0",
|
||||
"typescript-eslint": "^8.51.0",
|
||||
"wxt": "^0.20.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { settings } from "./settings";
|
||||
|
||||
export async function getTabsToSaveAsync(): Promise<[Browser.tabs.Tab[], number]>
|
||||
export async function getTabsToSaveAsync(forceSelected: boolean = false): Promise<[Browser.tabs.Tab[], number]>
|
||||
{
|
||||
let tabs: Browser.tabs.Tab[] = await browser.tabs.query({
|
||||
currentWindow: true,
|
||||
highlighted: true
|
||||
});
|
||||
|
||||
if (tabs.length < 2)
|
||||
if (!forceSelected && tabs.length < 2)
|
||||
{
|
||||
const ignorePinned: boolean = await settings.ignorePinned.getValue();
|
||||
tabs = await browser.tabs.query({
|
||||
|
||||
@@ -103,5 +103,13 @@ export const settings = {
|
||||
fallback: true,
|
||||
version: 1
|
||||
}
|
||||
),
|
||||
|
||||
compactView: storage.defineItem<boolean>(
|
||||
"sync:compactView",
|
||||
{
|
||||
fallback: false,
|
||||
version: 1
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user