mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 11:08:47 +02:00
Compare commits
5 Commits
ci-fix-ios
...
fix/359-36
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcfa34ca05 | ||
|
|
f1124c4112 | ||
|
|
a4c8259a02 | ||
|
|
fc93a39164 | ||
|
|
9b588c50bf |
4
apps/desktop/package-lock.json
generated
4
apps/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Item, ItemReference, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { RefObject, useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { ActionSheetRef } from "react-native-actions-sheet";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import {
|
||||
PresentSheetOptions,
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import List from "../../list";
|
||||
import SheetProvider from "../../sheet-provider";
|
||||
import { Button, ButtonProps } from "../../ui/button";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
|
||||
type RelationsListProps = {
|
||||
actionSheetRef: RefObject<ActionSheetRef>;
|
||||
close?: () => void;
|
||||
update?: (options: PresentSheetOptions) => void;
|
||||
item: { id: string; type: string };
|
||||
referenceType: string;
|
||||
relationType: "to" | "from";
|
||||
title: string;
|
||||
button?: ButtonProps;
|
||||
onAdd: () => void;
|
||||
};
|
||||
|
||||
const IconsByType = {
|
||||
reminder: "bell"
|
||||
};
|
||||
|
||||
export const RelationsList = ({
|
||||
actionSheetRef,
|
||||
item,
|
||||
referenceType,
|
||||
relationType,
|
||||
title,
|
||||
button,
|
||||
onAdd
|
||||
}: RelationsListProps) => {
|
||||
const updater = useRelationStore((state) => state.updater);
|
||||
const { colors } = useThemeColors();
|
||||
const [items, setItems] = useState<VirtualizedGrouping<Item>>();
|
||||
const hasNoRelations = !items || items?.placeholders?.length === 0;
|
||||
|
||||
useEffect(() => {
|
||||
db.relations?.[relationType]?.(
|
||||
{ id: item?.id, type: item?.type } as ItemReference,
|
||||
referenceType as any
|
||||
)
|
||||
.selector.sorted({
|
||||
sortBy: "dateEdited",
|
||||
sortDirection: "desc"
|
||||
})
|
||||
.then((grouped) => {
|
||||
setTimeout(() => {
|
||||
setItems(grouped);
|
||||
}, 300);
|
||||
});
|
||||
}, [relationType, referenceType, item?.id, item?.type, updater]);
|
||||
|
||||
return (
|
||||
<View style={{ paddingHorizontal: DefaultAppStyles.GAP, height: "100%" }}>
|
||||
<SheetProvider context="local" />
|
||||
<DialogHeader
|
||||
title={title}
|
||||
button={hasNoRelations ? undefined : button}
|
||||
/>
|
||||
{hasNoRelations ? (
|
||||
<View
|
||||
style={{
|
||||
height: "85%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={IconsByType[referenceType as keyof typeof IconsByType]}
|
||||
size={60}
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
<Paragraph>{strings.noLinksFound()}</Paragraph>
|
||||
<Button
|
||||
onPress={() => {
|
||||
onAdd?.();
|
||||
}}
|
||||
fontSize={AppFontSize.sm}
|
||||
// width="100%"
|
||||
type="inverted"
|
||||
icon="plus"
|
||||
title={strings.addItem(
|
||||
referenceType as "notebook" | "tag" | "reminder" | "note"
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<List
|
||||
data={items}
|
||||
loading={false}
|
||||
groupType={
|
||||
referenceType === "note"
|
||||
? "notes"
|
||||
: referenceType === "tag"
|
||||
? "tags"
|
||||
: referenceType === "notebook"
|
||||
? "notebooks"
|
||||
: referenceType === "reminder"
|
||||
? "reminders"
|
||||
: "notes"
|
||||
}
|
||||
dataType={referenceType as any}
|
||||
isRenderedInActionSheet={true}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
RelationsList.present = ({
|
||||
reference,
|
||||
referenceType,
|
||||
relationType,
|
||||
title,
|
||||
button,
|
||||
onAdd
|
||||
}: {
|
||||
reference: { id: string; type: string };
|
||||
referenceType: string;
|
||||
relationType: "to" | "from";
|
||||
title: string;
|
||||
button?: ButtonProps;
|
||||
onAdd: () => void;
|
||||
}) => {
|
||||
presentSheet({
|
||||
component: (ref, close, update) => (
|
||||
<RelationsList
|
||||
actionSheetRef={ref}
|
||||
close={close}
|
||||
update={update}
|
||||
item={reference}
|
||||
referenceType={referenceType}
|
||||
relationType={relationType}
|
||||
title={title}
|
||||
button={button}
|
||||
onAdd={onAdd}
|
||||
/>
|
||||
)
|
||||
});
|
||||
};
|
||||
@@ -45,11 +45,11 @@ import ExportNotesSheet from "../components/sheets/export-notes";
|
||||
import PaywallSheet from "../components/sheets/paywall";
|
||||
import PublishNoteSheet from "../components/sheets/publish-note";
|
||||
import { ReferencesList } from "../components/sheets/references";
|
||||
import { RelationsList } from "../components/sheets/relations-list/index";
|
||||
import { useSideBarDraggingStore } from "../components/side-menu/dragging-store";
|
||||
import { ButtonProps } from "../components/ui/button";
|
||||
import AddReminder from "../screens/add-reminder";
|
||||
import { useTabStore } from "../screens/editor/tiptap/use-tab-store";
|
||||
import RelationsList from "../screens/relations-list";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
@@ -1047,8 +1047,9 @@ export const useActions = ({
|
||||
title: strings.dataTypesPluralCamelCase.reminder(),
|
||||
icon: "clock-outline",
|
||||
onPress: async () => {
|
||||
close();
|
||||
RelationsList.present({
|
||||
reference: item,
|
||||
item,
|
||||
referenceType: "reminder",
|
||||
relationType: "from",
|
||||
title: strings.dataTypesPluralCamelCase.reminder(),
|
||||
@@ -1065,26 +1066,6 @@ export const useActions = ({
|
||||
}
|
||||
AddReminder.present(undefined, item);
|
||||
close();
|
||||
},
|
||||
button: {
|
||||
type: "plain",
|
||||
onPress: async () => {
|
||||
if (features && !features.activeReminders.isAllowed) {
|
||||
ToastManager.show({
|
||||
type: "info",
|
||||
message: features.activeReminders.error,
|
||||
actionText: strings.upgrade(),
|
||||
func: () => {
|
||||
PaywallSheet.present(features.activeReminders);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
AddReminder.present(undefined, item);
|
||||
close();
|
||||
},
|
||||
icon: "plus",
|
||||
iconSize: 20
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -279,6 +279,7 @@ let MoveNotes: any = null;
|
||||
let Settings: any = null;
|
||||
let ManageTags: any = null;
|
||||
let AddReminder: any = null;
|
||||
let RelationsList: any = null;
|
||||
let PayWall: any = null;
|
||||
let Wrapped: any = null;
|
||||
export const RootNavigation = () => {
|
||||
@@ -385,6 +386,15 @@ export const RootNavigation = () => {
|
||||
return AddReminder;
|
||||
}}
|
||||
/>
|
||||
|
||||
<RootStack.Screen
|
||||
name="RelationsList"
|
||||
getComponent={() => {
|
||||
RelationsList =
|
||||
RelationsList || require("../screens/relations-list").default;
|
||||
return RelationsList;
|
||||
}}
|
||||
/>
|
||||
<RootStack.Screen
|
||||
name="PayWall"
|
||||
getComponent={() => {
|
||||
|
||||
@@ -46,7 +46,6 @@ import EditorTabs from "../../../components/sheets/editor-tabs";
|
||||
import { Issue } from "../../../components/sheets/github/issue";
|
||||
import LinkNote from "../../../components/sheets/link-note";
|
||||
import PaywallSheet from "../../../components/sheets/paywall";
|
||||
import { RelationsList } from "../../../components/sheets/relations-list";
|
||||
import TableOfContents from "../../../components/sheets/toc";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
@@ -80,6 +79,7 @@ import { fluidTabsRef } from "../../../utils/global-refs";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import AddReminder from "../../add-reminder";
|
||||
import ManageTags from "../../manage-tags";
|
||||
import RelationsList from "../../relations-list";
|
||||
import { useDragState } from "../../settings/editor/state";
|
||||
import { EditorMessage, EditorProps, useEditorType } from "./types";
|
||||
import { useTabStore } from "./use-tab-store";
|
||||
@@ -466,7 +466,7 @@ export const useEditorEvents = (
|
||||
const note = await db.notes.note(noteId);
|
||||
if (!note) return;
|
||||
RelationsList.present({
|
||||
reference: note as any,
|
||||
item: note as any,
|
||||
referenceType: "reminder",
|
||||
relationType: "from",
|
||||
title: strings.dataTypesPluralCamelCase.reminder(),
|
||||
|
||||
@@ -18,8 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { resolveItems } from "@notesnook/common";
|
||||
import { Tag, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { Color, Note } from "@notesnook/core";
|
||||
import { Color, Note, Tag, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { db } from "../../common/database";
|
||||
import { FloatingButton } from "../../components/container/floating-button";
|
||||
@@ -39,10 +39,9 @@ import useNavigationStore, {
|
||||
NotesScreenParams,
|
||||
RouteName
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { setOnFirstSave } from "./common";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { rootNavigatorRef } from "../../utils/global-refs";
|
||||
import { setOnFirstSave } from "./common";
|
||||
|
||||
export interface RouteProps<T extends RouteName> extends NavigationProps<T> {
|
||||
get: (
|
||||
|
||||
142
apps/mobile/app/screens/relations-list/index.tsx
Normal file
142
apps/mobile/app/screens/relations-list/index.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Item, ItemReference, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../common/database";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import { useRelationStore } from "../../stores/use-relation-store";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
|
||||
type RelationsListProps = {
|
||||
item: Item;
|
||||
referenceType: "notebook" | "tag" | "reminder" | "note";
|
||||
relationType: "to" | "from";
|
||||
title: string;
|
||||
onAdd?: () => void;
|
||||
};
|
||||
|
||||
const IconsByType = {
|
||||
reminder: "bell"
|
||||
};
|
||||
|
||||
function RelationsList(props: NavigationProps<"RelationsList">) {
|
||||
const { item, referenceType, relationType, title, onAdd } = props.route
|
||||
.params as RelationsListProps;
|
||||
const updater = useRelationStore((state) => state.updater);
|
||||
const { colors } = useThemeColors();
|
||||
const [items, setItems] = useState<VirtualizedGrouping<Item>>();
|
||||
const hasNoRelations = !items || items?.placeholders?.length === 0;
|
||||
|
||||
useEffect(() => {
|
||||
db.relations?.[relationType]?.(
|
||||
{ id: item?.id, type: item?.type } as ItemReference,
|
||||
referenceType
|
||||
)
|
||||
.selector.sorted({
|
||||
sortBy: "dateEdited",
|
||||
sortDirection: "desc"
|
||||
})
|
||||
.then((grouped) => {
|
||||
setTimeout(() => {
|
||||
setItems(grouped);
|
||||
}, 300);
|
||||
});
|
||||
}, [relationType, referenceType, item?.id, item?.type, updater]);
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: colors.primary.background,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Header title={title} canGoBack />
|
||||
<View style={{ flex: 1 }}>
|
||||
{hasNoRelations ? (
|
||||
<View
|
||||
style={{
|
||||
height: "85%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={IconsByType[referenceType as keyof typeof IconsByType]}
|
||||
size={60}
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
<Paragraph>{strings.noLinksFound()}</Paragraph>
|
||||
<Button
|
||||
onPress={onAdd}
|
||||
fontSize={AppFontSize.sm}
|
||||
type="inverted"
|
||||
icon="plus"
|
||||
title={strings.addItem(referenceType)}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<List
|
||||
data={items}
|
||||
loading={false}
|
||||
groupType={
|
||||
referenceType === "note"
|
||||
? "notes"
|
||||
: referenceType === "tag"
|
||||
? "tags"
|
||||
: referenceType === "notebook"
|
||||
? "notebooks"
|
||||
: referenceType === "reminder"
|
||||
? "reminders"
|
||||
: "notes"
|
||||
}
|
||||
dataType={referenceType}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
RelationsList.present = ({
|
||||
item,
|
||||
relationType,
|
||||
referenceType,
|
||||
title,
|
||||
onAdd
|
||||
}: RelationsListProps) => {
|
||||
Navigation.navigate("RelationsList", {
|
||||
item,
|
||||
relationType,
|
||||
referenceType,
|
||||
title,
|
||||
onAdd
|
||||
});
|
||||
};
|
||||
|
||||
export default RelationsList;
|
||||
@@ -71,6 +71,7 @@ const routeNames = {
|
||||
Archive: "Archive",
|
||||
ManageTags: "ManageTags",
|
||||
AddReminder: "AddReminder",
|
||||
RelationsList: "RelationsList",
|
||||
PayWall: "PayWall",
|
||||
Wrapped: "Wrapped"
|
||||
};
|
||||
|
||||
@@ -108,6 +108,13 @@ export interface RouteParams extends ParamListBase {
|
||||
reminder?: Reminder;
|
||||
reference?: Note;
|
||||
};
|
||||
RelationsList: {
|
||||
item: Item;
|
||||
referenceType: "notebook" | "tag" | "reminder" | "note";
|
||||
relationType: "to" | "from";
|
||||
title: string;
|
||||
onAdd?: () => void;
|
||||
};
|
||||
Intro: GenericRouteParam;
|
||||
PayWall: {
|
||||
canGoBack?: boolean;
|
||||
|
||||
4
apps/mobile/package-lock.json
generated
4
apps/mobile/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.23",
|
||||
"version": "3.3.24",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.23",
|
||||
"version": "3.3.24",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
4
apps/web/package-lock.json
generated
4
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.19",
|
||||
"version": "3.3.20",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||
@@ -16,6 +16,7 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useDatePicker } from "@rehookify/datepicker";
|
||||
import { Box, Button, Flex, Text } from "@theme-ui/components";
|
||||
import { useState } from "react";
|
||||
@@ -31,6 +32,7 @@ type DayPickerProps = {
|
||||
export function DayPicker(props: DayPickerProps) {
|
||||
const { selected, sx, maxDate, minDate, onSelect } = props;
|
||||
const [selectedDates, onDatesChange] = useState<Date[]>([selected]);
|
||||
|
||||
const {
|
||||
data: { weekDays, months, years, calendars },
|
||||
propGetters: { dayButton, addOffset, subtractOffset, setOffset }
|
||||
@@ -52,6 +54,24 @@ export function DayPicker(props: DayPickerProps) {
|
||||
|
||||
const { month, year, days } = calendars[0];
|
||||
|
||||
const currentMonthDate = months.find((m) => m.month === month)?.$date;
|
||||
const isNextMonthBeyondMax =
|
||||
maxDate && currentMonthDate
|
||||
? new Date(
|
||||
currentMonthDate.getFullYear(),
|
||||
currentMonthDate.getMonth() + 1,
|
||||
1
|
||||
) > stripTime(maxDate)
|
||||
: false;
|
||||
const isPrevMonthBeforeMin =
|
||||
minDate && currentMonthDate
|
||||
? new Date(
|
||||
currentMonthDate.getFullYear(),
|
||||
currentMonthDate.getMonth(),
|
||||
1
|
||||
) <= stripTime(minDate)
|
||||
: false;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
@@ -66,7 +86,7 @@ export function DayPicker(props: DayPickerProps) {
|
||||
<Button
|
||||
variant="icon"
|
||||
sx={{ p: 0 }}
|
||||
{...subtractOffset({ months: 1 })}
|
||||
{...subtractOffset({ months: 1 }, { disabled: isPrevMonthBeforeMin })}
|
||||
>
|
||||
<ChevronLeft />
|
||||
</Button>
|
||||
@@ -83,9 +103,12 @@ export function DayPicker(props: DayPickerProps) {
|
||||
value={month}
|
||||
onChange={(e) => {
|
||||
const selectedOption = e.target.selectedOptions[0];
|
||||
setOffset(new Date(selectedOption.dataset.date || ""))?.onClick?.(
|
||||
e
|
||||
const d = clampDate(
|
||||
new Date(selectedOption.dataset.date || ""),
|
||||
minDate,
|
||||
maxDate
|
||||
);
|
||||
setOffset(d)?.onClick?.(e as any);
|
||||
}}
|
||||
>
|
||||
{months.map((month) => (
|
||||
@@ -112,9 +135,12 @@ export function DayPicker(props: DayPickerProps) {
|
||||
value={year}
|
||||
onChange={(e) => {
|
||||
const selectedOption = e.target.selectedOptions[0];
|
||||
setOffset(new Date(selectedOption.dataset.date || ""))?.onClick?.(
|
||||
e
|
||||
const d = clampDate(
|
||||
new Date(selectedOption.dataset.date || ""),
|
||||
minDate,
|
||||
maxDate
|
||||
);
|
||||
setOffset(d)?.onClick?.(e as any);
|
||||
}}
|
||||
>
|
||||
{years.map((year) => (
|
||||
@@ -129,7 +155,16 @@ export function DayPicker(props: DayPickerProps) {
|
||||
))}
|
||||
</select>
|
||||
</Flex>
|
||||
<Button variant="icon" sx={{ p: 0 }} {...addOffset({ months: 1 })}>
|
||||
<Button
|
||||
variant="icon"
|
||||
sx={{ p: 0 }}
|
||||
{...addOffset(
|
||||
{ months: 1 },
|
||||
{
|
||||
disabled: isNextMonthBeyondMax
|
||||
}
|
||||
)}
|
||||
>
|
||||
<ChevronRight />
|
||||
</Button>
|
||||
</Flex>
|
||||
@@ -195,3 +230,24 @@ export function DayPicker(props: DayPickerProps) {
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function clampDate(d: Date, minDate?: Date, maxDate?: Date) {
|
||||
/**
|
||||
* Strip time for accurate comparison
|
||||
*/
|
||||
const normalizedMaxDate = maxDate ? stripTime(maxDate) : null;
|
||||
const normalizedMinDate = minDate ? stripTime(minDate) : null;
|
||||
|
||||
if (normalizedMaxDate && d > normalizedMaxDate) {
|
||||
return normalizedMaxDate;
|
||||
}
|
||||
if (normalizedMinDate && d < normalizedMinDate) {
|
||||
return normalizedMinDate;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
function stripTime(date: Date) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
}
|
||||
|
||||
@@ -208,7 +208,8 @@ export const AttachFilesDialog = DialogManager.register(
|
||||
style={{
|
||||
maxHeight: 350,
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
flexDirection: "column",
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
{fileStates.map((state, index) => (
|
||||
|
||||
@@ -22,7 +22,14 @@ import Dialog from "../components/dialog";
|
||||
import { getHomeRoute, hardNavigate } from "../navigation";
|
||||
import { appVersion } from "../utils/version";
|
||||
import Config from "../utils/config";
|
||||
import { ArrowRight, Checkmark, Icon, Warn } from "../components/icons";
|
||||
import {
|
||||
ArrowRight,
|
||||
Checkmark,
|
||||
Icon,
|
||||
Warn,
|
||||
File,
|
||||
InternalLink
|
||||
} from "../components/icons";
|
||||
import { BaseDialogProps, DialogManager } from "../common/dialog-manager";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
@@ -89,7 +96,19 @@ const features: Record<FeatureKeys, Feature> = {
|
||||
)
|
||||
}
|
||||
]
|
||||
: [],
|
||||
: [
|
||||
{
|
||||
icon: File,
|
||||
title: "Improved attachments UX",
|
||||
subtitle:
|
||||
"We've improved the UI/UX of attaching multiple files into the editor. The entire process is now handled in a unified dialog."
|
||||
},
|
||||
{
|
||||
icon: InternalLink,
|
||||
title: "Opening file links on desktop",
|
||||
subtitle: "The NN Desktop app can now open file links (file:///)."
|
||||
}
|
||||
],
|
||||
cta: {
|
||||
title: strings.gotIt(),
|
||||
icon: Checkmark,
|
||||
|
||||
Reference in New Issue
Block a user