mobile: update ui

This commit is contained in:
Ammar Ahmed
2026-04-29 13:58:30 +05:00
parent edd50110a7
commit 67dc2ddaff
105 changed files with 5800 additions and 3659 deletions

View File

@@ -0,0 +1,9 @@
{
"iconSets": [
{
"inputDir": "../../packages/icons/svgs",
"fontFamily": "notesnook-icons",
"outputDir": "./fonts"
}
]
}

View File

@@ -1,3 +1,21 @@
/*
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/>.
*/
export const FontSizes = {
XXS: 10,
XS: 12,
@@ -15,10 +33,24 @@ export const FontFamily = {
BOLD: "Inter-Bold" // 700
};
const LineHeightMultipliers = {
"100%": 1,
"110%": 1.1,
"120%": 1.2,
"130%": 1.3,
"140%": 1.4,
"150%": 1.5
};
export type LineHeightVariants =
| "100%"
| "110%"
| "120%"
| "130%"
| "140%"
| "150%";
export const getLineHeight = (
fontSize: keyof typeof FontSizes,
type: 1 | 2
type: LineHeightVariants
) => {
if (type === 1) return (FontSizes[fontSize] / 100) * 120;
if (type === 2) return (FontSizes[fontSize] / 100) * 150;
return FontSizes[fontSize] * LineHeightMultipliers[type];
};

View File

@@ -17,15 +17,15 @@ 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 { useThemeColors } from "@notesnook/theme";
import React, { useState } from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
import { NavigationProps } from "../../services/navigation";
import { Toast } from "../toast";
import { AuthMode, initialAuthMode } from "./common";
import { Login } from "./login";
import { Signup } from "./signup";
import { useThemeColors } from "@notesnook/theme";
import { NavigationProps } from "../../services/navigation";
const Auth = ({ navigation, route }: NavigationProps<"Auth">) => {
const [currentAuthMode, setCurrentAuthMode] = useState(

View File

@@ -178,6 +178,7 @@ export const Login = ({
formRef={formRef}
fwdRef={emailInputRef}
testID="input.email"
label={strings.email()}
returnKeyLabel="Next"
returnKeyType="next"
autoComplete="email"
@@ -200,6 +201,7 @@ export const Login = ({
name="password"
formRef={formRef}
fwdRef={passwordInputRef}
label={strings.password()}
testID="input.password"
returnKeyLabel={strings.done()}
returnKeyType="done"

View File

@@ -22,9 +22,9 @@ import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { TextInput, View } from "react-native";
import { db } from "../../common/database/index";
import { Radius, Spacing } from "../../common/design/spacing";
import useTimer from "../../hooks/use-timer";
import { eSendEvent, ToastManager } from "../../services/event-manager";
import { eCloseSimpleDialog } from "../../utils/events";
import { hexToRGBA, RGB_Linear_Shade } from "../../utils/colors";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { presentDialog } from "../dialog/functions";
@@ -35,7 +35,6 @@ import PinInput from "../ui/pin-input/index";
import { Pressable } from "../ui/pressable";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { Radius, Spacing } from "../../common/design/spacing";
type MFAInfo = {
primaryMethod: string;
@@ -119,12 +118,14 @@ const TwoFactorVerification = ({
{
id: "sms",
title: strings.sendCodeSms(),
icon: "message-plus-outline"
icon: "chat",
iconFamily: "notesnook"
},
{
id: "email",
title: strings.sendCodeEmail(),
icon: "email-outline"
icon: "envelope-simple",
iconFamily: "notesnook"
},
{
id: "app",
@@ -134,7 +135,8 @@ const TwoFactorVerification = ({
{
id: "recoveryCode",
title: strings.recoveryCode(),
icon: "key"
icon: "lock-simple",
iconFamily: "notesnook"
}
];
@@ -182,47 +184,54 @@ const TwoFactorVerification = ({
}, 500);
}}
style={{
alignItems: "center"
alignItems: "center",
gap: Spacing.LEVEL_3
}}
>
<IconButton
<View
style={{
width: 50,
height: 50,
backgroundColor: colors.primary.shade,
borderRadius: Radius.XS,
marginBottom: Spacing.LEVEL_7
}}
size={25}
name="key"
color={colors.primary.accent}
/>
<Heading
style={{
textAlign: "center",
marginBottom: Spacing.LEVEL_1
paddingHorizontal: Spacing.LEVEL_3,
width: "100%"
}}
>
{currentMethod.method ? strings["2fa"]() : strings.select2faMethod()}
</Heading>
<Paragraph
style={{
width: "80%",
textAlign: "center"
}}
>
{currentMethod.method
? strings["2faCodeHelpText"][
currentMethod.method as keyof (typeof strings)["2faCodeHelpText"]
]?.() || strings.select2faCodeHelpText()
: strings.select2faCodeHelpText()}
</Paragraph>
<IconButton
style={{
width: 50,
height: 50,
backgroundColor: colors.primary.shade,
borderRadius: Radius.XS,
marginBottom: Spacing.LEVEL_7
}}
size={25}
iconFamily="notesnook"
name="shield-check"
color={colors.primary.accent}
/>
<Heading
style={{
textAlign: "center",
marginBottom: Spacing.LEVEL_1
}}
>
{currentMethod.method ? strings["2fa"]() : strings.select2faMethod()}
</Heading>
<Paragraph
style={{
textAlign: "center"
}}
>
{currentMethod.method
? strings["2faCodeHelpText"][
currentMethod.method as keyof (typeof strings)["2faCodeHelpText"]
]?.() || strings.select2faCodeHelpText()
: strings.select2faCodeHelpText()}
</Paragraph>
</View>
{currentMethod.method ? (
<>
<View
style={{
marginTop: Spacing.LEVEL_4,
borderRadius: Radius.S,
borderWidth: 1,
borderColor: colors.primary.border,
@@ -303,7 +312,7 @@ const TwoFactorVerification = ({
currentMethod.method === "email" ? (
<Button
onPress={onSendCode}
type={seconds ? "secondary" : "transparent"}
type={"plain"}
disabled={!seconds}
title={
sending
@@ -316,6 +325,7 @@ const TwoFactorVerification = ({
}
loading={sending}
fontSize={AppFontSize.sm}
fontFamily="REGULAR"
style={{
paddingVertical: 0,
alignSelf: "flex-start",
@@ -335,7 +345,12 @@ const TwoFactorVerification = ({
/>
</>
) : (
<>
<View
style={{
gap: Spacing.LEVEL_2,
width: "100%"
}}
>
{getMethods().map((item) => (
<Pressable
key={item.title}
@@ -346,35 +361,42 @@ const TwoFactorVerification = ({
});
}}
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
marginTop: 0,
padding: Spacing.LEVEL_2,
backgroundColor: colors.secondary.background,
flexDirection: "row",
borderRadius: 0,
borderRadius: Radius.S,
alignItems: "center",
width: "100%",
justifyContent: "flex-start"
justifyContent: "flex-start",
gap: Spacing.LEVEL_1
}}
>
<IconButton
type="secondaryAccented"
style={{
marginRight: 10
borderRadius: Radius.XS,
padding: Spacing.LEVEL_1,
width: undefined,
height: undefined,
backgroundColor: RGB_Linear_Shade(
0.04,
hexToRGBA(colors.secondary.background)
)
}}
size={15}
color={colors.primary.accent}
size={17}
color={colors.primary.icon}
name={item.icon}
iconFamily={item.iconFamily as "notesnook"}
/>
<View
style={{
flexShrink: 1
}}
>
<Paragraph size={AppFontSize.md}>{item.title}</Paragraph>
<Paragraph size={AppFontSize.sm}>{item.title}</Paragraph>
</View>
</Pressable>
))}
</>
</View>
)}
</View>
);

View File

@@ -20,14 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { View } from "react-native";
import { notesnook } from "../../../e2e/test.ids";
import { getColorLinearShade } from "../../utils/colors";
import { Spacing } from "../../common/design/spacing";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { Button, ButtonProps } from "../ui/button";
import Paragraph from "../ui/typography/paragraph";
const DialogButtons = ({
onPressPositive,
@@ -51,82 +48,39 @@ const DialogButtons = ({
return (
<View
style={[
styles.container,
{
backgroundColor: colors.secondary.background,
height: 60,
paddingHorizontal: DefaultAppStyles.GAP,
borderTopWidth: 0.7,
borderTopColor: getColorLinearShade(
colors.secondary.background,
0.05,
isDark
)
flexDirection: "row",
gap: Spacing.LEVEL_2,
paddingHorizontal: Spacing.LEVEL_4
}
]}
>
{doneText ? (
<View
style={{
flexDirection: "row",
alignItems: "center"
}}
>
<Icon
color={colors.primary.accent}
name="check-circle-outline"
size={AppFontSize.md}
/>
<Paragraph color={colors.primary.accent}>{" " + doneText}</Paragraph>
</View>
) : loading ? (
<ActivityIndicator
size={AppFontSize.lg}
color={colors.primary.accent}
/>
) : (
<View />
)}
<View
<Button
onPress={onPressNegative}
fontSize={AppFontSize.sm}
testID={notesnook.ids.default.dialog.no}
type="plain-outline"
style={{
flexDirection: "row",
alignItems: "center"
width: "48.5%"
}}
>
title={negativeTitle}
/>
{onPressPositive ? (
<Button
onPress={onPressNegative}
onPress={onPressPositive}
fontSize={AppFontSize.sm}
testID={notesnook.ids.default.dialog.no}
type="plain"
testID={notesnook.ids.default.dialog.yes}
style={{
width: "48.5%"
}}
loading={loading}
bold
title={negativeTitle}
type={positiveType || "accent"}
title={positiveTitle}
/>
{onPressPositive ? (
<Button
onPress={onPressPositive}
fontSize={AppFontSize.sm}
testID={notesnook.ids.default.dialog.yes}
style={{
marginLeft: 10
}}
bold
type={positiveType || "transparent"}
title={positiveTitle}
/>
) : null}
</View>
) : null}
</View>
);
};
export default DialogButtons;
const styles = StyleSheet.create({
container: {
justifyContent: "space-between",
alignItems: "center",
flexDirection: "row",
marginTop: DefaultAppStyles.GAP_VERTICAL
}
});

View File

@@ -23,6 +23,7 @@ import { DDS } from "../../services/device-detection";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../utils/elevation";
import { getContainerBorder } from "../../utils/colors";
import { Radius } from "../../common/design/spacing";
const DialogContainer = ({
width,
@@ -44,7 +45,7 @@ const DialogContainer = ({
{
width: width || DDS.isTab ? 500 : "85%",
maxHeight: height || 450,
borderRadius: 10,
borderRadius: Radius.LG,
backgroundColor: colors.primary.background,
paddingTop: 12
},

View File

@@ -57,7 +57,6 @@ const DialogHeader = ({
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
minHeight: 50,
paddingHorizontal: padding,
...style
}}
@@ -76,7 +75,7 @@ const DialogHeader = ({
>
<Heading
style={{ textAlign: centered ? "center" : "left" }}
size={AppFontSize.lg}
fontSize="XL"
>
{title}{" "}
{titlePart ? (

View File

@@ -58,6 +58,7 @@ export type DialogInfo = {
onFormSubmit?: (form: FormRef) => Promise<boolean>;
};
input: boolean;
inputLabel?: string;
inputPlaceholder: string;
defaultValue: string;
// eslint-disable-next-line @typescript-eslint/ban-types

View File

@@ -19,13 +19,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useThemeColors } from "@notesnook/theme";
import React, {
RefObject,
useCallback,
useEffect,
useRef,
useState,
RefObject
useState
} from "react";
import { TextInput, View, ViewStyle } from "react-native";
import { Spacing } from "../../common/design/spacing";
import { DDS } from "../../services/device-detection";
import {
eSubscribeEvent,
@@ -42,7 +43,6 @@ import { Button } from "../ui/button";
import Input from "../ui/input";
import { FormInput, type FormRef } from "../ui/input/form-input";
import { Notice } from "../ui/notice";
import Seperator from "../ui/seperator";
import BaseDialog from "./base-dialog";
import DialogButtons from "./dialog-buttons";
import DialogHeader from "./dialog-header";
@@ -155,7 +155,7 @@ export const Dialog = ({ context = "global" }: { context?: string }) => {
maxHeight: 450,
borderRadius: defaultBorderRadius,
backgroundColor: colors.primary.background,
paddingTop: 12,
gap: Spacing.LEVEL_4,
...getContainerBorder(colors.primary.border, 0.5),
overflow: "hidden"
};
@@ -170,9 +170,7 @@ export const Dialog = ({ context = "global" }: { context?: string }) => {
bounce={!dialogInfo.input && !dialogInfo.form}
closeOnTouch={!dialogInfo.disableBackdropClosing}
background={dialogInfo.background}
transparent={
dialogInfo.transparent === undefined ? false : dialogInfo.transparent
}
transparent={dialogInfo.transparent}
onShow={async () => {
if (dialogInfo.input && !dialogInfo.form) {
inputRef.current?.setNativeProps({
@@ -201,54 +199,61 @@ export const Dialog = ({ context = "global" }: { context?: string }) => {
: dialogInfo.component}
{dialogInfo.component ? null : (
<View style={style}>
<DialogHeader
title={dialogInfo.title}
icon={dialogInfo.icon}
paragraph={dialogInfo.paragraph}
paragraphColor={dialogInfo.paragraphColor}
padding={12}
style={{
minHeight: 0
}}
/>
<Seperator half />
<View
style={[
{
paddingVertical: Spacing.LEVEL_4
},
style
]}
>
<View
style={[
{
paddingHorizontal: Spacing.LEVEL_3,
gap: Spacing.LEVEL_4
}
]}
>
<DialogHeader
title={dialogInfo.title}
icon={dialogInfo.icon}
paragraph={dialogInfo.paragraph}
paragraphColor={dialogInfo.paragraphColor}
style={{
minHeight: 0
}}
/>
{dialogInfo.form ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
gap: DefaultAppStyles.GAP / 2
}}
>
{dialogInfo.form.items.map((item, index) => (
<FormInput
key={item.name}
fwdRef={item.ref}
name={item.name}
autoFocus={index === 0}
placeholder={item.placeholder}
formRef={formRef as RefObject<FormRef>}
validators={item.validators}
defaultValue={item.defaultValue}
secureTextEntry={dialogInfo.secureTextEntry}
onSubmitEditing={() => {
const nextItem = dialogInfo?.form?.items?.[index + 1];
if (nextItem) {
nextItem?.ref.current?.focus();
} else {
onPressPositive();
}
}}
/>
))}
</View>
) : dialogInfo.input ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
}}
>
{dialogInfo.form ? (
<View
style={{
gap: Spacing.LEVEL_2
}}
>
{dialogInfo.form.items.map((item, index) => (
<FormInput
key={item.name}
fwdRef={item.ref}
name={item.name}
autoFocus={index === 0}
placeholder={item.placeholder}
formRef={formRef as RefObject<FormRef>}
validators={item.validators}
defaultValue={item.defaultValue}
secureTextEntry={dialogInfo.secureTextEntry}
onSubmitEditing={() => {
const nextItem = dialogInfo?.form?.items?.[index + 1];
if (nextItem) {
nextItem?.ref.current?.focus();
} else {
onPressPositive();
}
}}
/>
))}
</View>
) : dialogInfo.input ? (
<Input
fwdRef={inputRef}
autoCapitalize="none"
@@ -258,6 +263,7 @@ export const Dialog = ({ context = "global" }: { context?: string }) => {
testID="input-value"
secureTextEntry={dialogInfo.secureTextEntry}
defaultValue={dialogInfo.defaultValue}
label={dialogInfo.inputLabel}
onSubmit={() => {
onPressPositive();
}}
@@ -266,48 +272,47 @@ export const Dialog = ({ context = "global" }: { context?: string }) => {
keyboardType={dialogInfo.keyboardType || "default"}
placeholder={dialogInfo.inputPlaceholder}
/>
</View>
) : null}
) : null}
{dialogInfo?.notice ? (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<Notice
type={dialogInfo.notice.type || "information"}
text={dialogInfo.notice.text}
/>
</View>
) : null}
{dialogInfo.check ? (
<>
<Button
onPress={() => {
setChecked(!checked);
}}
icon={
checked
? "check-circle-outline"
: "checkbox-blank-circle-outline"
}
iconColor={
checked ? colors.secondary.icon : colors.primary.icon
}
{dialogInfo?.notice ? (
<View
style={{
justifyContent: "flex-start"
paddingHorizontal: DefaultAppStyles.GAP
}}
height={35}
iconSize={20}
width="100%"
title={dialogInfo.check.info}
type={checked ? dialogInfo.check.type || "plain" : "plain"}
/>
</>
) : null}
>
<Notice
type={dialogInfo.notice.type || "information"}
text={dialogInfo.notice.text}
/>
</View>
) : null}
{dialogInfo.check ? (
<>
<Button
onPress={() => {
setChecked(!checked);
}}
icon={
checked
? "check-circle-outline"
: "checkbox-blank-circle-outline"
}
iconColor={
checked ? colors.secondary.icon : colors.primary.icon
}
style={{
justifyContent: "flex-start"
}}
height={35}
iconSize={20}
width="100%"
title={dialogInfo.check.info}
type={checked ? dialogInfo.check.type || "plain" : "plain"}
/>
</>
) : null}
</View>
<DialogButtons
onPressNegative={onNegativePress}
onPressPositive={

View File

@@ -17,25 +17,24 @@ 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 { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useState } from "react";
import { View } from "react-native";
import { notesnook } from "../../../e2e/test.ids";
import { Radius, Spacing } from "../../common/design/spacing";
import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import Navigation from "../../services/navigation";
import { RouteName } from "../../stores/use-navigation-store";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { eScrollEvent } from "../../utils/events";
import { AppFontSize } from "../../utils/size";
import { fluidTabsRef } from "../../utils/global-refs";
import { DefaultAppStyles } from "../../utils/styles";
import { IconButtonProps } from "../ui/icon-button";
import { Pressable } from "../ui/pressable";
import { IconButton, IconButtonProps } from "../ui/icon-button";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { LeftMenus } from "./left-menus";
import { RightMenus } from "./right-menus";
export const Header = ({
renderedInRoute,
@@ -64,6 +63,9 @@ export const Header = ({
state.selectionMode
]);
const deviceMode = useSettingStore((state) => state.deviceMode);
const isTablet = deviceMode === "tablet";
const onScroll = useCallback(
(data: { x: number; y: number; id?: string; route: string }) => {
if (data.route !== renderedInRoute || data.id !== id) return;
@@ -85,34 +87,58 @@ export const Header = ({
};
}, [borderHidden, onScroll]);
const HeaderWrapper = hasSearch ? Pressable : View;
const _onLeftButtonPress = () => {
if (onLeftMenuButtonPress) return onLeftMenuButtonPress();
if (!canGoBack) {
if (fluidTabsRef.current?.isDrawerOpen()) {
Navigation.closeDrawer();
} else {
Navigation.openDrawer();
}
return;
}
Navigation.goBack();
};
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: DefaultAppStyles.GAP,
marginBottom: Spacing.LEVEL_3
}}
>
<HeaderWrapper
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
borderRadius: 10,
paddingVertical: 3,
borderWidth: hasSearch ? 1 : 0,
borderColor: colors.primary.border,
paddingHorizontal: !hasSearch ? 0 : DefaultAppStyles.GAP_SMALL,
borderRadius: Radius.S,
paddingHorizontal: Spacing.LEVEL_2,
paddingVertical: Spacing.LEVEL_3,
backgroundColor: colors.secondary.background,
alignItems: "center"
}}
testID="search-header"
onPress={() => {
onSearch?.();
}}
>
<LeftMenus
canGoBack={canGoBack}
onLeftButtonPress={onLeftMenuButtonPress}
/>
{isTablet && !canGoBack ? null : (
<IconButton
testID={notesnook.ids.default.header.buttons.left}
left={40}
top={40}
onPress={_onLeftButtonPress}
onLongPress={() => {
Navigation.popToTop();
}}
style={{
width: 20,
height: 20
}}
size={20}
name={canGoBack ? "arrow-left" : "menu"}
iconFamily="notesnook"
color={colors.primary.icon}
/>
)}
{!title ? (
<View
@@ -123,18 +149,39 @@ export const Header = ({
borderRadius: 100
}}
/>
) : hasSearch ? (
<Paragraph>
{selectionMode
? `${selectedItemsList.length} selected`
: strings.searchInRoute(title)}
</Paragraph>
) : (
<Heading size={AppFontSize.lg}>{title}</Heading>
<Heading fontSize="XL">
{selectionMode ? `${selectedItemsList.length} selected` : title}
</Heading>
)}
<RightMenus rightButton={rightButton} />
</HeaderWrapper>
<View
style={{
flexDirection: "row",
alignItems: "center"
}}
>
{rightButton ? (
<IconButton {...rightButton} color={colors.primary.icon} />
) : null}
{hasSearch ? (
<IconButton
color={colors.primary.icon}
size={20}
onPress={() => {
onSearch?.();
}}
style={{
width: 20,
height: 20
}}
iconFamily="notesnook"
name="search"
/>
) : null}
</View>
</View>
</View>
);
};

View File

@@ -1,66 +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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import { notesnook } from "../../../e2e/test.ids";
import Navigation from "../../services/navigation";
import { useSettingStore } from "../../stores/use-setting-store";
import { fluidTabsRef } from "../../utils/global-refs";
import { IconButton } from "../ui/icon-button";
export const LeftMenus = ({
canGoBack,
onLeftButtonPress
}: {
canGoBack?: boolean;
onLeftButtonPress?: () => void;
}) => {
const { colors } = useThemeColors();
const deviceMode = useSettingStore((state) => state.deviceMode);
const isTablet = deviceMode === "tablet";
const _onLeftButtonPress = () => {
if (onLeftButtonPress) return onLeftButtonPress();
if (!canGoBack) {
if (fluidTabsRef.current?.isDrawerOpen()) {
Navigation.closeDrawer();
} else {
Navigation.openDrawer();
}
return;
}
Navigation.goBack();
};
return isTablet && !canGoBack ? null : (
<IconButton
testID={notesnook.ids.default.header.buttons.left}
left={40}
top={40}
onPress={_onLeftButtonPress}
onLongPress={() => {
Navigation.popToTop();
}}
name={canGoBack ? "arrow-left" : "menu"}
color={colors.primary.icon}
/>
);
};

View File

@@ -22,22 +22,22 @@ import {
GroupingByIdKey,
GroupingKey,
GroupOptions,
ItemType
ItemType,
Item,
VirtualizedGrouping
} from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View } from "react-native";
import React, { RefObject } from "react";
import { FlatList, View } from "react-native";
import { Radius, Spacing } from "../../../common/design/spacing";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import { presentSheet } from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { RouteName } from "../../../stores/use-navigation-store";
import { AppFontSize } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import Sort from "../../sheets/sort";
import { IconButton } from "../../ui/icon-button";
import { Pressable } from "../../ui/pressable";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
type SectionHeaderProps = {
item: GroupHeader;
@@ -49,8 +49,9 @@ type SectionHeaderProps = {
group: GroupingKey;
groupId?: string;
type?: GroupingByIdKey;
onOpenJumpToDialog: () => void;
itemCount?: number;
data?: VirtualizedGrouping<Item>;
ref?: RefObject<FlatList>;
};
export const SectionHeader = React.memo<
@@ -64,10 +65,11 @@ export const SectionHeader = React.memo<
screen,
groupOptions,
group,
onOpenJumpToDialog,
itemCount,
groupId,
type
type,
data,
ref
}: SectionHeaderProps) {
const { colors } = useThemeColors();
const isCompactModeEnabled = useIsCompactModeEnabled(
@@ -78,8 +80,9 @@ export const SectionHeader = React.memo<
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
marginBottom: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: Spacing.LEVEL_3,
marginBottom: Spacing.LEVEL_3,
marginTop: Spacing.LEVEL_3
}}
>
<View
@@ -88,58 +91,36 @@ export const SectionHeader = React.memo<
alignItems: "center",
width: "100%",
alignSelf: "center",
justifyContent: "space-between",
borderBottomWidth: 1,
borderColor: colors.primary.border,
paddingBottom: 1,
paddingTop:
index === 0
? DefaultAppStyles.GAP_VERTICAL
: DefaultAppStyles.GAP_VERTICAL_SMALL
justifyContent: "space-between"
}}
>
<Pressable
onPress={() => {
onOpenJumpToDialog();
}}
hitSlop={{ top: 10, left: 10, right: 30, bottom: 15 }}
<Paragraph
fontSize="MD"
style={{
justifyContent: "flex-start",
flexDirection: "row",
width: "auto"
alignSelf: "center",
textAlignVertical: "center"
}}
color={colors.secondary.paragraph}
>
<Heading
size={AppFontSize.xxs}
style={{
alignSelf: "center",
textAlignVertical: "center"
}}
color={color || colors.primary.accent}
>
{!item.title || item.title === ""
? screen === "Search"
? strings.results(itemCount || 0)
: strings.pinned().toUpperCase()
: item.title.toUpperCase()}
</Heading>
</Pressable>
{!item.title || item.title === ""
? screen === "Search"
? strings.results(itemCount || 0)
: strings.pinned().toUpperCase()
: item.title.toUpperCase()}
</Paragraph>
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
gap: Spacing.LEVEL_1
}}
>
{index === 0 ? (
<>
<IconButton
name={
groupOptions.sortDirection === "asc"
? "sort-ascending"
: "sort-descending"
}
name={"sliders"}
iconFamily="notesnook"
color={colors.secondary.icon}
testID="icon-sort"
onPress={() => {
@@ -155,15 +136,20 @@ export const SectionHeader = React.memo<
hideGroupOptions={
screen === "Reminders" || screen === "Search"
}
data={data}
ref={ref}
/>
)
});
}}
style={{
width: 25,
height: 25
width: 30,
height: 30,
borderWidth: 1,
borderRadius: Radius.XS,
borderColor: colors.secondary.border
}}
size={AppFontSize.lg - 2}
size={16}
/>
<IconButton
hidden={
@@ -173,14 +159,16 @@ export const SectionHeader = React.memo<
screen !== "Search"
}
style={{
width: 25,
height: 25
width: 30,
height: 30,
borderWidth: 1,
borderRadius: Radius.XXS,
borderColor: colors.secondary.border
}}
testID="icon-compact-mode"
color={colors.secondary.icon}
name={
isCompactModeEnabled ? "view-list" : "view-list-outline"
}
name={"view-list"}
iconFamily="notesnook"
onPress={() => {
SettingsService.set({
[dataType === "notebook"
@@ -192,20 +180,10 @@ export const SectionHeader = React.memo<
: "normal"
});
}}
size={AppFontSize.lg - 2}
size={16}
/>
</>
) : null}
{/* <IconButton
style={{
width: 25,
height: 25
}}
color={colors.secondary.icon}
name={"chevron-down"}
size={SIZE.lg - 2}
/> */}
</View>
</View>
</View>

View File

@@ -28,7 +28,6 @@ import { useThemeColors } from "@notesnook/theme";
import { EntityLevel, decode } from "entities";
import React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import useNavigationStore, {
RouteParams
@@ -56,6 +55,9 @@ import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import dayjs from "dayjs";
import { ExpiryDate } from "../../ui/expiry-date";
import { Radius, Spacing } from "../../../common/design/spacing";
import { create } from "zustand";
import { FontFamily } from "../../../common/design/font";
type NoteItemProps = {
item: Note | BaseTrashItem<Note>;
@@ -72,6 +74,24 @@ type NoteItemProps = {
renderedInRoute?: keyof RouteParams;
};
const useShowMoreStore = create<{
showMoreStatus: Record<string, boolean>;
show: (id: string) => void;
hide: (id: string) => void;
}>((set) => ({
showMoreStatus: {},
show(id) {
set((state) => ({
showMoreStatus: { ...state.showMoreStatus, [id]: true }
}));
},
hide(id) {
set((state) => ({
showMoreStatus: { ...state.showMoreStatus, [id]: false }
}));
}
}));
const NoteItem = ({
item,
isTrash,
@@ -98,68 +118,54 @@ const NoteItem = ({
const primaryColors = isEditingNote ? colors.selected : colors.primary;
const selectionMode = useSelectionStore((state) => state.selectionMode);
const [selected] = useIsSelected(item);
const showMore = useShowMoreStore((state) => state.showMoreStatus[item.id]);
const statusIcons = [
{
condition: item.conflicted,
name: "alert-circle",
color: colors.error.accent
},
{
condition: item.localOnly,
testID: "sync-off",
name: "sync-off",
color: primaryColors.icon
},
{
condition: item.readonly,
testID: "pencil-lock",
name: "pencil-lock",
color: primaryColors.icon
},
{
condition: item.pinned,
testID: "icon-pinned",
name: "pin",
color: primaryColors.icon
},
{
condition: !!locked,
testID: "lock",
name: "lock",
color: primaryColors.icon
},
{
condition: item.favorite,
testID: "star-filled",
name: "star-outline",
color: "orange"
}
];
return (
<>
<View
style={{
flexGrow: 1,
flexShrink: 1
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
>
{compactMode ? null : (
<Paragraph
style={{
fontSize: AppFontSize.xxxs,
color: colors.secondary.paragraph
}}
>
{getFormattedDate(
date,
dayjs(date).isBefore(dayjs().subtract(1, "day").hour(23))
? "date"
: "time"
)}
</Paragraph>
)}
{compactMode ? (
<Paragraph
numberOfLines={1}
color={color?.colorCode || primaryColors.heading}
size={AppFontSize.sm}
style={{
paddingRight: 10
}}
>
{item.title}
</Paragraph>
) : (
<Heading
numberOfLines={1}
color={color?.colorCode || primaryColors.heading}
size={AppFontSize.sm}
style={{
paddingRight: 10
}}
>
{item.title}
</Heading>
)}
{item.headline && !compactMode ? (
<Paragraph
style={{
flexWrap: "wrap"
}}
color={primaryColors.paragraph}
numberOfLines={2}
>
{decode(item.headline, {
level: EntityLevel.HTML
})}
</Paragraph>
) : null}
{compactMode ? null : (
<View
style={{
@@ -167,50 +173,52 @@ const NoteItem = ({
justifyContent: "flex-start",
alignItems: "center",
width: "100%",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
columnGap: 8,
rowGap: 4,
columnGap: Spacing.LEVEL_0,
rowGap: Spacing.LEVEL_0,
flexWrap: "wrap"
}}
>
{!isTrash ? (
<>
{item.conflicted ? (
<Icon
name="alert-circle"
size={AppFontSize.sm}
color={colors.error.accent}
/>
) : null}
{statusIcons
.filter((statusIcon) => statusIcon.condition)
.map((statusIcon) => (
<View
key={statusIcon.testID || statusIcon.name}
style={{
borderRadius: Radius.XXS,
paddingHorizontal: 3,
paddingVertical: 3,
// borderWidth: 1,
// borderColor: primaryColors.border,
flexDirection: "row",
alignItems: "center"
}}
>
<AppIcon
testID={statusIcon.testID}
name={statusIcon.name}
size={12}
iconFamily="notesnook"
color={statusIcon.color}
/>
</View>
))}
{item.localOnly ? (
<Icon
testID="sync-off"
name="sync-off"
size={AppFontSize.sm}
color={primaryColors.icon}
/>
) : null}
{item.readonly ? (
<Icon
testID="pencil-lock"
name="pencil-lock"
size={AppFontSize.sm}
color={primaryColors.icon}
/>
) : null}
{attachmentsCount > 0 ? (
{attachmentsCount !== 0 ? (
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: 2
borderRadius: Radius.XXS,
paddingHorizontal: 3,
paddingVertical: 3,
gap: Spacing.LEVEL_0
}}
>
<Icon
name="attachment"
<AppIcon
name="link"
iconFamily="notesnook"
size={AppFontSize.sm}
color={primaryColors.icon}
/>
@@ -223,93 +231,34 @@ const NoteItem = ({
</View>
) : null}
{item.pinned ? (
<Icon
testID="icon-pinned"
name="pin-outline"
size={AppFontSize.sm}
color={color?.colorCode || primaryColors.accent}
/>
) : null}
{locked ? (
<Icon
name="lock"
testID="note-locked-icon"
size={AppFontSize.sm}
color={primaryColors.icon}
/>
) : null}
{item.favorite ? (
<Icon
testID="icon-star"
name="star-outline"
size={AppFontSize.sm}
color="orange"
/>
) : null}
{reminder ? (
<ReminderTime
reminder={reminder}
color={color?.colorCode}
textStyle={{
fontSize: AppFontSize.xxs
}}
short
iconSize={AppFontSize.xxs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start"
}}
/>
) : null}
{item.expiryDate?.value ? (
<ExpiryDate
note={item as Note}
color={color?.colorCode}
textStyle={{ fontSize: AppFontSize.xxs }}
short
iconSize={AppFontSize.xxs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start"
}}
/>
) : null}
{notebooks?.items
?.filter(
(item) =>
renderedInRoute !== "Notebook" ||
item.id !== useNavigationStore.getState().focusedRouteId
)
.filter((_, index) => showMore || index < 1)
.map((item) => (
<View
key={item.id}
style={{
borderRadius: 4,
borderRadius: 100,
paddingHorizontal: Spacing.LEVEL_1,
paddingVertical: 2,
backgroundColor: colors.secondary.background,
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
borderWidth: 0.5,
borderColor: primaryColors.border,
paddingVertical: 1,
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL / 2
gap: Spacing.LEVEL_0
}}
>
<AppIcon
name="book-outline"
size={AppFontSize.xxxs}
name="bookmark"
iconFamily="notesnook"
size={AppFontSize.xs}
color={colors.secondary.icon}
/>
<Paragraph
size={AppFontSize.xxxs}
fontSize="XS"
color={colors.secondary.paragraph}
>
{item.title}
@@ -317,31 +266,64 @@ const NoteItem = ({
</View>
))}
{!isTrash && !compactMode && tags
? tags.items?.map((item) =>
item.id ? (
<View
key={item.id}
style={{
borderRadius: 4,
backgroundColor: colors.secondary.background,
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
borderWidth: 0.5,
borderColor:
color?.colorCode || primaryColors.border,
paddingVertical: 1
}}
{tags?.items
?.filter((_, index) => showMore || index < 1)
.map((item) =>
item.id ? (
<View
key={item.id}
style={{
borderRadius: 100,
paddingHorizontal: Spacing.LEVEL_1,
paddingVertical: 2,
backgroundColor: colors.secondary.background,
flexDirection: "row",
alignItems: "center",
gap: Spacing.LEVEL_0
}}
>
<Paragraph
size={AppFontSize.xs}
color={colors.secondary.paragraph}
>
<Paragraph
size={AppFontSize.xxxs}
color={colors.secondary.paragraph}
>
#{item.title}
</Paragraph>
</View>
) : null
)
: null}
{item.title}
</Paragraph>
</View>
) : null
)}
{(() => {
const filteredNotebooks = (notebooks?.items || []).filter(
(nb) =>
renderedInRoute !== "Notebook" ||
nb.id !== useNavigationStore.getState().focusedRouteId
);
const filteredTags = (tags?.items || []).filter((t) => t.id);
const totalNotebooks = filteredNotebooks.length;
const totalTags = filteredTags.length;
const hasMore = totalNotebooks > 1 || totalTags > 1;
if (!hasMore) return null;
const hiddenCount =
(totalNotebooks > 1 ? totalNotebooks - 1 : 0) +
(totalTags > 1 ? totalTags - 1 : 0);
return (
<Heading
size={AppFontSize.xs}
color={colors.primary.accent}
onPress={() => {
if (showMore) {
useShowMoreStore.getState().hide(item.id);
} else {
useShowMoreStore.getState().show(item.id);
}
}}
>
{showMore
? "Show less"
: `+${hiddenCount} ${strings.more()}`}
</Heading>
);
})()}
</>
) : (
<>
@@ -372,6 +354,140 @@ const NoteItem = ({
)}
</View>
)}
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: Spacing.LEVEL_1
}}
>
{color ? (
<View
style={{
width: 8,
height: 8,
borderRadius: 100,
backgroundColor: color?.colorCode
}}
/>
) : null}
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
flexGrow: 1,
alignItems: "center"
}}
>
<Heading
numberOfLines={1}
color={primaryColors.heading}
size={AppFontSize.sm}
style={{
flexShrink: 1
}}
>
{item.title}
</Heading>
<IconButton
testID={notesnook.listitem.menu}
color={colors.secondary.icon}
name="dots-three"
iconFamily="notesnook"
size={20}
onPress={() => !noOpen && Properties.present(item)}
style={{
justifyContent: "center",
height: undefined,
width: undefined,
borderRadius: 100,
alignItems: "center"
}}
/>
</View>
</View>
{item.headline && !compactMode ? (
<Paragraph
style={{
flexWrap: "wrap"
}}
color={primaryColors.paragraph}
numberOfLines={2}
>
{decode(item.headline, {
level: EntityLevel.HTML
})}
</Paragraph>
) : null}
<View
style={{
flexDirection: "row",
gap: Spacing.LEVEL_1
}}
>
{compactMode ? null : (
<View
style={{
gap: Spacing.LEVEL_0,
flexDirection: "row"
}}
>
<AppIcon size={13} name="calendar" iconFamily="notesnook" />
<Paragraph
style={{
fontSize: AppFontSize.xs,
color: colors.secondary.paragraph
}}
>
{getFormattedDate(
date,
dayjs(date).isBefore(dayjs().subtract(1, "day").hour(23))
? "date"
: "time"
)}
</Paragraph>
</View>
)}
{item.expiryDate?.value ? (
<ExpiryDate
note={item as Note}
color={color?.colorCode}
textStyle={{ fontSize: AppFontSize.xxs }}
short
iconSize={AppFontSize.xxs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start"
}}
/>
) : null}
{reminder ? (
<ReminderTime
reminder={reminder}
color={color?.colorCode}
textStyle={{
fontSize: AppFontSize.xs,
fontFamily: FontFamily.REGULAR
}}
short
iconSize={AppFontSize.xxs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start",
backgroundColor: colors.primary.shade
}}
/>
) : null}
</View>
</View>
<View
style={{
@@ -382,7 +498,7 @@ const NoteItem = ({
{compactMode ? (
<>
{item.conflicted ? (
<Icon
<AppIcon
name="alert-circle"
style={{
marginRight: 6
@@ -393,7 +509,7 @@ const NoteItem = ({
) : null}
{locked ? (
<Icon
<AppIcon
name="lock"
testID="note-locked-icon"
size={AppFontSize.sm}
@@ -405,7 +521,7 @@ const NoteItem = ({
) : null}
{item.favorite ? (
<Icon
<AppIcon
testID="icon-star"
name="star-outline"
size={AppFontSize.sm}
@@ -445,22 +561,7 @@ const NoteItem = ({
/>
</View>
</>
) : (
<IconButton
testID={notesnook.listitem.menu}
color={colors.secondary.icon}
name="dots-horizontal"
size={AppFontSize.lg}
onPress={() => !noOpen && Properties.present(item)}
style={{
justifyContent: "center",
height: 35,
width: 35,
borderRadius: 100,
alignItems: "center"
}}
/>
)}
) : null}
</View>
</>
);

View File

@@ -36,7 +36,8 @@ import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
import { editorController } from "../../../screens/editor/tiptap/utils";
import { RouteParams } from "../../../stores/use-navigation-store";
import NotePreview from "../../note-history/preview";
import SelectionWrapper, { selectItem } from "../selection-wrapper";
import SelectionWrapper from "../selection-wrapper";
import { selectItem } from "../../../stores/use-selection-store";
export const openNote = async (
item: Note,
@@ -94,6 +95,7 @@ type NoteWrapperProps = {
isRenderedInActionSheet: boolean;
locked?: boolean;
renderedInRoute?: keyof RouteParams;
hasGroupHeader?: boolean;
};
export const NoteWrapper = React.memo<
@@ -103,6 +105,7 @@ export const NoteWrapper = React.memo<
item,
index,
isRenderedInActionSheet,
hasGroupHeader,
...restProps
}: NoteWrapperProps) {
const isTrash = item.type === "trash";
@@ -113,6 +116,7 @@ export const NoteWrapper = React.memo<
onPress={() => openNote(item as Note, isTrash, isRenderedInActionSheet)}
isSheet={isRenderedInActionSheet}
item={item}
hasGroupHeader={hasGroupHeader}
index={index}
color={restProps.color?.colorCode}
>

View File

@@ -27,7 +27,8 @@ import Navigation from "../../../services/navigation";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { useTrashStore } from "../../../stores/use-trash-store";
import { presentDialog } from "../../dialog/functions";
import SelectionWrapper, { selectItem } from "../selection-wrapper";
import SelectionWrapper from "../selection-wrapper";
import { selectItem } from "../../../stores/use-selection-store";
import { strings } from "@notesnook/intl";
export const openNotebook = (item: Notebook | BaseTrashItem<Notebook>) => {

View File

@@ -36,7 +36,8 @@ import { IconButton } from "../../ui/icon-button";
import { ReminderTime } from "../../ui/reminder-time";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import SelectionWrapper, { selectItem } from "../selection-wrapper";
import SelectionWrapper from "../selection-wrapper";
import { selectItem } from "../../../stores/use-selection-store";
const ReminderItem = React.memo(
({

View File

@@ -23,26 +23,9 @@ import React, { PropsWithChildren, useRef } from "react";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { DefaultAppStyles } from "../../../utils/styles";
import { Pressable } from "../../ui/pressable";
import { View } from "react-native";
export function selectItem(item: Item) {
if (useSelectionStore.getState().selectionMode === item.type) {
const { selectionMode, clearSelection, setSelectedItem } =
useSelectionStore.getState();
if (selectionMode === item.type) {
setSelectedItem(item.id);
}
if (useSelectionStore.getState().selectedItemsList.length === 0) {
clearSelection();
}
return true;
}
return false;
}
import { Spacing } from "../../../common/design/spacing";
type SelectionWrapperProps = PropsWithChildren<{
item: Item;
@@ -51,6 +34,7 @@ type SelectionWrapperProps = PropsWithChildren<{
isSheet?: boolean;
color?: string;
index?: number;
hasGroupHeader?: boolean;
}>;
const SelectionWrapper = ({
@@ -60,6 +44,7 @@ const SelectionWrapper = ({
isSheet,
children,
color,
hasGroupHeader,
index = 0
}: SelectionWrapperProps) => {
const itemId = useRef(item.id);
@@ -86,47 +71,37 @@ const SelectionWrapper = ({
};
return (
<Pressable
customColor={
isEditingNote
? colors.selected.background
: isSheet
? colors.primary.hover
: "transparent"
}
testID={testID}
onLongPress={onLongPress}
onPress={onPress}
customSelectedColor={colors.primary.hover}
customAlpha={!isDark ? -0.02 : 0.02}
customOpacity={1}
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
alignSelf: "center",
overflow: "hidden",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: compactMode ? 4 : DefaultAppStyles.GAP_VERTICAL,
borderRadius: isSheet ? 10 : 0,
marginBottom: isSheet ? DefaultAppStyles.GAP_VERTICAL : undefined
paddingHorizontal: Spacing.LEVEL_3,
backgroundColor: isEditingNote ? colors.selected.background : undefined
}}
>
{isEditingNote ? (
<View
style={{
backgroundColor: color || colors.selected.accent,
position: "absolute",
bottom: 0,
top: 0,
left: 0,
width: 5
}}
/>
) : null}
{children}
</Pressable>
<Pressable
customColor={isSheet ? colors.primary.hover : "transparent"}
testID={testID}
onLongPress={onLongPress}
onPress={onPress}
customSelectedColor={colors.primary.hover}
customAlpha={!isDark ? -0.02 : 0.02}
customOpacity={1}
style={{
flexDirection: "row",
width: "100%",
alignSelf: "center",
overflow: "hidden",
borderRadius: 0,
marginTop: hasGroupHeader ? 0 : Spacing.LEVEL_3,
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
alignItems: "flex-start",
paddingVertical: Spacing.LEVEL_2,
paddingTop: hasGroupHeader ? 0 : Spacing.LEVEL_2
}}
>
{children}
</Pressable>
</View>
);
};

View File

@@ -28,7 +28,8 @@ import { Properties } from "../../properties";
import { IconButton } from "../../ui/icon-button";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import SelectionWrapper, { selectItem } from "../selection-wrapper";
import SelectionWrapper from "../selection-wrapper";
import { selectItem } from "../../../stores/use-selection-store";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../../utils/styles";

View File

@@ -21,10 +21,11 @@ import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { Dimensions, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { Radius, Spacing } from "../../common/design/spacing";
import { Message, useMessageStore } from "../../stores/use-message-store";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import AppIcon from "../ui/AppIcon";
import { Pressable } from "../ui/pressable";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
export const Card = ({
@@ -47,15 +48,19 @@ export const Card = ({
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: Spacing.LEVEL_3,
marginBottom: Spacing.LEVEL_4,
marginTop: Spacing.LEVEL_3
}}
>
<Pressable
onPress={messageBoardState.onPress}
type="plain"
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: Spacing.LEVEL_3,
paddingHorizontal: Spacing.LEVEL_2,
backgroundColor: colors.primary.shade,
borderRadius: Radius.S,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -66,23 +71,24 @@ export const Card = ({
style={{
flexDirection: "row",
alignItems: "center",
width: "100%"
width: "100%",
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
>
<View
style={{
width: 40 * fontScale,
height: 40 * fontScale,
borderRadius: 100,
width: 34,
height: 34,
borderRadius: Radius.XXS,
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
backgroundColor: colors.secondary.background
}}
>
<Icon
size={AppFontSize.xxxl}
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
size={16}
color={colors.primary.icon}
allowFontScaling
name={messageBoardState.icon}
/>
@@ -90,25 +96,26 @@ export const Card = ({
<View
style={{
marginLeft: 10,
marginRight: 10
gap: Spacing.LEVEL_0
}}
>
<Paragraph
<Heading
style={{
flexWrap: "nowrap",
flexShrink: 1
}}
size={AppFontSize.sm}
fontSize="MD"
color={colors.primary.heading}
>
{messageBoardState.actionText}
</Paragraph>
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xs}>
</Heading>
<Paragraph color={colors.secondary.paragraph} fontSize="SM">
{messageBoardState.message}
</Paragraph>
</View>
</View>
<AppIcon size={24} name="chevron-right" color={colors.primary.icon} />
</Pressable>
</View>
);

View File

@@ -43,9 +43,7 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import { View } from "react-native";
import { getGroupOptions } from "../../hooks/use-group-options";
import { useIsCompactModeEnabled } from "../../hooks/use-is-compact-mode-enabled";
import { eSendEvent } from "../../services/event-manager";
import { RouteName } from "../../stores/use-navigation-store";
import { eOpenJumpToDialog } from "../../utils/events";
import { SectionHeader } from "../list-items/headers/section-header";
import { NoteWrapper } from "../list-items/note/wrapper";
import { NotebookWrapper } from "../list-items/notebook/wrapper";
@@ -190,12 +188,8 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
type={props.type}
color={props.customAccentColor}
groupOptions={groupOptions}
onOpenJumpToDialog={() => {
eSendEvent(eOpenJumpToDialog, {
ref: props.scrollRef,
data: items
});
}}
ref={props.scrollRef}
data={items}
/>
) : null}
@@ -205,6 +199,9 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
color={color.current}
notebooks={notebooks.current}
reminder={reminder.current}
hasGroupHeader={
groupHeader && previousIndex.current === index && !isSheet
}
attachmentsCount={attachmentsCount.current}
date={getDate(item as Note, group)}
isRenderedInActionSheet={isSheet}
@@ -229,12 +226,8 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
type={props.type}
color={props.customAccentColor}
groupOptions={groupOptions}
onOpenJumpToDialog={() => {
eSendEvent(eOpenJumpToDialog, {
ref: props.scrollRef,
data: items
});
}}
ref={props.scrollRef}
data={items}
/>
) : null}
<NotebookWrapper
@@ -260,12 +253,8 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
type={props.type}
groupId={props.groupId}
groupOptions={groupOptions}
onOpenJumpToDialog={() => {
eSendEvent(eOpenJumpToDialog, {
ref: props.scrollRef,
data: items
});
}}
ref={props.scrollRef}
data={items}
/>
) : null}
<ReminderItem
@@ -289,12 +278,8 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
type={props.type}
color={props.customAccentColor}
groupOptions={groupOptions}
onOpenJumpToDialog={() => {
eSendEvent(eOpenJumpToDialog, {
ref: props.scrollRef,
data: items
});
}}
ref={props.scrollRef}
data={items}
/>
) : null}
<TagItem
@@ -319,12 +304,8 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
color={props.customAccentColor}
groupOptions={groupOptions}
itemCount={items?.placeholders.length}
onOpenJumpToDialog={() => {
eSendEvent(eOpenJumpToDialog, {
ref: props.scrollRef,
data: items
});
}}
ref={props.scrollRef}
data={items}
/>
) : null}
<SearchResult item={item as HighlightedResult} />

View File

@@ -43,6 +43,8 @@ import ColorPicker from "../dialogs/color-picker";
import PaywallSheet from "../sheets/paywall";
import { Button } from "../ui/button";
import { Pressable } from "../ui/pressable";
import { Spacing } from "../../common/design/spacing";
import AppIcon from "../ui/AppIcon";
const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
const { colors } = useThemeColors();
@@ -80,12 +82,11 @@ const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
key={item.id}
onPress={toggleColor}
style={{
width: 35,
height: 35,
width: 40,
height: 40,
borderRadius: 100,
justifyContent: "center",
alignItems: "center",
marginRight: 5
alignItems: "center"
}}
>
{isLinked ? (
@@ -151,31 +152,10 @@ export const ColorTags = ({ item }: { item: Note }) => {
/>
<View
style={{
flexGrow: isTablet ? undefined : 1,
flexDirection: "row",
marginLeft: 5,
flexShrink: 2
flexDirection: "row"
}}
>
{!colorNotes || !colorNotes.length ? (
<Button
onPress={onPress}
buttonType={{
text: colors.primary.accent
}}
title={strings.addColor()}
type="secondary"
icon="plus"
iconPosition="right"
height={30}
fontSize={AppFontSize.xs}
style={{
marginRight: 5,
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
/>
) : (
{colorNotes?.length ? (
<LegendList
data={colorNotes}
estimatedItemSize={30}
@@ -184,11 +164,14 @@ export const ColorTags = ({ item }: { item: Note }) => {
bounces={false}
renderItem={renderItem}
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
gap: Spacing.LEVEL_1
}}
ListFooterComponent={
<Pressable
style={{
width: 35,
height: 35,
width: 40,
height: 40,
borderRadius: 100,
justifyContent: "center",
alignItems: "center",
@@ -197,16 +180,17 @@ export const ColorTags = ({ item }: { item: Note }) => {
type="secondary"
onPress={onPress}
>
<Icon
<AppIcon
testID="icon-plus"
iconFamily="notesnook"
name="plus"
color={colors.primary.icon}
color={colors.primary.accent}
size={AppFontSize.lg}
/>
</Pressable>
}
/>
)}
) : null}
</View>
</>
);

View File

@@ -29,6 +29,7 @@ import DateTimePickerModal from "react-native-modal-datetime-picker";
import { db } from "../../common/database";
import { Item, Note } from "@notesnook/core";
import AppIcon from "../ui/AppIcon";
import { Radius, Spacing } from "../../common/design/spacing";
export const DateMeta = ({ item }: { item: Item }) => {
const { colors, isDark } = useThemeColors();
const [isDatePickerVisible, setIsDatePickerVisible] = useState(false);
@@ -50,44 +51,52 @@ export const DateMeta = ({ item }: { item: Item }) => {
key={key}
style={{
flexDirection: "row",
width: "48.5%",
justifyContent: "space-between",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2
backgroundColor: colors.secondary.background,
borderRadius: Radius.XS,
padding: Spacing.LEVEL_2,
gap: Spacing.LEVEL_1,
alignItems: "center"
}}
>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{strings.dateDescFromKey(
key as
| "dateDeleted"
| "dateEdited"
| "dateModified"
| "dateCreated"
| "dateUploaded"
)}
</Paragraph>
<Paragraph
size={AppFontSize.xs}
color={colors.secondary.paragraph}
onPress={
item.type !== "note"
? undefined
: () => {
setIsDatePickerVisible(true);
}
}
>
{getFormattedDate(
key === "dateCreated"
? dateCreated
: (item[key as keyof Item] as string),
"date-time"
)}
{key === "dateCreated" && item.type === "note" ? (
<>
{" "}
<AppIcon name="pencil" size={AppFontSize.md} />
</>
) : null}
</Paragraph>
<View>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{strings.dateDescFromKey(
key as
| "dateDeleted"
| "dateEdited"
| "dateModified"
| "dateCreated"
| "dateUploaded"
)}
</Paragraph>
<Paragraph
size={AppFontSize.xs}
color={colors.primary.paragraph}
fontFamily="MEDIUM"
onPress={
item.type !== "note"
? undefined
: () => {
setIsDatePickerVisible(true);
}
}
>
{getFormattedDate(
key === "dateCreated"
? dateCreated
: (item[key as keyof Item] as string),
"date-time"
)}
</Paragraph>
</View>
{key === "dateCreated" && item.type === "note" ? (
<>
<AppIcon name="edit-pencil" size={10} iconFamily="notesnook" />
</>
) : null}
</View>
);
@@ -119,9 +128,10 @@ export const DateMeta = ({ item }: { item: Item }) => {
<View
style={{
borderTopWidth: 1,
borderTopColor: colors.primary.border,
paddingHorizontal: DefaultAppStyles.GAP,
paddingTop: DefaultAppStyles.GAP_VERTICAL_SMALL
borderColor: colors.primary.border,
paddingVertical: Spacing.LEVEL_2,
flexDirection: "row",
gap: Spacing.LEVEL_2
}}
>
{getDateMeta().map(renderItem)}

View File

@@ -18,14 +18,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
import { eSendEvent, presentSheet } from "../../services/event-manager";
import { eOnLoadNote } from "../../utils/events";
import {
eSendEvent,
presentSheet,
sendItemUpdateEvent,
ToastManager
} from "../../services/event-manager";
import { eOnLoadNote, refreshNotesPage } from "../../utils/events";
import { fluidTabsRef } from "../../utils/global-refs";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
@@ -37,27 +41,43 @@ import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { DateMeta } from "./date-meta";
import { Items } from "./items";
import Notebooks from "./notebooks";
import { TagStrip, Tags } from "./tags";
import { Tags } from "./tags";
import { Dialog } from "../dialog";
const Line = ({ top = 6, bottom = 6 }) => {
const { colors } = useThemeColors();
return (
<View
style={{
height: 1,
backgroundColor: colors.primary.border,
width: "100%",
marginTop: top,
marginBottom: bottom
}}
/>
);
};
import AppIcon from "../ui/AppIcon";
import { Spacing } from "../../common/design/spacing";
import { Button } from "../ui/button";
import ManageTags from "../../screens/manage-tags";
import ColorPicker from "../dialogs/color-picker";
import { useRelationStore } from "../../stores/use-relation-store";
import { useMenuStore } from "../../stores/use-menu-store";
import Navigation from "../../services/navigation";
import { useIsFeatureAvailable } from "@notesnook/common";
import PaywallSheet from "../sheets/paywall";
import { useSettingStore } from "../../stores/use-setting-store";
export const Properties = ({ close = () => {}, item, buttons = [] }) => {
const { colors } = useThemeColors();
const colorFeature = useIsFeatureAvailable("colors");
const [noteNotebooks, setNoteNotebooks] = useState([]);
const [tags, setTags] = useState([]);
const [visible, setVisible] = useState(false);
const colorNotes = useMenuStore((state) => state.colorNotes);
useEffect(() => {
async function getNotebooks() {
let filteredNotebooks = await db.relations.to(item, "notebook").resolve();
return filteredNotebooks || [];
}
if (item.type === "note") {
getNotebooks().then((notebooks) => setNoteNotebooks(notebooks));
db.relations
.to(item, "tag")
.resolve()
.then((tags) => {
setTags(tags);
});
}
}, [item]);
if (!item || !item.id) {
return (
<Paragraph style={{ marginVertical: 10, alignSelf: "center" }}>
@@ -74,7 +94,8 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
backgroundColor: colors.primary.background,
borderBottomRightRadius: DDS.isLargeTablet() ? 10 : 1,
borderBottomLeftRadius: DDS.isLargeTablet() ? 10 : 1,
maxHeight: "100%"
maxHeight: "100%",
paddingTop: Spacing.LEVEL_3
}}
nestedScrollEnabled
bounces={false}
@@ -83,111 +104,240 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
renderItem={() => (
<View
style={{
gap: DefaultAppStyles.GAP_VERTICAL
gap: Spacing.LEVEL_1
}}
>
{item.type === "note" ? (
<ColorPicker
visible={visible}
setVisible={setVisible}
onColorAdded={async (color) => {
await db.relations.to(item, "color").unlink();
await db.relations.add(color, item);
useRelationStore.getState().update();
useMenuStore.getState().setColorNotes();
Navigation.queueRoutesForUpdate();
sendItemUpdateEvent(color.id, "color");
eSendEvent(refreshNotesPage);
}}
/>
) : null}
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: Spacing.LEVEL_3
}}
>
<View
style={{
flexDirection: "row",
justifyContent: "space-between"
}}
>
<View>
<View
style={{
flexDirection: "row",
alignItems: "center",
flexShrink: 1,
gap: 5
gap: Spacing.LEVEL_1
}}
>
{item.type === "color" ? (
<Pressable
type="accent"
accentColor={item.colorCode}
accentText={colors.static.white}
{noteNotebooks?.map((item) => (
<View
key={item.id}
style={{
width: 30,
height: 30,
borderRadius: 100,
marginRight: 10
paddingHorizontal: Spacing.LEVEL_1,
paddingVertical: 2,
backgroundColor: colors.secondary.background,
flexDirection: "row",
alignItems: "center",
gap: Spacing.LEVEL_0
}}
/>
) : item.type === "tag" ? (
<Icon
name="pound"
size={AppFontSize.lg}
color={colors.primary.icon}
/>
) : null}
>
<AppIcon
name="bookmark"
iconFamily="notesnook"
size={AppFontSize.xs}
color={colors.secondary.icon}
/>
<Paragraph fontSize="XS" color={colors.secondary.paragraph}>
{item.title}
</Paragraph>
</View>
))}
<Heading size={AppFontSize.lg}>{item.title}</Heading>
{tags?.map((item) =>
item.id ? (
<View
key={item.id}
style={{
borderRadius: 100,
paddingHorizontal: Spacing.LEVEL_1,
paddingVertical: 2,
backgroundColor: colors.secondary.background,
flexDirection: "row",
alignItems: "center",
gap: Spacing.LEVEL_0
}}
>
<Paragraph
size={AppFontSize.xs}
color={colors.secondary.paragraph}
>
{item.title}
</Paragraph>
</View>
) : null
)}
</View>
{item.type === "note" ? (
<IconButton
name="open-in-new"
type="plain"
color={colors.primary.icon}
size={AppFontSize.lg}
<View
style={{
flexDirection: "row",
justifyContent: "space-between"
}}
>
<View
style={{
alignSelf: "flex-start"
flexDirection: "row",
alignItems: "center",
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
onPress={() => {
close();
eSendEvent(eOnLoadNote, {
item: item,
newTab: true
});
if (!DDS.isTab) {
fluidTabsRef.current?.goToPage("editor");
}
>
{item.type === "color" ? (
<Pressable
type="accent"
accentColor={item.colorCode}
accentText={colors.static.white}
style={{
width: 8,
height: 8,
borderRadius: 100
}}
/>
) : item.type === "tag" ? (
<AppIcon
name="shopping-mode"
iconFamily="evilicons"
size={AppFontSize.lg}
color={colors.primary.icon}
/>
) : null}
<Heading size={AppFontSize.xl}>{item.title}</Heading>
</View>
{item.type === "note" ? (
<IconButton
name="square-out"
iconFamily="notesnook"
type="plain"
color={colors.primary.icon}
size={AppFontSize.lg}
style={{
alignSelf: "flex-start"
}}
onPress={() => {
close();
eSendEvent(eOnLoadNote, {
item: item,
newTab: true
});
if (!DDS.isTab) {
fluidTabsRef.current?.goToPage("editor");
}
}}
/>
) : null}
</View>
{(item.type === "notebook" || item.type === "reminder") &&
item.description ? (
<Paragraph>{item.description}</Paragraph>
) : null}
{item.type === "reminder" ? (
<ReminderTime
reminder={item}
style={{
justifyContent: "flex-start",
borderWidth: 0,
alignSelf: "flex-start",
backgroundColor: "transparent",
paddingHorizontal: 0,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
fontSize={AppFontSize.xs}
/>
) : null}
</View>
{(item.type === "notebook" || item.type === "reminder") &&
item.description ? (
<Paragraph>{item.description}</Paragraph>
<DateMeta item={item} />
{item.type === "note" && colorNotes.length > 0 ? (
<Tags close={close} item={item} />
) : null}
{item.type === "note" ? (
<TagStrip close={close} item={item} />
) : null}
{item.type === "reminder" ? (
<ReminderTime
reminder={item}
style={{
justifyContent: "flex-start",
borderWidth: 0,
alignSelf: "flex-start",
backgroundColor: "transparent",
paddingHorizontal: 0,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
<View
style={{
flexDirection: "row",
borderBottomWidth: 1,
borderTopWidth: colorNotes.length > 0 ? 1 : 0,
borderColor: colors.primary.border,
paddingVertical: Spacing.LEVEL_2,
paddingTop: colorNotes.length > 0 ? Spacing.LEVEL_2 : 0,
gap: Spacing.LEVEL_2
}}
>
<Button
onPress={async () => {
ManageTags.present([item.id]);
close();
}}
buttonType={{
text: colors.primary.paragraph
}}
title={strings.addTag()}
type={colorNotes?.length ? "accent-outline" : "shade"}
icon="plus"
iconFamily="notesnook"
style={{
paddingHorizontal: Spacing.LEVEL_3,
paddingVertical: Spacing.LEVEL_2,
width: colorNotes?.length > 0 ? "100%" : "48.5%"
}}
fontSize={AppFontSize.xs}
/>
) : null}
{colorNotes.length > 0 ? null : (
<Button
onPress={() => {
if (colorFeature && !colorFeature.isAllowed) {
ToastManager.show({
message: colorFeature.error,
type: "info",
context: "local",
actionText: strings.upgrade(),
func: () => {
PaywallSheet.present(colorFeature);
ToastManager.hide();
}
});
return;
}
useSettingStore.getState().setSheetKeyboardHandler(false);
setVisible(true);
}}
title={strings.addColor()}
type="secondaryAccented"
icon="plus"
iconFamily="notesnook"
style={{
width: "48.5%",
paddingHorizontal: Spacing.LEVEL_3,
paddingVertical: Spacing.LEVEL_2
}}
/>
)}
</View>
</View>
<DateMeta item={item} />
<Line bottom={0} top={0} />
{item.type === "note" ? (
<>
<Tags close={close} item={item} />
<Line bottom={0} top={0} />
</>
) : null}
{item.type === "note" ? (
{/* {item.type === "note" ? (
<Notebooks note={item} close={close} />
) : null}
) : null} */}
<Items
item={item}
buttons={buttons}

View File

@@ -33,6 +33,7 @@ import AppIcon from "../ui/AppIcon";
import { Button } from "../ui/button";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
import { Radius, Spacing } from "../../common/design/spacing";
const TOP_BAR_ITEMS: ActionId[] = [
"pin",
@@ -152,7 +153,7 @@ export const Items = ({
key={item.id}
style={{
alignItems: "center",
width: columnItemWidth - 8,
width: columnItemWidth - 10,
opacity: item.locked ? 0.5 : 1
}}
>
@@ -161,12 +162,12 @@ export const Items = ({
type={item.checked ? "shade" : "secondary"}
testID={"icon-" + item.id}
style={{
height: columnItemWidth / 1.5,
width: columnItemWidth - 8,
width: columnItemWidth - 10,
paddingVertical: Spacing.LEVEL_2,
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
marginBottom: DDS.isTab ? 7 : 3.5
marginBottom: 6
}}
>
<Icon
@@ -253,7 +254,7 @@ export const Items = ({
key={item.id}
testID={"icon-" + item.id}
style={{
width: columnItemWidth - 8,
width: columnItemWidth - 10,
alignSelf: "flex-start",
gap: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
@@ -261,24 +262,25 @@ export const Items = ({
<View
style={{
height: columnItemWidth / 2,
width: columnItemWidth - DefaultAppStyles.GAP_SMALL,
width: 65,
justifyContent: "center",
alignItems: "center",
borderWidth: 1,
borderRadius: defaultBorderRadius,
borderColor: item.checked
? item.activeColor || colors.primary.accent
: colors.primary.border,
overflow: "hidden"
backgroundColor: item.checked
? colors.primary.shade
: colors.secondary.background,
borderRadius: Radius.XS,
overflow: "hidden",
paddingVertical: Spacing.LEVEL_2,
paddingHorizontal: Spacing.LEVEL_2
}}
>
<Icon
name={item.icon}
allowFontScaling
size={DDS.isTab ? AppFontSize.xxl : AppFontSize.md + 4}
size={16}
color={
item.checked
? item.activeColor || colors.primary.accent
? colors.primary.icon
: item.id === "delete" || item.id === "trash"
? colors.error.icon
: colors.secondary.icon
@@ -310,7 +312,13 @@ export const Items = ({
<Paragraph
textBreakStrategy="simple"
size={AppFontSize.xxs}
fontSize="XXS"
fontFamily="MEDIUM"
color={
item.checked
? colors.primary.paragraph
: colors.secondary.paragraph
}
style={{ textAlign: "center" }}
>
{item.title}
@@ -321,8 +329,12 @@ export const Items = ({
[
colors.error.icon,
colors.primary.accent,
colors.primary.border,
colors.primary.icon,
colors.primary.paragraph,
colors.primary.shade,
colors.secondary.background,
colors.secondary.icon,
colors.secondary.paragraph,
colors.static.orange,
columnItemWidth,
topBarSorting
@@ -352,16 +364,18 @@ export const Items = ({
autoplay={false}
showPagination
paginationStyleItemActive={{
borderRadius: 2,
backgroundColor: colors.selected.background,
height: 6,
marginHorizontal: 2
borderRadius: 6,
backgroundColor: colors.selected.accent,
height: 5,
width: 20,
marginHorizontal: 3
}}
paginationStyleItemInactive={{
borderRadius: 2,
borderRadius: 6,
backgroundColor: colors.secondary.background,
height: 6,
marginHorizontal: 2
height: 5,
width: 14,
marginHorizontal: 3
}}
paginationStyle={{
position: "relative",
@@ -380,7 +394,7 @@ export const Items = ({
style={{
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP,
gap: 5,
gap: Spacing.LEVEL_2,
width: width
}}
>
@@ -394,7 +408,7 @@ export const Items = ({
style={{
flexDirection: "row",
flexWrap: "wrap",
gap: 5,
gap: Spacing.LEVEL_1,
paddingHorizontal: DefaultAppStyles.GAP
}}
>

View File

@@ -17,18 +17,17 @@ 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 { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import { db } from "../../common/database";
import ManageTags from "../../screens/manage-tags";
import { TaggedNotes } from "../../screens/notes/tagged";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { sleep } from "../../utils/time";
import { Button } from "../ui/button";
import { ColorTags } from "./color-tags";
import { Spacing } from "../../common/design/spacing";
export const Tags = ({ item, close }) => {
const { colors } = useThemeColors();
@@ -37,32 +36,12 @@ export const Tags = ({ item, close }) => {
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
alignSelf: "center",
justifyContent: "space-between",
width: "100%"
width: "100%",
borderTopWidth: 1,
borderColor: colors.primary.border,
paddingVertical: Spacing.LEVEL_3
}}
>
<Button
onPress={async () => {
ManageTags.present([item.id]);
close();
}}
buttonType={{
text: colors.primary.accent
}}
title={strings.addTag()}
type="secondary"
icon="plus"
iconPosition="right"
fontSize={AppFontSize.xs}
style={{
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
}}
/>
<ColorTags item={item} />
</View>
) : null;

View File

@@ -40,6 +40,7 @@ import { getElevationStyle } from "../../../utils/elevation";
import { defaultBorderRadius } from "../../../utils/size";
import { useThemeColors } from "@notesnook/theme";
import { getContainerBorder } from "../../../utils/colors";
import { Radius, Spacing } from "../../../common/design/spacing";
export const AddNotebookSheet = ({
notebook,
@@ -127,53 +128,63 @@ export const AddNotebookSheet = ({
...getElevationStyle(5),
width: DDS.isTab ? 400 : "85%",
maxHeight: 450,
borderRadius: defaultBorderRadius,
borderRadius: Radius.LG,
backgroundColor: colors.primary.background,
paddingTop: 12,
gap: Spacing.LEVEL_4,
paddingVertical: Spacing.LEVEL_4,
...getContainerBorder(colors.primary.border, 0.5),
overflow: "hidden"
}}
>
<View
style={{
paddingHorizontal: 12
paddingHorizontal: Spacing.LEVEL_3,
gap: Spacing.LEVEL_4
}}
>
<DialogHeader
title={notebook ? strings.editNotebook() : strings.newNotebook()}
/>
<Input
fwdRef={titleInput}
testID={notesnook.ids.dialogs.notebook.inputs.title}
onChangeText={(value) => {
title.current = value;
<View
style={{
gap: Spacing.LEVEL_2
}}
onLayout={() => {
setTimeout(() => {
titleInput?.current?.focus();
}, 300);
}}
placeholder={strings.enterNotebookTitle()}
onSubmit={() => {
descriptionInput.current?.focus();
}}
returnKeyLabel="Next"
returnKeyType="next"
defaultValue={notebook ? notebook.title : title.current}
/>
>
<Input
fwdRef={titleInput}
testID={notesnook.ids.dialogs.notebook.inputs.title}
onChangeText={(value) => {
title.current = value;
}}
onLayout={() => {
setTimeout(() => {
titleInput?.current?.focus();
}, 300);
}}
placeholder={"eg. My Notebook"}
onSubmit={() => {
descriptionInput.current?.focus();
}}
label={strings.enterNotebookTitle()}
returnKeyLabel="Next"
returnKeyType="next"
defaultValue={notebook ? notebook.title : title.current}
/>
<Input
fwdRef={descriptionInput}
testID={notesnook.ids.dialogs.notebook.inputs.description}
onChangeText={(value) => {
description.current = value;
}}
placeholder={strings.enterNotebookDescription()}
returnKeyLabel={strings.next()}
returnKeyType="next"
defaultValue={notebook ? notebook.description : ""}
/>
<Input
fwdRef={descriptionInput}
testID={notesnook.ids.dialogs.notebook.inputs.description}
onChangeText={(value) => {
description.current = value;
}}
label={strings.enterNotebookDescription()}
placeholder={"eg. This is My Notebook"}
returnKeyLabel={strings.next()}
returnKeyType="next"
defaultValue={notebook ? notebook.description : ""}
/>
</View>
</View>
<DialogButtons
onPressNegative={() => {

View File

@@ -19,19 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import {
GroupingByIdKey,
GroupHeader,
GroupingKey,
GroupOptions,
Item,
ItemType,
SortOptions
SortOptions,
VirtualizedGrouping
} from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useState } from "react";
import { View } from "react-native";
import {
getGroupOptions,
setGroupOptionsById
} from "../../../hooks/use-group-options";
import React, { RefObject, useEffect, useRef, useState } from "react";
import { FlatList, View } from "react-native";
import { eSendEvent } from "../../../services/event-manager";
import Navigation from "../../../services/navigation";
import { RouteName } from "../../../stores/use-navigation-store";
@@ -46,13 +49,20 @@ import { Button } from "../../ui/button";
import { Pressable } from "../../ui/pressable";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { Radius, Spacing } from "../../../common/design/spacing";
import { getElevationStyle } from "../../../utils/elevation";
import { useMessageStore } from "../../../stores/use-message-store";
const Sort = ({
dataType,
screen,
hideGroupOptions,
group: groupType,
groupId,
type
type,
hideJumpToSection,
ref,
data
}: {
dataType: ItemType;
type?: GroupingByIdKey;
@@ -60,29 +70,42 @@ const Sort = ({
group: GroupingKey;
hideGroupOptions?: boolean;
groupId?: string;
hideJumpToSection?: boolean;
data?: VirtualizedGrouping<Item>;
ref?: RefObject<FlatList>;
}) => {
const { colors } = useThemeColors();
const [groups, setGroups] = useState<
{
index: number;
group: GroupHeader;
}[]
>();
const offsets = useRef<number[]>([]);
const scrollRef = useRef<RefObject<FlatList>>(undefined);
const [currentIndex, setCurrentIndex] = useState(0);
const currentScrollPosition = useRef(0);
const [groupOptions, setGroupOptions] = useState(
getGroupOptions(groupType, groupId, type)
);
const getSortButtonTitle = () => {
const { sortDirection, groupBy, sortBy } = groupOptions || {};
const getSortButtonTitle = (type: "asc" | "desc") => {
const { groupBy, sortBy } = groupOptions || {};
const isAlphabetical = groupBy === "abc" || sortBy === "title";
const isDueDate = sortBy === "dueDate";
const isRelevance = sortBy === "relevance";
if (sortDirection === "asc") {
if (type === "asc") {
if (isAlphabetical) return strings.aToZ();
if (isDueDate) return strings.earliestFirst();
if (isRelevance) return strings.leastRelevantFirst();
return strings.oldNew();
return strings.oldestFirst();
} else {
if (isAlphabetical) return strings.zToA();
if (isDueDate) return strings.latestFirst();
if (isRelevance) return strings.mostRelevantFirst();
return strings.newOld();
return strings.newestFirst();
}
};
@@ -111,13 +134,49 @@ const Sort = ({
await updateGroupOptions(_groupOptions);
};
useEffect(() => {
data?.groups?.().then((groups) => {
setGroups(groups);
offsets.current = [];
groups.map((item, index) => {
let offset = 35 * index;
let groupIndex = item.index;
const messageState = useMessageStore.getState().message;
const msgOffset = messageState?.visible ? 60 : 10;
groupIndex = groupIndex + 1;
groupIndex = groupIndex - (index + 1);
offset = offset + groupIndex * 100 + msgOffset;
offsets.current.push(offset);
});
const index = offsets.current?.findIndex((o, i) => {
return (
o <= currentScrollPosition.current + 100 &&
offsets.current[i + 1] - 100 > currentScrollPosition.current
);
});
setCurrentIndex(index < 0 ? 0 : index);
});
}, [data]);
const onPress = (item: { index: number; group: GroupHeader }) => {
scrollRef.current?.current?.scrollToIndex({
index: item.index,
animated: true
});
close();
};
return (
<View
style={{
width: "100%",
backgroundColor: colors.primary.background,
justifyContent: "space-between",
gap: DefaultAppStyles.GAP_SMALL
gap: Spacing.LEVEL_3,
paddingTop: Spacing.LEVEL_3
}}
>
<View
@@ -128,9 +187,9 @@ const Sort = ({
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<Heading size={AppFontSize.lg}>{strings.sortBy()}</Heading>
<Heading fontSize="LG">{strings.sortBy()}</Heading>
<Button
{/* <Button
title={getSortButtonTitle()}
icon={
groupOptions?.sortDirection === "asc"
@@ -145,14 +204,16 @@ const Sort = ({
paddingHorizontal: DefaultAppStyles.GAP_SMALL
}}
onPress={setOrderBy}
/>
/> */}
</View>
<View
style={{
flexDirection: "column",
justifyContent: "flex-start",
borderBottomColor: colors.primary.border
borderBottomColor: colors.primary.border,
paddingHorizontal: Spacing.LEVEL_3,
gap: Spacing.LEVEL_3
}}
>
{Object.keys(SORT).map((item) => {
@@ -178,40 +239,92 @@ const Sort = ({
}
return (
<Pressable
<View
key={item}
type={groupOptions?.sortBy === item ? "selected" : "plain"}
noborder
style={{
width: "100%",
justifyContent: "space-between",
flexDirection: "row",
borderRadius: 0,
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
}}
onPress={async () => {
const _groupOptions: GroupOptions = {
...groupOptions,
sortBy: item as SortOptions["sortBy"]
};
await updateGroupOptions(_groupOptions);
gap: Spacing.LEVEL_2
}}
>
<Paragraph>
{strings.sortByStrings[
item as keyof typeof strings.sortByStrings
]()}
</Paragraph>
<Pressable
type={
groupOptions?.sortBy === item ? "selected" : "plain-outline"
}
style={{
width: "100%",
justifyContent: "space-between",
flexDirection: "row",
borderRadius: Radius.XS,
paddingHorizontal: Spacing.LEVEL_2,
paddingVertical: Spacing.LEVEL_2
}}
onPress={async () => {
const _groupOptions: GroupOptions = {
...groupOptions,
sortBy: item as SortOptions["sortBy"]
};
await updateGroupOptions(_groupOptions);
}}
>
<Paragraph>
{strings.sortByStrings[
item as keyof typeof strings.sortByStrings
]()}
</Paragraph>
{groupOptions?.sortBy === item ? (
<AppIcon
size={AppFontSize.lg}
name="check"
color={colors.selected.accent}
/>
{groupOptions?.sortBy === item ? (
<AppIcon
size={AppFontSize.lg}
name="checkbox"
iconFamily="notesnook"
color={[colors.selected.accent, "white"]}
/>
) : null}
</Pressable>
{groupOptions.sortBy === item ? (
<View
style={{
backgroundColor: colors.secondary.background,
borderRadius: Radius.S,
padding: Spacing.LEVEL_1,
flexDirection: "row",
gap: Spacing.LEVEL_2
}}
>
<Button
style={{
flexGrow: 1,
borderRadius: Radius.XS,
...(groupOptions?.sortDirection === "desc"
? getElevationStyle(10)
: {})
}}
type={
groupOptions?.sortDirection === "desc"
? "accent-background"
: "plain"
}
title={getSortButtonTitle("desc")}
/>
<Button
style={{
flexGrow: 1,
borderRadius: Radius.XS,
...(groupOptions?.sortDirection === "asc"
? getElevationStyle(10)
: {})
}}
type={
groupOptions?.sortDirection === "asc"
? "accent-background"
: "plain"
}
title={getSortButtonTitle("asc")}
/>
</View>
) : null}
</Pressable>
</View>
);
})}
</View>
@@ -223,18 +336,19 @@ const Sort = ({
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: Spacing.LEVEL_3,
paddingBottom: Spacing.LEVEL_3
}}
>
<Heading size={AppFontSize.lg}>{strings.groupBy()}</Heading>
<Heading fontSize="LG">{strings.groupBy()}</Heading>
</View>
<View
style={{
borderRadius: 0,
flexDirection: "row",
flexWrap: "wrap"
flexWrap: "wrap",
paddingHorizontal: Spacing.LEVEL_3,
gap: Spacing.LEVEL_2
}}
>
{Object.keys(GROUP).map((item) => (
@@ -243,16 +357,14 @@ const Sort = ({
type={
groupOptions?.groupBy === GROUP[item as keyof typeof GROUP]
? "selected"
: "plain"
: "plain-outline"
}
noborder
style={{
width: "100%",
justifyContent: "space-between",
flexDirection: "row",
borderRadius: 0,
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
width: "auto",
borderRadius: 100,
paddingHorizontal: Spacing.LEVEL_3,
paddingVertical: Spacing.LEVEL_1
}}
onPress={async () => {
const _groupOptions: GroupOptions = {
@@ -262,24 +374,82 @@ const Sort = ({
await updateGroupOptions(_groupOptions);
}}
>
<Paragraph>
<Paragraph
fontFamily={
groupOptions?.groupBy === GROUP[item as keyof typeof GROUP]
? "SEMI_BOLD"
: "REGULAR"
}
color={
groupOptions?.groupBy === GROUP[item as keyof typeof GROUP]
? colors.primary.paragraph
: colors.secondary.paragraph
}
>
{strings.groupByStrings[
item as keyof typeof strings.groupByStrings
]()}
</Paragraph>
{groupOptions.groupBy === item ? (
<AppIcon
size={AppFontSize.lg}
name="check"
color={colors.selected.accent}
/>
) : null}
</Pressable>
))}
</View>
</>
) : null}
{!hideJumpToSection && groups ? (
<>
<View
style={{
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: Spacing.LEVEL_3,
paddingBottom: Spacing.LEVEL_3
}}
>
<Heading fontSize="LG">{strings.jumpToGroup()}</Heading>
</View>
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
paddingHorizontal: Spacing.LEVEL_3,
gap: Spacing.LEVEL_2
}}
>
{groups?.map((item, index) => {
return (
<Pressable
key={item.group.id}
onPress={() => onPress(item)}
type={currentIndex === index ? "selected" : "plain-outline"}
style={{
minWidth: "20%",
width: null,
borderRadius: 100,
paddingHorizontal: Spacing.LEVEL_3,
paddingVertical: Spacing.LEVEL_1
}}
>
<Paragraph
size={AppFontSize.sm}
fontFamily={
currentIndex === index ? "SEMI_BOLD" : "REGULAR"
}
color={colors.primary.paragraph}
style={{
textAlign: "center"
}}
>
{item.group.title}
</Paragraph>
</Pressable>
);
})}
</View>
</>
) : null}
</View>
);
};

View File

@@ -21,7 +21,6 @@ import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import { useGroupOptions } from "../../hooks/use-group-options";
import { presentSheet, ToastManager } from "../../services/event-manager";
@@ -34,9 +33,7 @@ import { DefaultAppStyles } from "../../utils/styles";
import { presentDialog } from "../dialog/functions";
import { AddNotebookSheet } from "../sheets/add-notebook";
import Sort from "../sheets/sort";
import { IconButton } from "../ui/icon-button";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
import { SideMenuHome } from "./side-menu-home";
import { SideMenuNotebooks } from "./side-menu-notebooks";
import { SideMenuTags } from "./side-menu-tags";
@@ -44,12 +41,14 @@ import {
useSideMenuNotebookSelectionStore,
useSideMenuTagsSelectionStore
} from "./stores";
import { TabBarButton } from "./tab-bar-button";
import { useSideBarDraggingStore } from "./dragging-store";
import { Button } from "../ui/button";
import SettingsService from "../../services/settings";
import { isFeatureAvailable } from "@notesnook/common";
import PaywallSheet from "../sheets/paywall";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import { Spacing } from "../../common/design/spacing";
/**
* Simple Tab View Implementation for the Side bar
@@ -77,7 +76,7 @@ type SimpleTabViewProps = {
};
const createSceneMap = (
scenes: Record<string, React.ComponentType<any>>
scenes: Record<string, React.ComponentType<unknown>>
): ((props: { route: SimpleRoute }) => React.ReactNode) => {
// eslint-disable-next-line react/display-name
return ({ route }: { route: SimpleRoute }) => {
@@ -216,55 +215,61 @@ const TabBar = (props: SimpleTabBarProps) => {
const getIcon = (key: string) => {
switch (key) {
case "home":
return "home-outline";
return "home";
case "notebooks":
return "book-outline";
return "bookmark";
case "tags":
return "pound";
return "shopping-mode";
default:
return "home-outline";
return "home";
}
};
return (
<View
style={{
flexDirection: "row",
width: "100%",
justifyContent: "space-between",
backgroundColor: colors.primary.background,
paddingHorizontal: DefaultAppStyles.GAP,
paddingVertical: DefaultAppStyles.GAP_SMALL,
borderTopWidth: 1,
borderTopColor: colors.primary.border
paddingHorizontal: Spacing.LEVEL_3
}}
>
{isSelectionEnabled ? (
<>
{[
{
title: "Select all",
icon: "check-all"
},
{
title: "Delete",
icon: "delete"
},
{
title: "Move",
icon: "arrow-right-bold-box-outline",
hidden:
!notebookSelectionEnabled || props.navigationState.index !== 1
},
{
title: "Close",
icon: "close"
}
].map((item) =>
item.hidden ? null : (
<>
<Pressable
<View
style={{
flexDirection: "row",
width: "100%",
justifyContent: "space-between",
backgroundColor: colors.primary.background,
borderTopWidth: 1,
borderTopColor: colors.primary.border,
paddingTop: Spacing.LEVEL_2
}}
>
{isSelectionEnabled ? (
<>
{[
{
title: "Select all",
icon: "checks"
},
{
title: "Delete",
icon: "trash"
},
{
title: "Move",
icon: "drive-file-move",
hidden:
!notebookSelectionEnabled || props.navigationState.index !== 1
},
{
title: "Close",
icon: "close"
}
].map((item) =>
item.hidden ? null : (
<TabBarButton
key={item.title}
icon={item.icon}
label={item.title}
onPress={async () => {
switch (item.title) {
case "Select all": {
@@ -325,221 +330,177 @@ const TabBar = (props: SimpleTabBarProps) => {
}
}
}}
/>
)
)}
</>
) : (
<>
{dragging ? (
<Button
onPress={() => {
useSideBarDraggingStore.setState({
dragging: false
});
}}
style={{
width: "100%"
}}
type="accent"
testID="check"
title={strings.done()}
icon={"check"}
iconSize={AppFontSize.lg - 2}
/>
) : (
<>
<View
style={{
borderRadius: 10,
paddingVertical: 2,
width: "25%"
flexDirection: "row",
gap: Spacing.LEVEL_2
}}
type="plain"
>
<Icon
name={item.icon}
color={colors.primary.icon}
size={AppFontSize.lg}
/>
<Paragraph
color={colors.primary.paragraph}
size={AppFontSize.xxxs - 1}
>
{item.title}
</Paragraph>
</Pressable>
</>
)
)}
</>
) : (
<>
{dragging ? (
<Button
onPress={() => {
useSideBarDraggingStore.setState({
dragging: false
});
}}
style={{
width: "100%"
}}
type="accent"
testID="check"
title={strings.done()}
icon={"check"}
iconSize={AppFontSize.lg - 2}
/>
) : (
<>
<View
style={{
flexDirection: "row",
gap: DefaultAppStyles.GAP_SMALL
}}
>
{props.navigationState.routes.map((route, index) => {
const isFocused = props.navigationState.index === index;
{props.navigationState.routes.map((route, index) => {
const isFocused = props.navigationState.index === index;
return (
<Pressable
key={route.key}
testID={`tab-${route.key}`}
onPress={() => {
props.jumpTo(route.key);
switch (route.key) {
case "notebooks":
Navigation.routeNeedsUpdate(
"Notebooks",
Navigation.routeUpdateFunctions.Notebooks
);
break;
case "tags":
Navigation.routeNeedsUpdate(
"Tags",
Navigation.routeUpdateFunctions.Tags
);
break;
default:
break;
}
}}
style={{
borderRadius: 10,
paddingVertical: 2,
width: 40,
height: 40
}}
type={isFocused ? "selected" : "plain"}
>
<Icon
name={getIcon(route.key)}
color={
isFocused ? colors.selected.icon : colors.primary.icon
}
size={AppFontSize.lg}
return (
<TabBarButton
key={route.key}
testID={`tab-${route.key}`}
icon={getIcon(route.key)}
label={route.title || ""}
isActive={isFocused}
onPress={() => {
props.jumpTo(route.key);
switch (route.key) {
case "notebooks":
Navigation.routeNeedsUpdate(
"Notebooks",
Navigation.routeUpdateFunctions.Notebooks
);
break;
case "tags":
Navigation.routeNeedsUpdate(
"Tags",
Navigation.routeUpdateFunctions.Tags
);
break;
default:
break;
}
}}
/>
</Pressable>
);
})}
</View>
);
})}
</View>
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
}}
>
{props.navigationState.index > 0 ? (
<>
<IconButton
name="plus"
testID="sidebar-add-button"
size={AppFontSize.lg - 2}
top={10}
color={colors.primary.icon}
onPress={async () => {
if (props.navigationState.index === 1) {
const notebooksFeature =
await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
PaywallSheet.present(notebooksFeature);
return;
}
AddNotebookSheet.present();
} else {
const tagsFeature = await isFeatureAvailable("tags");
if (!tagsFeature.isAllowed) {
PaywallSheet.present(tagsFeature);
return;
}
presentDialog({
title: strings.addTag(),
paragraph: strings.addTagDesc(),
input: true,
positiveText: "Add",
positivePress: async (tag) => {
if (tag) {
await db.tags.add({
title: tag
});
useTagStore.getState().refresh();
return true;
}
ToastManager.show({
context: "local",
type: "error",
message: strings.allFieldsRequired()
});
return false;
}
});
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
}}
>
{props.navigationState.index > 0 ? (
<>
<TabBarButton
icon="plus"
testID="sidebar-add-button"
label={
props.navigationState.index === 1 ? "Notebook" : "Tag"
}
}}
style={{
width: 35,
height: 35
}}
/>
onPress={async () => {
if (props.navigationState.index === 1) {
const notebooksFeature =
await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
PaywallSheet.present(notebooksFeature);
return;
}
<IconButton
name={
groupOptions?.sortDirection === "asc"
? "sort-ascending"
: "sort-descending"
}
top={10}
testID="sidebar-sort-button"
color={colors.primary.icon}
onPress={() => {
presentSheet({
component: (
<Sort
dataType={
props.navigationState.index === 1
? "notebook"
: "tag"
AddNotebookSheet.present();
} else {
const tagsFeature =
await isFeatureAvailable("tags");
if (!tagsFeature.isAllowed) {
PaywallSheet.present(tagsFeature);
return;
}
presentDialog({
title: strings.addTag(),
inputLabel: "Enter title",
inputPlaceholder: "eg. journal",
input: true,
positiveText: "Add",
positivePress: async (tag) => {
if (tag) {
await db.tags.add({
title: tag
});
useTagStore.getState().refresh();
return true;
}
ToastManager.show({
context: "local",
type: "error",
message: strings.allFieldsRequired()
});
return false;
}
group={
props.navigationState.index === 1
? "notebooks"
: "tags"
}
hideGroupOptions
/>
)
});
}}
style={{
width: 35,
height: 35
}}
size={AppFontSize.lg - 2}
/>
</>
) : null}
});
}
}}
/>
{props.navigationState.index === 0 ? (
<>
<IconButton
onPress={() => {
useThemeStore.getState().setColorScheme();
}}
style={{
width: 28,
height: 28
}}
top={10}
testID="sidebar-theme-button"
color={colors.primary.icon}
name={isDark ? "weather-night" : "weather-sunny"}
size={AppFontSize.lg - 2}
/>
</>
) : null}
</View>
</>
)}
</>
)}
<TabBarButton
icon={
groupOptions?.sortDirection === "asc"
? "sort-ascending"
: "sort-descending"
}
testID="sidebar-sort-button"
label="Sort"
onPress={() => {
presentSheet({
component: (
<Sort
type={
props.navigationState.index === 1
? "notebook"
: "tag"
}
group={
props.navigationState.index === 1
? "notebooks"
: "tags"
}
hideGroupOptions
/>
)
});
}}
/>
</>
) : null}
{props.navigationState.index === 0 ? (
<>
<TabBarButton
icon={isDark ? "dark-mode-outline" : "sun"}
testID="sidebar-theme-button"
label={isDark ? "Dark" : "Light"}
onPress={() => {
useThemeStore.getState().setColorScheme();
}}
/>
</>
) : null}
</View>
</>
)}
</>
)}
</View>
</View>
);
};

View File

@@ -20,10 +20,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef, useState } from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useTotalNotes } from "../../hooks/use-db-item";
import { db } from "../../common/database";
import { Radius, Spacing } from "../../common/design/spacing";
import {
eSubscribeEvent,
subscribeToItemUpdate
@@ -32,14 +32,14 @@ import Navigation from "../../services/navigation";
import useNavigationStore, {
RouteParams
} from "../../stores/use-navigation-store";
import { useRelationStore } from "../../stores/use-relation-store";
import { eAfterSync, eMenuItemUpdate } from "../../utils/events";
import { SideMenuItem } from "../../utils/menu-items";
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { AppFontSize } from "../../utils/size";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
import { useSideBarDraggingStore } from "./dragging-store";
import { useRelationStore } from "../../stores/use-relation-store";
import AppIcon from "../ui/AppIcon";
export function MenuItem({
item,
@@ -144,30 +144,32 @@ export function MenuItem({
style={{
width: "100%",
alignSelf: "center",
borderRadius: defaultBorderRadius,
borderRadius: Radius.XS,
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
paddingHorizontal: Spacing.LEVEL_1,
justifyContent: "space-between",
alignItems: "center",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL
paddingVertical: Spacing.LEVEL_1,
marginBottom: Spacing.LEVEL_0
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL,
flexShrink: 1
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
>
{renderIcon ? (
renderIcon(item, AppFontSize.md)
) : (
<Icon
<AppIcon
style={{
textAlignVertical: "center",
textAlign: "left"
}}
iconFamily="notesnook"
allowFontScaling
name={item.icon}
color={
@@ -185,20 +187,21 @@ export function MenuItem({
color={
isFocused ? colors.selected.paragraph : colors.primary.paragraph
}
size={AppFontSize.sm}
style={{ flexShrink: 1 }}
fontFamily={isFocused ? "MEDIUM" : "REGULAR"}
fontSize="SM"
>
{item.title}
</Paragraph>
</View>
<Paragraph
size={AppFontSize.xxs}
fontSize="XS"
color={
isFocused ? colors.primary.paragraph : colors.secondary.paragraph
}
style={{
marginLeft: DefaultAppStyles.GAP_SMALL
marginLeft: Spacing.LEVEL_1
}}
>
{menuItemCount}

View File

@@ -24,19 +24,20 @@ import { StoreApi, UseBoundStore } from "zustand";
import { useTotalNotes } from "../../hooks/use-db-item";
import {
eSubscribeEvent,
eUnSubscribeEvent,
ToastManager
eUnSubscribeEvent
} from "../../services/event-manager";
import { TreeItem } from "../../stores/create-notebook-tree-stores";
import { SelectionStore } from "../../stores/item-selection-store";
import { eOnNotebookUpdated } from "../../utils/events";
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import AppIcon from "../ui/AppIcon";
import { IconButton } from "../ui/icon-button";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
import { useRelationStore } from "../../stores/use-relation-store";
import { Radius, Spacing } from "../../common/design/spacing";
import Heading from "../ui/typography/heading";
import { AddNotebookSheet } from "../sheets/add-notebook";
export const NotebookItem = ({
index,
@@ -94,20 +95,31 @@ export const NotebookItem = ({
};
}, [item.notebook.id, notebook.id, onItemUpdate]);
const itemPadding =
item.depth === 0 ? undefined : item.depth < 6 ? 15 * item.depth : 15 * 5;
return (
<View
style={{
paddingLeft:
item.depth === 0
? undefined
: item.depth < 6
? 15 * item.depth
: 15 * 5,
paddingLeft: itemPadding,
width: "100%",
marginTop: 2,
opacity: item.disabled ? 0.5 : 1
opacity: item.disabled ? 0.5 : 1,
paddingBottom: Spacing.LEVEL_0
}}
>
{item.depth > 0 ? (
<View
style={{
height: "100%",
width: 1,
backgroundColor: colors.primary.border,
top: 0,
bottom: 0,
position: "absolute",
left: itemPadding
}}
/>
) : null}
<Pressable
type={isFocused || selected ? "selected" : "transparent"}
onLongPress={onLongPress}
@@ -155,47 +167,39 @@ export const NotebookItem = ({
width: "100%",
alignItems: "center",
flexDirection: "row",
borderRadius: defaultBorderRadius,
paddingRight: DefaultAppStyles.GAP_SMALL
borderRadius: Radius.XS,
paddingVertical: Spacing.LEVEL_1,
paddingHorizontal: Spacing.LEVEL_1,
marginBottom:
expanded && item.hasChildren ? Spacing.LEVEL_0 : undefined
// borderLeftWidth: item.depth > 0 ? 1 : undefined,
// borderLeftColor: colors.primary.border
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
flexShrink: 1
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
>
<IconButton
size={AppFontSize.md}
color={
selected || isFocused ? colors.selected.icon : colors.primary.icon
}
testID={item.hasChildren ? `expand-notebook-${index}` : ""}
onPress={() => {
if (item.hasChildren && !disableExpand) {
onToggleExpanded?.();
} else {
onPress?.();
{item.depth === 0 ? (
<AppIcon
size={AppFontSize.md}
color={
selected || isFocused
? colors.selected.icon
: colors.primary.icon
}
}}
top={0}
left={50}
bottom={0}
right={40}
style={{
width: 32,
height: 32,
borderRadius: defaultBorderRadius
}}
name={
!item.hasChildren || disableExpand
? "book-outline"
: expanded
? "chevron-down"
: "chevron-right"
}
/>
testID={item.hasChildren ? `expand-notebook-${index}` : ""}
style={{
borderRadius: defaultBorderRadius
}}
iconFamily="notesnook"
name={"bookmark"}
/>
) : null}
<Paragraph
color={
@@ -210,34 +214,30 @@ export const NotebookItem = ({
<View
style={{
gap: DefaultAppStyles.GAP_SMALL,
gap: Spacing.LEVEL_1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
marginLeft: DefaultAppStyles.GAP_SMALL
marginLeft: Spacing.LEVEL_1
}}
>
{selectionEnabled ? (
<View
style={{
width: 25,
height: 25,
justifyContent: "center",
alignItems: "center"
}}
>
<AppIcon
name={selected ? "checkbox-outline" : "checkbox-blank-outline"}
name={selected ? "checkbox" : "box-empty"}
iconFamily="notesnook"
size={AppFontSize.md}
color={selected ? colors.selected.icon : colors.primary.icon}
/>
</View>
) : (
<>
<Paragraph
size={AppFontSize.xxs}
color={colors.secondary.paragraph}
>
<Paragraph fontSize="SM" color={colors.secondary.paragraph}>
{totalNotes?.(notebook?.id) || 0}
</Paragraph>
</>
@@ -263,8 +263,81 @@ export const NotebookItem = ({
}}
/>
) : null}
{item.hasChildren ? (
<IconButton
size={12}
color={
selected || isFocused
? colors.selected.icon
: colors.primary.icon
}
testID={item.hasChildren ? `expand-notebook-${index}` : ""}
onPress={() => {
if (item.hasChildren && !disableExpand) {
onToggleExpanded?.();
}
}}
top={0}
left={20}
bottom={0}
right={20}
style={{
borderRadius: defaultBorderRadius,
width: undefined,
height: undefined
}}
iconFamily="notesnook"
name={expanded ? "chevron-up" : "chevron-down"}
/>
) : null}
</View>
</Pressable>
{expanded && item.hasChildren && !selectionEnabled ? (
<View
style={{
width: "100%",
paddingLeft: (item.depth + 1) * 15
}}
>
<View
style={{
height: "100%",
width: 1,
backgroundColor: colors.primary.border,
top: 0,
bottom: 0,
position: "absolute",
left: (item.depth + 1) * 15
}}
/>
<Pressable
style={{
// borderLeftWidth: 1,
// borderLeftColor: colors.primary.border,
flexDirection: "row",
gap: Spacing.LEVEL_1,
justifyContent: "flex-start",
paddingVertical: Spacing.LEVEL_1,
paddingHorizontal: Spacing.LEVEL_1,
alignItems: "center"
}}
onPress={() => {
AddNotebookSheet.present(undefined, item.notebook);
}}
>
<AppIcon
name="plus"
size={14}
style={{
marginTop: -2
}}
iconFamily="notesnook"
/>
<Heading fontSize="SM">Create sub-notebook</Heading>
</Pressable>{" "}
</View>
) : null}
</View>
);
};

View File

@@ -70,7 +70,7 @@ export const PinnedSection = React.memo(
menuPins.map((item) => ({
id: item.id,
title: item.title,
icon: item.type === "notebook" ? "notebook-outline" : "pound",
icon: item.type === "notebook" ? "bookmark" : "shopping-mode",
dataType: item.type,
data: item,
onPress: onPress,

View File

@@ -30,6 +30,7 @@ import { Pressable } from "../ui/pressable";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import { useSideBarDraggingStore } from "./dragging-store";
import { Radius, Spacing } from "../../common/design/spacing";
const SettingsIcon = () => {
const { colors } = useThemeColors();
@@ -77,31 +78,31 @@ export const SideMenuHeader = (props: { rightButtons?: IconButtonProps[] }) => {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
paddingBottom: DefaultAppStyles.GAP,
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<View
style={{
flexDirection: "row",
gap: DefaultAppStyles.GAP_SMALL,
gap: Spacing.LEVEL_1,
alignItems: "center"
}}
>
<View
style={{
backgroundColor: "black",
width: 28,
height: 28,
borderRadius: 10
width: 26,
height: 26,
borderRadius: Radius.XS,
overflow: "hidden"
}}
>
<SvgView width={28} height={28} src={NOTESNOOK_LOGO_SVG} />
<SvgView width={26} height={26} src={NOTESNOOK_LOGO_SVG} />
</View>
<Heading size={AppFontSize.lg}>Notesnook</Heading>
<Heading lineHeight="120%" fontSize="XL">
Notesnook
</Heading>
</View>
<View

View File

@@ -38,6 +38,7 @@ import { ColorSection } from "./color-section";
import { MenuItem } from "./menu-item";
import { PinnedSection } from "./pinned-section";
import { SideMenuHeader } from "./side-menu-header";
import { Spacing } from "../../common/design/spacing";
const pro = {
title: strings.upgradePlan(),
@@ -71,8 +72,7 @@ export function SideMenuHome() {
height: "100%",
width: "100%",
backgroundColor: colors.primary.background,
gap: DefaultAppStyles.GAP,
paddingTop: DefaultAppStyles.GAP_VERTICAL
paddingTop: Spacing.LEVEL_1
}}
>
<SideMenuHeader />
@@ -129,7 +129,8 @@ export function SideMenuHome() {
</>
)}
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: DefaultAppStyles.GAP,
marginTop: Spacing.LEVEL_3
}}
nestedScrollEnabled={false}
/>

View File

@@ -23,9 +23,15 @@ import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import Paragraph from "../ui/typography/paragraph";
import { SideMenuHeader } from "./side-menu-header";
import Heading from "../ui/typography/heading";
import { Spacing } from "../../common/design/spacing";
import { Button } from "../ui/button";
type SideMenuListEmptyProps = {
placeholder: string;
placeholderTitle: string;
placeholderBody: string;
placeholderButtonTitle: string;
onPressPlaceholderButton: () => void;
isLoading?: boolean;
};
@@ -76,9 +82,39 @@ export const SideMenuListEmpty = (props: SideMenuListEmptyProps) => {
))}
</View>
) : (
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{props.placeholder}
</Paragraph>
<View
style={{
alignItems: "center",
gap: Spacing.LEVEL_1
}}
>
<Heading size={AppFontSize.md} color={colors.secondary.paragraph}>
{props.placeholderTitle}
</Heading>
<Paragraph
style={{
textAlign: "center",
maxWidth: "60%"
}}
fontSize="SM"
color={colors.secondary.paragraph}
>
{props.placeholderBody}
</Paragraph>
<Button
title={props.placeholderButtonTitle}
onPress={props.onPressPlaceholderButton}
fontSize={AppFontSize.sm}
style={{
marginTop: Spacing.LEVEL_2,
paddingVertical: Spacing.LEVEL_2,
paddingHorizontal: Spacing.LEVEL_2
}}
type="accent-outline"
icon="plus"
/>
</View>
)}
</View>
</View>

View File

@@ -41,6 +41,9 @@ import {
} from "./stores";
import { LegendList } from "@legendapp/list";
import { useRelationStore } from "../../stores/use-relation-store";
import { AddNotebookSheet } from "../sheets/add-notebook";
import { Spacing } from "../../common/design/spacing";
import AppIcon from "../ui/AppIcon";
useSideMenuNotebookSelectionStore.setState({
multiSelect: true
});
@@ -53,7 +56,7 @@ export const SideMenuNotebooks = () => {
const [filteredNotebooks, setFilteredNotebooks] = React.useState(notebooks);
const searchTimer = React.useRef<NodeJS.Timeout>(undefined);
const lastQuery = React.useRef<string>(undefined);
const updater = useRelationStore(state => state.updater);
const updater = useRelationStore((state) => state.updater);
const loadRootNotebooks = React.useCallback(async () => {
if (!filteredNotebooks) return;
const _notebooks: Notebook[] = [];
@@ -81,7 +84,7 @@ export const SideMenuNotebooks = () => {
useEffect(() => {
updateNotebooks();
}, [updateNotebooks,updater]);
}, [updateNotebooks, updater]);
useEffect(() => {
(async () => {
@@ -136,7 +139,12 @@ export const SideMenuNotebooks = () => {
>
{!notebooks || notebooks.placeholders.length === 0 ? (
<SideMenuListEmpty
placeholder={strings.emptyPlaceholders("notebook")}
placeholderTitle={strings.noNotebooksYet()}
placeholderBody={strings.notebooksEmptyBody()}
placeholderButtonTitle={strings.createNotebook()}
onPressPlaceholderButton={() => {
AddNotebookSheet.present();
}}
isLoading={isLoading}
/>
) : (
@@ -151,7 +159,8 @@ export const SideMenuNotebooks = () => {
<View
style={{
backgroundColor: colors.primary.background,
paddingTop: DefaultAppStyles.GAP_VERTICAL
paddingTop: Spacing.LEVEL_1,
paddingBottom: Spacing.LEVEL_3
}}
>
<SideMenuHeader />
@@ -159,34 +168,44 @@ export const SideMenuNotebooks = () => {
}
renderItem={renderItem}
/>
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
backgroundColor: colors.primary.background,
borderTopColor: colors.primary.border,
borderTopWidth: 1,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: Spacing.LEVEL_3
}}
>
<TextInput
placeholder="Filter notebooks..."
<View
style={{
fontFamily: "Inter-Regular",
fontSize: AppFontSize.xs,
paddingTop: 0,
paddingBottom: 0
width: "100%",
backgroundColor: colors.primary.background,
borderTopColor: colors.primary.border,
borderTopWidth: 1,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
flexDirection: "row",
justifyContent: "space-between"
}}
cursorColor={colors.primary.accent}
onChangeText={async (value: string) => {
searchTimer.current && clearTimeout(searchTimer.current);
searchTimer.current = setTimeout(async () => {
lastQuery.current = value;
updateNotebooks();
}, 500);
}}
placeholderTextColor={colors.primary.placeholder}
/>
>
<TextInput
placeholder={strings.filterNotebooks()}
style={{
fontFamily: "Inter-Regular",
fontSize: AppFontSize.xs,
paddingTop: 0,
paddingBottom: 0
}}
cursorColor={colors.primary.accent}
onChangeText={async (value: string) => {
searchTimer.current && clearTimeout(searchTimer.current);
searchTimer.current = setTimeout(async () => {
lastQuery.current = value;
updateNotebooks();
}, 500);
}}
placeholderTextColor={colors.primary.placeholder}
/>
<AppIcon name="funnel" size={14} iconFamily="notesnook" />
</View>
</View>
</>
)}
@@ -235,8 +254,7 @@ const NotebookItemWrapper = React.memo(
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
marginTop: index === 0 ? DefaultAppStyles.GAP_VERTICAL : 0
paddingHorizontal: Spacing.LEVEL_3
}}
>
<NotebookItem

View File

@@ -25,10 +25,12 @@ import { TextInput, View } from "react-native";
import { DatabaseLogger, db } from "../../common/database";
import { useDBItem, useTotalNotes } from "../../hooks/use-db-item";
import { TaggedNotes } from "../../screens/notes/tagged";
import { presentDialog } from "../dialog/functions";
import Navigation from "../../services/navigation";
import { ToastManager } from "../../services/event-manager";
import useNavigationStore from "../../stores/use-navigation-store";
import { useTags } from "../../stores/use-tag-store";
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
import { useTags, useTagStore } from "../../stores/use-tag-store";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { Properties } from "../properties";
import AppIcon from "../ui/AppIcon";
@@ -39,6 +41,7 @@ import { SideMenuListEmpty } from "./side-menu-list-empty";
import { useSideMenuTagsSelectionStore } from "./stores";
import { LegendList, LegendListRenderItemProps } from "@legendapp/list";
import { useRelationStore } from "../../stores/use-relation-store";
import { Radius, Spacing } from "../../common/design/spacing";
const TagItem = (props: {
tags: VirtualizedGrouping<Tag>;
@@ -67,11 +70,8 @@ const TagItem = (props: {
return (
<View
style={{
minHeight: 35,
justifyContent: "center",
paddingHorizontal: DefaultAppStyles.GAP,
marginTop:
(props.id as number) === 0 ? DefaultAppStyles.GAP_VERTICAL : 2
paddingHorizontal: Spacing.LEVEL_3,
marginBottom: Spacing.LEVEL_0
}}
>
{item ? (
@@ -118,31 +118,24 @@ const TagItem = (props: {
width: "100%",
alignItems: "center",
flexDirection: "row",
borderRadius: defaultBorderRadius,
paddingRight: DefaultAppStyles.GAP_SMALL
borderRadius: Radius.XS,
padding: Spacing.LEVEL_1
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
flexShrink: 1
flexShrink: 1,
gap: Spacing.LEVEL_1
}}
>
<View
style={{
width: 32,
height: 32,
justifyContent: "center",
alignItems: "center"
}}
>
<AppIcon
size={AppFontSize.md}
color={isFocused ? colors.selected.icon : colors.primary.icon}
name="pound"
/>
</View>
<AppIcon
size={16}
color={isFocused ? colors.selected.icon : colors.primary.icon}
name="shopping-mode"
iconFamily="notesnook"
/>
<Paragraph
color={
@@ -175,9 +168,9 @@ const TagItem = (props: {
</View>
) : (
<>
{item?.id && totalNotes.totalNotes?.(item?.id) ? (
{item?.id && totalNotes.totalNotes?.(item?.id) !== undefined ? (
<Paragraph
size={AppFontSize.xxs}
size={AppFontSize.sm}
color={colors.secondary.paragraph}
style={{
marginLeft: DefaultAppStyles.GAP_SMALL
@@ -241,6 +234,32 @@ export const SideMenuTags = () => {
setLoading(false);
}, [tags]);
const onPressAddTag = React.useCallback(() => {
presentDialog({
title: strings.addTag(),
// paragraph: strings.addTagDesc(),
input: true,
inputLabel: "Enter title",
inputPlaceholder: "eg. journal",
positiveText: strings.add(),
positivePress: async (tag) => {
if (tag) {
await db.tags.add({
title: tag
});
useTagStore.getState().refresh();
return true;
}
ToastManager.show({
context: "local",
type: "error",
message: strings.allFieldsRequired()
});
return false;
}
});
}, []);
useEffect(() => {
if (!isLoading) {
updateTags();
@@ -262,7 +281,10 @@ export const SideMenuTags = () => {
>
{!tags || tags?.placeholders.length === 0 ? (
<SideMenuListEmpty
placeholder={strings.emptyPlaceholders("tag")}
placeholderTitle={strings.noTagsYet()}
placeholderBody={strings.tagsEmptyBody()}
placeholderButtonTitle={strings.addTag()}
onPressPlaceholderButton={onPressAddTag}
isLoading={loading}
/>
) : (
@@ -278,7 +300,8 @@ export const SideMenuTags = () => {
<View
style={{
backgroundColor: colors.primary.background,
paddingTop: DefaultAppStyles.GAP_VERTICAL
paddingTop: Spacing.LEVEL_1,
paddingBottom: Spacing.LEVEL_3
}}
>
<SideMenuHeader />
@@ -288,36 +311,45 @@ export const SideMenuTags = () => {
/>
<View
style={{
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
backgroundColor: colors.primary.background,
borderTopColor: colors.primary.border,
borderTopWidth: 1,
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingHorizontal: Spacing.LEVEL_3
}}
>
<TextInput
placeholder="Filter tags..."
<View
style={{
fontFamily: "Inter-Regular",
fontSize: AppFontSize.xs,
paddingTop: 0,
paddingBottom: 0
width: "100%",
backgroundColor: colors.primary.background,
borderTopColor: colors.primary.border,
borderTopWidth: 1,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
flexDirection: "row",
justifyContent: "space-between"
}}
cursorColor={colors.primary.accent}
onChangeText={async (value) => {
searchTimer.current && clearTimeout(searchTimer.current);
searchTimer.current = setTimeout(async () => {
try {
lastQuery.current = value;
updateTags();
} catch (e) {
DatabaseLogger.error(e);
}
}, 100);
}}
placeholderTextColor={colors.primary.placeholder}
/>
>
<TextInput
placeholder={strings.filterTags()}
style={{
fontFamily: "Inter-Regular",
fontSize: AppFontSize.xs,
paddingTop: 0,
paddingBottom: 0
}}
cursorColor={colors.primary.accent}
onChangeText={async (value) => {
searchTimer.current && clearTimeout(searchTimer.current);
searchTimer.current = setTimeout(async () => {
try {
lastQuery.current = value;
updateTags();
} catch (e) {
DatabaseLogger.error(e);
}
}, 100);
}}
placeholderTextColor={colors.primary.placeholder}
/>
<AppIcon name="funnel" size={14} iconFamily="notesnook" />
</View>
</View>
</>
)}

View File

@@ -0,0 +1,111 @@
/*
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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import { Pressable } from "../ui/pressable";
import Paragraph from "../ui/typography/paragraph";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring
} from "react-native-reanimated";
import { Radius, Spacing } from "../../common/design/spacing";
import AppIcon from "../ui/AppIcon";
type TabBarButtonProps = {
icon: string;
label?: string;
onPress: () => void;
isActive?: boolean;
testID?: string;
};
export const TabBarButton = ({
icon,
label,
onPress,
isActive = false,
testID
}: TabBarButtonProps) => {
const { colors } = useThemeColors();
const scale = useSharedValue(1);
const animatedIconStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }]
}));
const handlePress = () => {
scale.value = withSpring(0.85, {
damping: 100,
mass: 1,
overshootClamping: false
});
setTimeout(() => {
scale.value = withSpring(1, {
damping: 100,
mass: 1,
overshootClamping: false
});
}, 100);
onPress();
};
return (
<Pressable
testID={testID}
onPress={handlePress}
style={{
borderRadius: 10,
paddingVertical: 2,
width: undefined,
gap: label ? Spacing.LEVEL_1 : 0,
backgroundColor: "transparent",
borderWidth: 0
}}
type={"plain"}
>
<Animated.View
style={[
{
backgroundColor: isActive ? colors.primary.shade : undefined,
borderRadius: Radius.XS,
padding: Spacing.LEVEL_1
},
animatedIconStyle
]}
>
<AppIcon
name={icon}
iconFamily="notesnook"
color={isActive ? colors.selected.icon : colors.primary.icon}
size={16}
/>
</Animated.View>
{label && (
<Paragraph fontFamily={isActive ? "MEDIUM" : "REGULAR"} fontSize={"XS"}>
{label}
</Paragraph>
)}
</Pressable>
);
};

View File

@@ -22,6 +22,10 @@ import { ColorValue, TextProps } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import EvilIcon from "react-native-vector-icons/EvilIcons";
import { AppFontSize } from "../../../utils/size";
import { createNanoIconSet } from "react-native-nano-icons";
import glyphMap from "../../../../fonts/notesnook-icons.glyphmap.json";
const NotesnookIcon = createNanoIconSet(glyphMap);
export interface IconProps extends TextProps {
/**
@@ -43,9 +47,9 @@ export interface IconProps extends TextProps {
* Color of the icon
*
*/
color?: ColorValue | number | undefined;
color?: ColorValue | ColorValue[] | number | undefined;
iconFamily?: "evilicons" | "material";
iconFamily?: "evilicons" | "material" | "notesnook";
}
export default function AppIcon({
@@ -59,6 +63,12 @@ export default function AppIcon({
color={colors.primary.icon}
{...(props as any)}
/>
) : iconFamily === "notesnook" ? (
<NotesnookIcon
size={AppFontSize.md}
color={colors.primary.icon}
{...(props as any)}
/>
) : (
<Icon
size={AppFontSize.md}

View File

@@ -26,7 +26,6 @@ import {
ViewStyle,
useWindowDimensions
} from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { AppFontSize, defaultBorderRadius } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import NativeTooltip from "../../../utils/tooltip";
@@ -35,6 +34,7 @@ import Heading from "../typography/heading";
import Paragraph from "../typography/paragraph";
import { Spacing } from "../../../common/design/spacing";
import { FontFamily } from "../../../common/design/font";
import AppIcon, { IconProps } from "../AppIcon";
export interface ButtonProps extends PressableProps {
height?: number;
icon?: string;
@@ -57,6 +57,7 @@ export interface ButtonProps extends PressableProps {
bold?: boolean;
iconColor?: ColorValue;
iconStyle?: TextStyle;
iconFamily?: IconProps["iconFamily"];
proTag?: boolean;
allowFontScaling?: boolean;
}
@@ -84,6 +85,7 @@ export const Button = ({
fwdRef,
proTag,
iconStyle,
iconFamily,
allowFontScaling = true,
...restProps
}: ButtonProps) => {
@@ -142,8 +144,9 @@ export const Button = ({
<ActivityIndicator color={textColor} size={fontSize + 4} />
) : null}
{icon && !loading && iconPosition === "left" ? (
<Icon
<AppIcon
name={icon}
iconFamily={iconFamily}
allowFontScaling={allowFontScaling}
style={[{ marginRight: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
@@ -177,8 +180,9 @@ export const Button = ({
)}
{icon && !loading && iconPosition === "right" ? (
<Icon
<AppIcon
name={icon}
iconFamily={iconFamily}
allowFontScaling
style={[iconStyle as any]}
color={iconColor || buttonType?.text || textColor}

View File

@@ -25,10 +25,10 @@ import {
TextStyle,
useWindowDimensions
} from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { hexToRGBA, RGB_Linear_Shade } from "../../../utils/colors";
import { AppFontSize } from "../../../utils/size";
import NativeTooltip from "../../../utils/tooltip";
import AppIcon, { IconProps } from "../AppIcon";
import { Pressable, PressableProps } from "../pressable";
export interface IconButtonProps extends PressableProps {
name: string;
@@ -42,6 +42,8 @@ export interface IconButtonProps extends PressableProps {
tooltipText?: string;
tooltipPosition?: number;
iconStyle?: TextStyle;
iconProps?: IconProps;
iconFamily?: IconProps["iconFamily"];
}
export const IconButton = ({
@@ -59,7 +61,9 @@ export const IconButton = ({
tooltipText,
type = "plain",
fwdRef,
iconProps,
tooltipPosition = NativeTooltip.POSITIONS.TOP,
iconFamily,
...restProps
}: IconButtonProps) => {
const { colors } = useThemeColors();
@@ -100,8 +104,10 @@ export const IconButton = ({
...style
}}
>
<Icon
<AppIcon
{...iconProps}
name={name}
iconFamily={iconFamily}
style={iconStyle as any}
allowFontScaling
color={

View File

@@ -17,9 +17,12 @@ 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 React, { RefObject, useState } from "react";
import { useThemeColors } from "@notesnook/theme";
import phone from "phone";
import React, { RefObject, useRef, useState } from "react";
import {
ColorValue,
findNodeHandle,
NativeSyntheticEvent,
TextInput,
TextInputProps,
@@ -28,22 +31,17 @@ import {
View,
ViewStyle
} from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import isURL from "validator/lib/isURL";
import { Spacing } from "../../../common/design/spacing";
import {
ERRORS_LIST,
validateEmail,
validatePass,
validateUsername
} from "../../../services/validation";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../../utils/elevation";
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
import { AppFontSize, defaultBorderRadius } from "../../../utils/size";
import { IconButton } from "../icon-button";
import Paragraph from "../typography/paragraph";
import phone from "phone";
import isURL from "validator/lib/isURL";
import { DefaultAppStyles } from "../../../utils/styles";
import { Spacing } from "../../../common/design/spacing";
import { useInputError } from "./input-error-context";
interface InputProps extends TextInputProps {
fwdRef?: RefObject<TextInput | null>;
@@ -113,6 +111,9 @@ const Input = ({
...restProps
}: InputProps) => {
const { colors, isDark } = useThemeColors();
const errorCtx = useInputError();
const internalRef = useRef<TextInput>(null);
const activeRef = fwdRef ?? internalRef;
const [error, setError] = useState(false);
const [focus, setFocus] = useState(false);
const [secureEntry, setSecureEntry] = useState(true);
@@ -121,6 +122,12 @@ const Input = ({
SHORT_PASS: false
});
type ErrorKey = keyof typeof errorList;
const reportError = (message: string | null) => {
if (!errorCtx) return;
const nativeId = findNodeHandle(activeRef.current);
if (nativeId !== null) errorCtx.setError(nativeId, message);
};
const color = error
? colors.error.border
: focus
@@ -137,34 +144,30 @@ const Input = ({
});
return;
}
let isError:
| boolean
| string
| { SHORT_PASS?: boolean; isValid?: boolean }
| undefined = undefined;
let isValid: boolean | string | undefined = undefined;
switch (validationType) {
case "password":
isError = validatePass(value);
isValid = validatePass(value);
break;
case "email":
isError = validateEmail(value);
isValid = validateEmail(value);
break;
case "username":
isError = validateUsername(value);
isValid = validateUsername(value);
break;
case "confirmPassword":
isError = customValidator && value === customValidator();
isValid = customValidator && value === customValidator();
break;
case "url":
isError = isURL(value, { allow_underscores: true });
isValid = isURL(value, { allow_underscores: true });
break;
case "phonenumber": {
const result = phone(value, {
strictDetection: true,
validateMobilePrefix: true
});
isError = result.isValid;
isValid = result.isValid;
if (result.isValid) {
onChangeText && onChangeText(result.phoneNumber);
}
@@ -173,23 +176,10 @@ const Input = ({
}
}
if (validationType === "password") {
let hasError = false;
const errors = isError as { [name: string]: boolean };
Object.keys(errors).forEach((e) => {
//ts-ignore
if (errors[e] === true) {
hasError = true;
}
});
setError(hasError);
onErrorCheck && onErrorCheck(hasError);
setErrorList(errors as { SHORT_PASS: boolean });
} else {
setError(!isError);
onErrorCheck && onErrorCheck(!isError);
}
const hasError = !isValid;
setError(hasError);
onErrorCheck && onErrorCheck(hasError);
reportError(hasError ? (errorMessage ?? null) : null);
};
const onChange = (value: string) => {
@@ -201,6 +191,7 @@ const Input = ({
setErrorList({
SHORT_PASS: false
});
reportError(null);
}
};
@@ -221,7 +212,7 @@ const Input = ({
const style: ViewStyle = {
borderWidth: 1,
borderRadius: defaultBorderRadius,
borderColor: color,
borderColor: error ? colors.static.red : color,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
@@ -277,10 +268,8 @@ const Input = ({
<TextInput
{...restProps}
ref={fwdRef}
onLayout={(e) => {
console.log(e.nativeEvent.layout);
}}
ref={activeRef}
onLayout={restProps.onLayout}
editable={!loading && restProps.editable}
onChangeText={onChange}
onBlur={onBlur}
@@ -343,86 +332,9 @@ const Input = ({
}}
/>
)}
{error && (
<IconButton
name="alert-circle-outline"
top={10}
bottom={10}
onPress={() => {
setShowError(!showError);
}}
size={20}
style={{
width: 25,
marginLeft: 5
}}
color={colors.error.icon}
/>
)}
</View>
{error && showError && errorMessage ? (
<View
style={{
position: "absolute",
backgroundColor: colors.secondary.background,
paddingVertical: 3,
paddingHorizontal: DefaultAppStyles.GAP_SMALL / 2,
borderRadius: 2.5,
...getElevationStyle(2),
top: 0
}}
>
<Paragraph
size={AppFontSize.xs}
style={{
textAlign: "right",
textAlignVertical: "bottom"
}}
>
<Icon
name="alert-circle-outline"
size={AppFontSize.xs}
color={colors.error.icon}
/>{" "}
{errorMessage}
</Paragraph>
</View>
) : null}
</TouchableOpacity>
</View>
{validationType === "password" &&
focus &&
Object.keys(errorList).filter((k) => errorList[k as ErrorKey] === true)
.length !== 0 ? (
<View
style={{
marginTop: -5,
marginBottom: 5
}}
>
{Object.keys(ERRORS_LIST).map((error) => (
<View
key={ERRORS_LIST[error as ErrorKey]}
style={{
flexDirection: "row",
alignItems: "center"
}}
>
<Icon
name={errorList[error as ErrorKey] ? "close" : "check"}
color={errorList[error as ErrorKey] ? "red" : "green"}
/>
<Paragraph style={{ marginLeft: 5 }} fontSize="XS">
{ERRORS_LIST[error as ErrorKey]}
</Paragraph>
</View>
))}
</View>
) : null}
</>
);
};

View File

@@ -0,0 +1,120 @@
/*
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 React, {
createContext,
RefObject,
useCallback,
useContext,
useMemo,
useRef,
useState
} from "react";
import { findNodeHandle, TextInput, View } from "react-native";
import Paragraph from "../typography/paragraph";
import { useThemeColors } from "@notesnook/theme";
import { Spacing } from "../../../common/design/spacing";
import AppIcon from "../AppIcon";
interface InputErrorContextType {
setError: (nativeId: number, message: string | null) => void;
getError: (nativeId: number) => string | null;
}
const InputErrorContext = createContext<InputErrorContextType | null>(null);
export function InputErrorProvider({
children
}: {
children: React.ReactNode;
}) {
const [errors, setErrors] = useState<Map<number, string | null>>(new Map());
const setError = useCallback((nativeId: number, message: string | null) => {
setErrors((prev) => {
const next = new Map(prev);
if (message === null) {
next.delete(nativeId);
} else {
next.set(nativeId, message);
}
return next;
});
}, []);
const getError = useCallback(
(nativeId: number) => errors.get(nativeId) ?? null,
[errors]
);
const value = useMemo(() => ({ setError, getError }), [setError, getError]);
return (
<InputErrorContext.Provider value={value}>
{children}
</InputErrorContext.Provider>
);
}
export function useInputError() {
return useContext(InputErrorContext);
}
interface ErrorContainerProps {
inputRef: RefObject<TextInput | null>;
}
export function ErrorContainer({ inputRef }: ErrorContainerProps) {
const ctx = useInputError();
const { colors } = useThemeColors();
const nativeIdRef = useRef<number | null>(null);
if (!ctx) return null;
// Resolve the native ID lazily — the ref's current may not be set on first
// render but will be by the time the input mounts and registers an error.
const nativeId =
nativeIdRef.current ??
(inputRef.current
? (nativeIdRef.current = findNodeHandle(inputRef.current))
: null);
const message = nativeId !== null ? ctx.getError(nativeId) : null;
if (!message) return null;
return (
<View
style={{
flexDirection: "row",
gap: Spacing.LEVEL_1
}}
>
<AppIcon
name="warning-circle"
color={colors.static.red}
iconFamily="notesnook"
size={16}
/>
<Paragraph color={colors.static.red} fontSize="SM">
{message}
</Paragraph>
</View>
);
}

View File

@@ -50,6 +50,8 @@ export interface PressableProps extends RNPressableProps {
type ButtonTypes =
| "plain"
| "plain-outline"
| "accent-background"
| "transparent"
| "accent"
| "shade"
@@ -61,7 +63,8 @@ type ButtonTypes =
| "error"
| "errorShade"
| "warn"
| "selected";
| "selected"
| "accent-outline";
type ButtonVariant = {
primary: string;
@@ -92,6 +95,14 @@ const buttonTypes = (
isDark
)
},
"plain-outline": {
primary: "transparent",
text: colors.primary.paragraph,
selected: colors.primary.hover,
borderWidth: 1,
borderColor: colors.primary.border,
borderSelectedColor: colors.primary.border
},
transparent: {
primary: "transparent",
text: colors.primary.accent,
@@ -167,6 +178,20 @@ const buttonTypes = (
false
)
},
"accent-background": {
primary: colors.primary.background,
text: colors.primary.accent,
selected: colors.primary.background,
borderWidth: 0
},
"accent-outline": {
primary: "transparent",
text: colors.primary.accent,
selected: accent || colors.primary.accent,
borderWidth: 1,
borderColor: accent || colors.primary.accent,
borderSelectedColor: accent || colors.primary.accent
},
inverted: {
primary: colors.primary.background,
text: colors.primary.accent,

View File

@@ -19,13 +19,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { isReminderActive } from "@notesnook/core";
import React from "react";
import { ViewStyle } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
import { AppFontSize } from "../../../utils/size";
import { Button, ButtonProps } from "../button";
import { getFormattedReminderTime } from "@notesnook/common";
import { Reminder } from "@notesnook/core";
import { DefaultAppStyles } from "../../../utils/styles";
import { Radius } from "../../../common/design/spacing";
export const ReminderTime = ({
checkIsActive = true,
@@ -55,8 +55,9 @@ export const ReminderTime = ({
title={time}
key={reminder.id}
icon="bell"
iconFamily="notesnook"
fontSize={AppFontSize.xs}
iconSize={AppFontSize.sm}
iconSize={12}
type="secondary"
buttonType={
isTodayOrTomorrow
@@ -70,7 +71,7 @@ export const ReminderTime = ({
}}
style={{
height: "auto",
borderRadius: defaultBorderRadius,
borderRadius: Radius.XXS,
borderColor: colors.primary.border,
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
...(style as ViewStyle)

View File

@@ -17,41 +17,23 @@ 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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import { StyleSheet, View } from "react-native";
import { IconButton, IconButtonProps } from "../ui/icon-button";
import { View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { Spacing } from "../../../common/design/spacing";
export const RightMenus = ({
rightButton
}: {
rightButton?: IconButtonProps;
}) => {
const LineSeparator = ({ padding }: { padding: keyof typeof Spacing }) => {
const { colors } = useThemeColors();
return (
<View style={styles.rightBtnContainer}>
{rightButton ? (
<IconButton {...rightButton} color={colors.primary.icon} />
) : (
<View
style={{
width: 40,
height: 40
}}
/>
)}
</View>
<View
style={{
width: "100%",
height: 1,
backgroundColor: colors.primary.border
// marginVertical: Spacing[padding]
}}
/>
);
};
const styles = StyleSheet.create({
rightBtnContainer: {
flexDirection: "row",
alignItems: "center"
},
rightBtn: {
justifyContent: "center",
alignItems: "center"
}
});
export default LineSeparator;

View File

@@ -27,6 +27,7 @@ import { useUserStore } from "../../../stores/use-user-store";
import { getContainerBorder } from "../../../utils/colors";
import { NotesnookModule } from "../../../utils/notesnook-module";
import { Toast } from "../../toast";
import { Spacing } from "../../../common/design/spacing";
/**
*
@@ -68,8 +69,9 @@ const SheetWrapper = ({
width: largeTablet || smallTablet ? width : "100%",
backgroundColor: colors.primary.background,
zIndex: 10,
borderTopRightRadius: 15,
borderTopLeftRadius: 15,
borderTopRightRadius: 35,
paddingTop: Spacing.LEVEL_4,
borderTopLeftRadius: 35,
alignSelf: "center",
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0,

View File

@@ -24,7 +24,8 @@ import { AppFontSize } from "../../../utils/size";
import {
FontFamily,
FontSizes,
getLineHeight
getLineHeight,
LineHeightVariants
} from "../../../common/design/font";
interface HeadingProps extends TextProps {
@@ -36,7 +37,7 @@ interface HeadingProps extends TextProps {
extraBold?: boolean;
fontSize?: keyof typeof FontSizes;
fontFamily?: keyof typeof FontFamily;
lineHeight?: "100%" | "150%";
lineHeight?: LineHeightVariants;
}
const extraBoldStyle = {
@@ -68,7 +69,7 @@ const Heading = ({
color: color || colors.primary.heading,
lineHeight:
fontSize && lineHeight
? getLineHeight(fontSize, lineHeight === "100%" ? 1 : 2)
? getLineHeight(fontSize, lineHeight)
: undefined
},
fontFamily

View File

@@ -24,7 +24,8 @@ import { AppFontSize } from "../../../utils/size";
import {
FontFamily,
FontSizes,
getLineHeight
getLineHeight,
LineHeightVariants
} from "../../../common/design/font";
interface ParagraphProps extends TextProps {
@@ -35,7 +36,7 @@ interface ParagraphProps extends TextProps {
size?: number;
fontSize?: keyof typeof FontSizes;
fontFamily?: keyof typeof FontFamily;
lineHeight?: "100%" | "150%";
lineHeight?: LineHeightVariants;
}
const Paragraph = ({
color,
@@ -43,7 +44,7 @@ const Paragraph = ({
style,
fontSize,
fontFamily,
lineHeight = "100%",
lineHeight,
...restProps
}: ParagraphProps) => {
const { colors } = useThemeColors();
@@ -59,7 +60,7 @@ const Paragraph = ({
fontFamily: fontFamily ? FontFamily[fontFamily] : FontFamily.REGULAR,
lineHeight:
fontSize && lineHeight
? getLineHeight(fontSize, lineHeight === "100%" ? 1 : 2)
? getLineHeight(fontSize, lineHeight)
: undefined
},
style

View File

@@ -30,6 +30,7 @@ import SettingsService from "../../services/settings";
import useNavigationStore from "../../stores/use-navigation-store";
import { useNotes } from "../../stores/use-notes-store";
import { openEditor } from "../notes/common";
import LineSeparator from "../../components/ui/seperator/line-separator";
export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
const [notes, loading] = useNotes();
@@ -66,6 +67,8 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
onPressDefaultRightButton={openEditor}
/>
<LineSeparator padding="LEVEL_3" />
<DelayLayout wait={loading}>
<List
data={notes}

View File

@@ -32,18 +32,12 @@ export const ERRORS_LIST = {
SHORT_PASS: strings.passTooShort()
};
export function validatePass(password) {
let errors = {
SHORT_PASS: false
};
if (password?.length < 8) {
errors.SHORT_PASS = true;
export function validatePass(password, length = 8) {
if (password?.length < length) {
return true;
} else {
errors.SHORT_PASS = false;
return false;
}
return errors;
}
export function validateUsername(username) {

View File

@@ -17,7 +17,7 @@ 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 { ItemType } from "@notesnook/core";
import { Item, ItemType } from "@notesnook/core";
import { create } from "zustand";
export interface SelectionStore {
@@ -62,3 +62,20 @@ export const useSelectionStore = create<SelectionStore>((set, get) => ({
set({ selectionMode: undefined, selectedItemsList: [] });
}
}));
export function selectItem(item: Item) {
if (useSelectionStore.getState().selectionMode === item.type) {
const { selectionMode, clearSelection, setSelectedItem } =
useSelectionStore.getState();
if (selectionMode === item.type) {
setSelectedItem(item.id);
}
if (useSelectionStore.getState().selectedItemsList.length === 0) {
clearSelection();
}
return true;
}
return false;
}

View File

@@ -36,10 +36,10 @@ export const STORE_LINK =
export const GROUP = {
default: "default",
none: "none",
abc: "abc",
year: "year",
month: "month",
week: "week",
month: "month"
abc: "abc"
};
export const SORT = {

View File

@@ -37,28 +37,16 @@ export const MenuItemsList: SideMenuItem[] = [
dataType: "note",
id: "Notes",
title: "Notes",
icon: "note-outline",
icon: "note",
type: "side-menu-item"
},
// {
// dataType: "notebook",
// id: "Notebooks",
// title: "Notebooks",
// icon: "book-outline"
// },
{
dataType: "note",
id: "Favorites",
title: "Favorites",
icon: "star-outline",
icon: "star",
type: "side-menu-item"
},
// {
// dataType: "tag",
// id: "Tags",
// title: "Tags",
// icon: "pound"
// },
{
dataType: "reminder",
id: "Reminders",
@@ -70,7 +58,7 @@ export const MenuItemsList: SideMenuItem[] = [
dataType: "monograph",
id: "Monographs",
title: "Monographs",
icon: "text-box-multiple-outline",
icon: "book-open",
onPress: () => {
Navigation.closeDrawer();
Monographs.navigate();
@@ -88,7 +76,7 @@ export const MenuItemsList: SideMenuItem[] = [
dataType: "note",
id: "Trash",
title: "Trash",
icon: "delete-outline",
icon: "trash",
type: "side-menu-item"
}
];

View File

@@ -0,0 +1 @@
{"m":{"f":"notesnook-icons","u":1024,"z":1020,"s":59648,"h":"83a1ac81fdaaf076cb52c3ad793c668b4be2ce48e94af989b74c69660096843b"},"i":{"archive":[1024,[[59648,"#666666"]]],"bell":[1024,[[59649,"#666666"]]],"book-open":[1024,[[59650,"#666666"]]],"bookmark":[1024,[[59651,"#666666"]]],"box-empty":[1024,[[59652,"#B0B0B1"]]],"calendar":[1024,[[59653,"rgba(102,102,102,0.8)"]]],"chat":[1024,[[59654,"white"]]],"checkbox":[1024,[[59655,"#008836"],[59656,"white"]]],"checks":[1024,[[59657,"#181818"]]],"chevron-down":[1024,[[59658,"#181818"]]],"chevron-up":[1024,[[59659,"#181818"]]],"close":[1024,[[59660,"#666666"]]],"dark-mode-outline":[1024,[[59661,"currentColor"]]],"dots-three":[1024,[[59662,"#202020"]]],"drive-file-move":[1088,[[59663,"#666666"]]],"envelope-simple":[1024,[[59664,"white"]]],"funnel":[1024,[[59665,"#666666"]]],"home":[1024,[[59666,"#181818"]]],"link":[560,[[59667,"#666666"]]],"lock-simple":[1024,[[59668,"white"]]],"menu":[1024,[[59669,"#181818"]]],"note":[1024,[[59670,"#181818"]]],"pin":[939,[[59671,"#666666"]]],"plus":[1024,[[59672,"#666666"]]],"search":[1024,[[59673,"#181818"]]],"shield-check":[1024,[[59674,"#008836"]]],"shopping-mode":[1024,[[59675,"#666666"]]],"sliders":[1024,[[59676,"#181818"]]],"sort-ascending":[1024,[[59677,"#666666"]]],"sort-descending":[1024,[[59678,"currentColor"]]],"star-filled":[1024,[[59679,"#E5C131"]]],"star":[1024,[[59680,"#666666"]]],"sun":[1024,[[59681,"#666666"]]],"trash":[1024,[[59682,"#666666"]]],"view-list":[1024,[[59683,"#181818"]]],"warning-circle":[1024,[[59684,"#BB3431"]]]}}

Binary file not shown.

View File

@@ -1,43 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Add to Notes</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
<key>RCTNewArchEnabled</key>
<true/>
</dict>
</plist>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Add to Notes</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
<key>RCTNewArchEnabled</key>
<true/>
<key>UIAppFonts</key>
<array>
<string>svgs.ttf</string>
<string>notesnook-icons.ttf</string>
</array>
</dict>
</plist>

View File

@@ -386,6 +386,7 @@
240525450DF9ABA0F332B52E /* [CP] Copy Pods Resources */,
65A7F34B255687E600699170 /* Embed App Extensions */,
48C834D962D612F18A0388B3 /* [CP] Embed Pods Frameworks */,
5C222D5F8D0742BFAE9C4245 /* Copy nanoicons fonts */,
);
buildRules = (
);
@@ -723,6 +724,20 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5C222D5F8D0742BFAE9C4245 /* Copy nanoicons fonts */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy nanoicons fonts";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\n NANOICONS_DIR=\"${PROJECT_DIR}/nanoicons-fonts\"\n if [ -d \"$NANOICONS_DIR\" ]; then\n cp \"$NANOICONS_DIR\"/*.ttf \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\" 2>/dev/null || true\n fi\n ";
};
658D06A625A7446E008C70C0 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;

View File

@@ -99,6 +99,7 @@
<string>Inter-Bold.ttf</string>
<string>MaterialCommunityIcons.ttf</string>
<string>EvilIcons.ttf</string>
<string>notesnook-icons.ttf</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>

View File

@@ -2113,6 +2113,34 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-nano-icons (0.1.8):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-netinfo (11.4.1):
- React-Core
- react-native-notification-sounds (0.5.5):
@@ -3591,6 +3619,7 @@ DEPENDENCIES:
- react-native-in-app-review (from `../node_modules/react-native-in-app-review`)
- "react-native-keep-awake (from `../node_modules/@sayem314/react-native-keep-awake`)"
- react-native-mmkv-storage (from `../node_modules/react-native-mmkv-storage`)
- react-native-nano-icons (from `../node_modules/react-native-nano-icons`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-notification-sounds (from `../node_modules/react-native-notification-sounds`)
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
@@ -3801,6 +3830,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@sayem314/react-native-keep-awake"
react-native-mmkv-storage:
:path: "../node_modules/react-native-mmkv-storage"
react-native-nano-icons:
:path: "../node_modules/react-native-nano-icons"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-notification-sounds:
@@ -4016,6 +4047,7 @@ SPEC CHECKSUMS:
react-native-in-app-review: 1516ba69d60d58053b7eb3aaaf8d2a5a74af8b57
react-native-keep-awake: a351e6f67006b47f316ae2b17ee8ee69386167f4
react-native-mmkv-storage: e84980084e371a9c2230bbde071536a7e1539406
react-native-nano-icons: 118c99a62175c3f4737ff21e85252c90158816fb
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-notification-sounds: ce106d58df0dd384bccbd2e84fb53accab7cc068
react-native-orientation-locker: cc6f357b289a2e0dd2210fea0c52cb8e0727fdaa

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -119,6 +119,7 @@
"react-native-material-menu": "^2.0.0",
"react-native-mmkv-storage": "^12.0.1",
"react-native-modal-datetime-picker": "14.0.0",
"react-native-nano-icons": "^0.1.8",
"react-native-navigation-bar-color": "2.0.2",
"react-native-nitro-cloud-uploader": "^1.0.9",
"react-native-nitro-modules": "^0.32.0",

View File

@@ -0,0 +1,11 @@
{
"name": "@notesnook/icons",
"version": "2.1.3",
"main": "./svgs",
"exports": {
".": "./svgs",
"./*": "./svgs/*"
},
"license": "GPL-3.0-or-later",
"sideEffects": false
}

View File

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 5.33331V14H2V5.33331" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.3334 2H0.666748V5.33333H15.3334V2Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.66675 8H9.33341" stroke="#666666" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 5.33331C12 4.27245 11.5786 3.25503 10.8284 2.50489C10.0783 1.75474 9.06087 1.33331 8 1.33331C6.93913 1.33331 5.92172 1.75474 5.17157 2.50489C4.42143 3.25503 4 4.27245 4 5.33331C4 9.99998 2 11.3333 2 11.3333H14C14 11.3333 12 9.99998 12 5.33331Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.15335 14C9.03614 14.2021 8.86791 14.3698 8.6655 14.4864C8.46309 14.6029 8.2336 14.6643 8.00001 14.6643C7.76643 14.6643 7.53694 14.6029 7.33453 14.4864C7.13212 14.3698 6.96389 14.2021 6.84668 14" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 740 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.33325 2H5.33325C6.0405 2 6.71877 2.28095 7.21887 2.78105C7.71897 3.28115 7.99992 3.95942 7.99992 4.66667V14C7.99992 13.4696 7.7892 12.9609 7.41413 12.5858C7.03906 12.2107 6.53035 12 5.99992 12H1.33325V2Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.6667 2H10.6667C9.95942 2 9.28115 2.28095 8.78105 2.78105C8.28095 3.28115 8 3.95942 8 4.66667V14C8 13.4696 8.21071 12.9609 8.58579 12.5858C8.96086 12.2107 9.46957 12 10 12H14.6667V2Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 688 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.6665 1.33331C3.56986 1.33331 2.6665 2.23667 2.6665 3.33331V12.6666C2.6665 13.7633 3.56986 14.6666 4.6665 14.6666H13.3332V13.3333H4.6665C4.28982 13.3333 3.99984 13.0433 3.99984 12.6666C3.99984 12.29 4.28982 12 4.6665 12H13.3332V10.6666V1.33331H10.6665H6.6665H4.6665ZM4.6665 2.66665H6.6665V8.08201L7.71598 7.34633L8.6665 6.67836L10.6665 8.08201V2.66665H11.9998V10.6666H4.6665C4.43194 10.6666 4.20976 10.7159 3.99984 10.7916V3.33331C3.99984 2.95663 4.28982 2.66665 4.6665 2.66665ZM7.99984 2.66665H9.33317V5.51821L8.6665 5.05076L7.99984 5.51821V2.66665Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 683 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 0.5H12C13.933 0.5 15.5 2.067 15.5 4V12C15.5 13.933 13.933 15.5 12 15.5H4C2.067 15.5 0.5 13.933 0.5 12V4C0.5 2.067 2.067 0.5 4 0.5Z" stroke="#B0B0B1"/>
</svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14453)">
<path d="M10 1.5H9.5V0.5H8.5V1.5H3.5V0.5H2.5V1.5H2C1.45 1.5 1 1.95 1 2.5V10.5C1 11.05 1.45 11.5 2 11.5H10C10.55 11.5 11 11.05 11 10.5V2.5C11 1.95 10.55 1.5 10 1.5ZM10 10.5H2V5H10V10.5ZM10 4H2V2.5H10V4Z" fill="#666666" fill-opacity="0.8"/>
</g>
<defs>
<clipPath id="clip0_1253_14453">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5 3H2.50002C2.2348 3 1.98045 3.10536 1.79291 3.29289C1.60537 3.48043 1.50002 3.73478 1.50002 4V14C1.49886 14.1907 1.55281 14.3777 1.65537 14.5384C1.75793 14.6992 1.90473 14.8269 2.07814 14.9062C2.21029 14.9678 2.35425 14.9998 2.50002 15C2.73477 14.9994 2.96174 14.9157 3.14064 14.7638L3.14627 14.7594L5.18752 13H13.5C13.7652 13 14.0196 12.8946 14.2071 12.7071C14.3947 12.5196 14.5 12.2652 14.5 12V4C14.5 3.73478 14.3947 3.48043 14.2071 3.29289C14.0196 3.10536 13.7652 3 13.5 3ZM13.5 12H5.00002C4.87996 12.0001 4.76394 12.0433 4.67314 12.1219L2.50002 14V4H13.5V12Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="4" fill="#008836"/>
<path d="M6.69059 11.6351C6.49451 11.8354 6.17216 11.8354 5.97608 11.6351L3.34252 8.94556C3.1522 8.75118 3.1522 8.44031 3.34252 8.24593L3.80941 7.76911C4.00549 7.56886 4.32784 7.56886 4.52392 7.76911L5.97608 9.25217C6.17216 9.45242 6.49451 9.45242 6.69059 9.25217L11.4761 4.36486C11.6722 4.16461 11.9945 4.16461 12.1906 4.36486L12.6575 4.84168C12.8478 5.03605 12.8478 5.34693 12.6575 5.5413L6.69059 11.6351Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 580 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00586 4.44977C9.07802 4.45044 9.14939 4.46551 9.21582 4.49371C9.28229 4.52196 9.34294 4.56329 9.39355 4.61481C9.44391 4.66617 9.48375 4.72684 9.51074 4.79352C9.53776 4.8604 9.55137 4.93233 9.55078 5.00446C9.55014 5.07672 9.53508 5.14888 9.50684 5.21539C9.47867 5.28159 9.43799 5.34169 9.38672 5.39215L9.37207 5.4068H9.37109L3.78613 10.8922C3.68334 10.9933 3.54457 11.0503 3.40039 11.0504C3.25609 11.0504 3.11752 10.9933 3.01465 10.8922L0.614258 8.53571C0.56277 8.48506 0.522337 8.42446 0.494141 8.35797C0.465942 8.29147 0.450802 8.22024 0.450195 8.14801C0.449594 8.07579 0.463157 8.00403 0.490234 7.93707C0.51731 7.87018 0.556827 7.80885 0.607422 7.75739C0.658014 7.70594 0.718741 7.66547 0.785156 7.63727C0.851556 7.60911 0.922999 7.59397 0.995117 7.59332C1.06726 7.59272 1.13916 7.60635 1.20605 7.63336C1.27302 7.66044 1.33424 7.70088 1.38574 7.75153L3.39941 9.72809L8.61523 4.60699C8.71931 4.50492 8.86007 4.44848 9.00586 4.44977ZM15.0049 4.44977C15.0771 4.45041 15.1484 4.46549 15.2148 4.49371C15.2814 4.52198 15.342 4.56322 15.3926 4.61481C15.4431 4.66627 15.4837 4.72667 15.5107 4.79352C15.5378 4.86056 15.5505 4.93315 15.5498 5.00543C15.5491 5.07757 15.5341 5.14902 15.5059 5.21539C15.4775 5.28177 15.4363 5.34164 15.3848 5.39215L9.78516 10.8922C9.68228 10.9933 9.54371 11.0504 9.39941 11.0504C9.25513 11.0503 9.11654 10.9933 9.01367 10.8922L7.4873 9.39215C7.38328 9.29003 7.32371 9.15119 7.32227 9.00543C7.32091 8.85963 7.37741 8.7189 7.47949 8.61481C7.58169 8.51069 7.7213 8.45112 7.86719 8.44977C8.01301 8.44842 8.15372 8.50487 8.25781 8.60699L9.39941 9.72809L14.6143 4.60699C14.6657 4.5564 14.727 4.51687 14.7939 4.48981C14.8609 4.46272 14.9326 4.44914 15.0049 4.44977Z" fill="#181818" stroke="#181818" stroke-width="0.1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1223_13942)">
<path d="M0.7 5.1C0.313401 4.7134 0.313402 4.0866 0.7 3.7C1.0866 3.3134 1.7134 3.3134 2.1 3.7L5.29289 6.89289C5.68342 7.28342 6.31658 7.28342 6.70711 6.89289L9.9 3.7C10.2866 3.3134 10.9134 3.3134 11.3 3.7C11.6866 4.0866 11.6866 4.7134 11.3 5.1L6.70711 9.69289C6.31658 10.0834 5.68342 10.0834 5.29289 9.69289L0.7 5.1Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_1223_13942">
<rect width="12" height="12" fill="white" transform="translate(12) rotate(90)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 623 B

View File

@@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1223_13904)">
<path d="M0.7 6.9C0.313401 7.2866 0.313402 7.9134 0.7 8.3C1.0866 8.6866 1.7134 8.6866 2.1 8.3L5.29289 5.10711C5.68342 4.71658 6.31658 4.71658 6.70711 5.10711L9.9 8.3C10.2866 8.6866 10.9134 8.6866 11.3 8.3C11.6866 7.9134 11.6866 7.2866 11.3 6.9L6.70711 2.30711C6.31658 1.91658 5.68342 1.91658 5.29289 2.30711L0.7 6.9Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_1223_13904">
<rect width="12" height="12" fill="white" transform="matrix(-4.37114e-08 -1 -1 4.37114e-08 12 12)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 643 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 4L4 12" stroke="#666666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 4L12 12" stroke="#666666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M12.058 20q-3.333 0-5.667-2.334T4.058 12q0-2.47 1.413-4.535q1.414-2.067 4.01-2.973q.306-.107.536-.056t.381.199t.192.38q.04.233-.063.489q-.194.477-.282.966t-.087 1.03q0 2.667 1.866 4.533t4.534 1.867q.698 0 1.277-.148q.58-.148.988-.24q.218-.04.399.01t.289.176q.118.125.16.308q.04.183-.048.417q-.715 2.45-2.803 4.013T12.058 20m0-1q2.2 0 3.95-1.213t2.55-3.162q-.5.125-1 .2t-1 .075q-3.075 0-5.238-2.162T9.158 7.5q0-.5.075-1t.2-1q-1.95.8-3.163 2.55T5.058 12q0 2.9 2.05 4.95t4.95 2.05m-.25-6.75"/></svg>

After

Width:  |  Height:  |  Size: 729 B

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.1875 9.9375C11.1875 10.1229 11.1325 10.3042 11.0295 10.4583C10.9265 10.6125 10.7801 10.7327 10.6088 10.8036C10.4375 10.8746 10.249 10.8932 10.0671 10.857C9.88525 10.8208 9.7182 10.7315 9.58709 10.6004C9.45598 10.4693 9.36669 10.3023 9.33051 10.1204C9.29434 9.93854 9.31291 9.75004 9.38386 9.57873C9.45482 9.40743 9.57498 9.26101 9.72915 9.158C9.88332 9.05498 10.0646 9 10.25 9C10.4986 9 10.7371 9.09877 10.9129 9.27459C11.0887 9.4504 11.1875 9.68886 11.1875 9.9375ZM15.5625 9C15.3771 9 15.1958 9.05498 15.0417 9.158C14.8875 9.26101 14.7673 9.40743 14.6964 9.57873C14.6254 9.75004 14.6068 9.93854 14.643 10.1204C14.6792 10.3023 14.7685 10.4693 14.8996 10.6004C15.0307 10.7315 15.1977 10.8208 15.3796 10.857C15.5615 10.8932 15.75 10.8746 15.9213 10.8036C16.0926 10.7327 16.239 10.6125 16.342 10.4583C16.445 10.3042 16.5 10.1229 16.5 9.9375C16.5 9.68886 16.4012 9.4504 16.2254 9.27459C16.0496 9.09877 15.8111 9 15.5625 9ZM4.9375 9C4.75208 9 4.57082 9.05498 4.41665 9.158C4.26248 9.26101 4.14232 9.40743 4.07136 9.57873C4.00041 9.75004 3.98184 9.93854 4.01801 10.1204C4.05419 10.3023 4.14348 10.4693 4.27459 10.6004C4.4057 10.7315 4.57275 10.8208 4.7546 10.857C4.93646 10.8932 5.12496 10.8746 5.29627 10.8036C5.46757 10.7327 5.61399 10.6125 5.717 10.4583C5.82002 10.3042 5.875 10.1229 5.875 9.9375C5.875 9.68886 5.77623 9.4504 5.60041 9.27459C5.4246 9.09877 5.18614 9 4.9375 9Z" fill="#202020"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,3 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.48213 11.8435L11.3332 9.04349L8.48213 6.24349L7.49046 7.21741L8.6415 8.34784H5.6665V9.73915H8.6415L7.49046 10.8696L8.48213 11.8435ZM2.83317 13.9131C2.44359 13.9131 2.1102 13.7769 1.833 13.5047C1.55534 13.232 1.4165 12.9044 1.4165 12.5218V4.17393C1.4165 3.79132 1.55534 3.4639 1.833 3.19167C2.1102 2.91897 2.44359 2.78262 2.83317 2.78262H7.08317L8.49984 4.17393H14.1665C14.5561 4.17393 14.8897 4.31028 15.1674 4.58297C15.4446 4.8552 15.5832 5.18262 15.5832 5.56523V12.5218C15.5832 12.9044 15.4446 13.232 15.1674 13.5047C14.8897 13.7769 14.5561 13.9131 14.1665 13.9131H2.83317ZM2.83317 4.17393V12.5218H14.1665V5.56523H7.91546L6.4988 4.17393H2.83317Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1249_6859)">
<path d="M2 14H4.5L11.8733 6.62671L9.37333 4.12671L2 11.5V14ZM3.33333 12.0534L9.37333 6.01338L9.98667 6.62671L3.94667 12.6667H3.33333V12.0534Z" fill="#181818"/>
<path d="M12.2467 2.19329C11.9867 1.93329 11.5667 1.93329 11.3067 2.19329L10.0867 3.41329L12.5867 5.91329L13.8067 4.69329C14.0667 4.43329 14.0667 4.01329 13.8067 3.75329L12.2467 2.19329Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_1249_6859">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 615 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 3H2C1.86739 3 1.74021 3.05268 1.64645 3.14645C1.55268 3.24021 1.5 3.36739 1.5 3.5V12C1.5 12.2652 1.60536 12.5196 1.79289 12.7071C1.98043 12.8946 2.23478 13 2.5 13H13.5C13.7652 13 14.0196 12.8946 14.2071 12.7071C14.3946 12.5196 14.5 12.2652 14.5 12V3.5C14.5 3.36739 14.4473 3.24021 14.3536 3.14645C14.2598 3.05268 14.1326 3 14 3ZM12.7144 4L8 8.32187L3.28562 4H12.7144ZM13.5 12H2.5V4.63688L7.66187 9.36875C7.75412 9.45343 7.87478 9.50041 8 9.50041C8.12522 9.50041 8.24588 9.45343 8.33813 9.36875L13.5 4.63688V12Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 643 B

3
packages/icons/svgs/funnel.svg Executable file
View File

@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.6112 2.70869C12.5438 2.55311 12.4322 2.42075 12.2903 2.32809C12.1483 2.23543 11.9823 2.18654 11.8127 2.18751H2.18773C2.01838 2.18785 1.85277 2.23732 1.71098 2.32992C1.56919 2.42253 1.45732 2.55429 1.38895 2.70922C1.32057 2.86416 1.29862 3.0356 1.32577 3.20276C1.35291 3.36992 1.42798 3.52562 1.54187 3.65095L1.54625 3.65587L5.25023 7.61087V11.8125C5.25019 11.9709 5.29313 12.1263 5.37448 12.2622C5.45582 12.398 5.57251 12.5093 5.71211 12.5841C5.85171 12.6588 6.00899 12.6943 6.16717 12.6867C6.32535 12.6791 6.47851 12.6287 6.61031 12.541L8.36031 11.3739C8.48027 11.294 8.57864 11.1857 8.64666 11.0586C8.71469 10.9315 8.75026 10.7896 8.75023 10.6455V7.61087L12.4548 3.65587L12.4591 3.65095C12.5742 3.52619 12.65 3.37029 12.6771 3.20272C12.7041 3.03514 12.6812 2.86332 12.6112 2.70869ZM7.99445 7.14111C7.91876 7.22135 7.87618 7.32722 7.87523 7.43751V10.6455L6.12523 11.8125V7.43751C6.12526 7.32642 6.08303 7.21947 6.0071 7.13837L2.18773 3.06251H11.8127L7.99445 7.14111Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 5.99998L8 1.33331L14 5.99998V13.3333C14 13.6869 13.8595 14.0261 13.6095 14.2761C13.3594 14.5262 13.0203 14.6666 12.6667 14.6666H3.33333C2.97971 14.6666 2.64057 14.5262 2.39052 14.2761C2.14048 14.0261 2 13.6869 2 13.3333V5.99998Z" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 14.6667V8H10V14.6667" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 551 B

11
packages/icons/svgs/link.svg Executable file
View File

@@ -0,0 +1,11 @@
<svg width="6" height="11" viewBox="0 0 6 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14423)">
<path d="M0.8125 3.9375L0.8125 2.625C0.8125 2.33773 0.869081 2.05328 0.979014 1.78788C1.08895 1.52248 1.25008 1.28133 1.4532 1.0782C1.65633 0.875077 1.89748 0.713946 2.16288 0.604014C2.42828 0.494082 2.71273 0.437501 3 0.437501C3.28727 0.437501 3.57172 0.494082 3.83712 0.604014C4.10252 0.713946 4.34367 0.875077 4.5468 1.0782C4.74992 1.28133 4.91105 1.52248 5.02099 1.78788C5.13092 2.05328 5.1875 2.33773 5.1875 2.625L5.1875 3.9375M5.1875 6.5625L5.1875 7.875C5.1875 8.16227 5.13092 8.44672 5.02099 8.71212C4.91105 8.97752 4.74992 9.21867 4.5468 9.4218C4.13656 9.83203 3.58016 10.0625 3 10.0625C2.41984 10.0625 1.86344 9.83203 1.4532 9.4218C1.04297 9.01156 0.8125 8.45516 0.8125 7.875L0.8125 6.5625" stroke="#666666" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 7L3 3.5" stroke="#666666" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1253_14423">
<rect width="10.5" height="6" fill="white" transform="translate(4.5897e-07 10.5) rotate(-90)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 5H11V3.5C11 2.70435 10.6839 1.94129 10.1213 1.37868C9.55871 0.81607 8.79565 0.5 8 0.5C7.20435 0.5 6.44129 0.81607 5.87868 1.37868C5.31607 1.94129 5 2.70435 5 3.5V5H3C2.73478 5 2.48043 5.10536 2.29289 5.29289C2.10536 5.48043 2 5.73478 2 6V13C2 13.2652 2.10536 13.5196 2.29289 13.7071C2.48043 13.8946 2.73478 14 3 14H13C13.2652 14 13.5196 13.8946 13.7071 13.7071C13.8946 13.5196 14 13.2652 14 13V6C14 5.73478 13.8946 5.48043 13.7071 5.29289C13.5196 5.10536 13.2652 5 13 5ZM6 3.5C6 2.96957 6.21071 2.46086 6.58579 2.08579C6.96086 1.71071 7.46957 1.5 8 1.5C8.53043 1.5 9.03914 1.71071 9.41421 2.08579C9.78929 2.46086 10 2.96957 10 3.5V5H6V3.5ZM13 13H3V6H13V13Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 789 B

10
packages/icons/svgs/menu.svg Executable file
View File

@@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14461)">
<path d="M2.5 15H17.5V13.3333H2.5V15ZM2.5 10.8333H17.5V9.16667H2.5V10.8333ZM2.5 5V6.66667H17.5V5H2.5Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_1253_14461">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 371 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.3538 5.14625L9.85375 1.64625C9.80728 1.59983 9.75212 1.56303 9.69143 1.53793C9.63073 1.51284 9.56568 1.49995 9.5 1.5H3.5C3.23478 1.5 2.98043 1.60536 2.79289 1.79289C2.60536 1.98043 2.5 2.23478 2.5 2.5V13.5C2.5 13.7652 2.60536 14.0196 2.79289 14.2071C2.98043 14.3946 3.23478 14.5 3.5 14.5H12.5C12.7652 14.5 13.0196 14.3946 13.2071 14.2071C13.3946 14.0196 13.5 13.7652 13.5 13.5V5.5C13.5001 5.43432 13.4872 5.36927 13.4621 5.30858C13.437 5.24788 13.4002 5.19272 13.3538 5.14625ZM10 3.20688L11.7931 5H10V3.20688ZM12.5 13.5H3.5V2.5H9V5.5C9 5.63261 9.05268 5.75979 9.14645 5.85355C9.24022 5.94732 9.36739 6 9.5 6H12.5V13.5ZM10.5 8.5C10.5 8.63261 10.4473 8.75979 10.3536 8.85356C10.2598 8.94732 10.1326 9 10 9H6C5.86739 9 5.74022 8.94732 5.64645 8.85356C5.55268 8.75979 5.5 8.63261 5.5 8.5C5.5 8.36739 5.55268 8.24022 5.64645 8.14645C5.74022 8.05268 5.86739 8 6 8H10C10.1326 8 10.2598 8.05268 10.3536 8.14645C10.4473 8.24022 10.5 8.36739 10.5 8.5ZM10.5 10.5C10.5 10.6326 10.4473 10.7598 10.3536 10.8536C10.2598 10.9473 10.1326 11 10 11H6C5.86739 11 5.74022 10.9473 5.64645 10.8536C5.55268 10.7598 5.5 10.6326 5.5 10.5C5.5 10.3674 5.55268 10.2402 5.64645 10.1464C5.74022 10.0527 5.86739 10 6 10H10C10.1326 10 10.2598 10.0527 10.3536 10.1464C10.4473 10.2402 10.5 10.3674 10.5 10.5Z" fill="#181818"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

10
packages/icons/svgs/pin.svg Executable file
View File

@@ -0,0 +1,10 @@
<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14268)">
<path d="M10.7527 3.50183L7.54313 0.251121C7.46455 0.171507 7.37127 0.108353 7.26859 0.0652648C7.16592 0.0221771 7.05587 0 6.94474 0C6.8336 0 6.72356 0.0221771 6.62089 0.0652648C6.51821 0.108353 6.42492 0.171507 6.34635 0.251121L3.51015 3.13326C2.9464 2.95433 1.65919 2.73844 0.315917 3.83719C0.223329 3.91261 0.147457 4.00693 0.0932409 4.11402C0.0390243 4.22111 0.00767788 4.33856 0.00124234 4.45874C-0.00519321 4.57891 0.0134263 4.69911 0.0558887 4.81151C0.0983512 4.92392 0.163705 5.026 0.247696 5.11112L2.80308 7.69862L0.547022 9.98237C0.467636 10.0628 0.423037 10.1719 0.423037 10.2856C0.423037 10.3993 0.467636 10.5084 0.547022 10.5888C0.626409 10.6692 0.73408 10.7144 0.846349 10.7144C0.958619 10.7144 1.06629 10.6692 1.14568 10.5888L3.40015 8.30344L5.95395 10.8904C6.03245 10.9703 6.12574 11.0337 6.22847 11.077C6.33119 11.1203 6.44134 11.1426 6.5526 11.1427C6.5727 11.1427 6.59226 11.1427 6.61236 11.1427C6.73298 11.1343 6.85039 11.0996 6.9566 11.0411C7.06282 10.9826 7.15536 10.9016 7.22794 10.8036C8.26659 9.40541 8.16664 8.26862 7.92548 7.58933L10.7532 4.71416C10.8318 4.63453 10.8941 4.54 10.9366 4.43597C10.9791 4.33195 11.0009 4.22046 11.0009 4.10788C11.0008 3.99531 10.9789 3.88384 10.9363 3.77985C10.8937 3.67587 10.8313 3.5814 10.7527 3.50183ZM10.154 4.10826L7.12534 7.18648C7.06279 7.25007 7.02154 7.33196 7.0074 7.42058C6.99326 7.50921 7.00695 7.60009 7.04654 7.68041C7.54683 8.69451 6.95135 9.74773 6.5526 10.285L0.846349 4.50416C1.4852 3.98237 2.09654 3.84469 2.56404 3.84469C2.86069 3.84059 3.15488 3.89954 3.42765 4.01773C3.50722 4.05807 3.59733 4.07197 3.68516 4.05745C3.77298 4.04292 3.85405 4.00072 3.91683 3.93683L6.945 0.857013L10.154 4.10773V4.10826Z" fill="#666666"/>
</g>
<defs>
<clipPath id="clip0_1253_14268">
<rect width="11" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.25 8C14.25 8.19891 14.171 8.38968 14.0303 8.53033C13.8897 8.67098 13.6989 8.75 13.5 8.75H8.75V13.5C8.75 13.6989 8.67098 13.8897 8.53033 14.0303C8.38968 14.171 8.19891 14.25 8 14.25C7.80109 14.25 7.61032 14.171 7.46967 14.0303C7.32902 13.8897 7.25 13.6989 7.25 13.5V8.75H2.5C2.30109 8.75 2.11032 8.67098 1.96967 8.53033C1.82902 8.38968 1.75 8.19891 1.75 8C1.75 7.80109 1.82902 7.61032 1.96967 7.46967C2.11032 7.32902 2.30109 7.25 2.5 7.25H7.25V2.5C7.25 2.30109 7.32902 2.11032 7.46967 1.96967C7.61032 1.82902 7.80109 1.75 8 1.75C8.19891 1.75 8.38968 1.82902 8.53033 1.96967C8.67098 2.11032 8.75 2.30109 8.75 2.5V7.25H13.5C13.6989 7.25 13.8897 7.32902 14.0303 7.46967C14.171 7.61032 14.25 7.80109 14.25 8Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 838 B

10
packages/icons/svgs/search.svg Executable file
View File

@@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14465)">
<path d="M12.9167 11.6667H12.2583L12.025 11.4417C12.8417 10.4917 13.3333 9.25833 13.3333 7.91667C13.3333 4.925 10.9083 2.5 7.91667 2.5C4.925 2.5 2.5 4.925 2.5 7.91667C2.5 10.9083 4.925 13.3333 7.91667 13.3333C9.25833 13.3333 10.4917 12.8417 11.4417 12.025L11.6667 12.2583V12.9167L15.8333 17.075L17.075 15.8333L12.9167 11.6667ZM7.91667 11.6667C5.84167 11.6667 4.16667 9.99167 4.16667 7.91667C4.16667 5.84167 5.84167 4.16667 7.91667 4.16667C9.99167 4.16667 11.6667 5.84167 11.6667 7.91667C11.6667 9.99167 9.99167 11.6667 7.91667 11.6667Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_1253_14465">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 805 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5 3.75H4.5C4.10218 3.75 3.72064 3.90804 3.43934 4.18934C3.15804 4.47064 3 4.85218 3 5.25V10.5C3 15.4425 5.3925 18.4378 7.39969 20.0803C9.56156 21.8484 11.7122 22.4484 11.8059 22.4738C11.9348 22.5088 12.0708 22.5088 12.1997 22.4738C12.2934 22.4484 14.4413 21.8484 16.6059 20.0803C18.6075 18.4378 21 15.4425 21 10.5V5.25C21 4.85218 20.842 4.47064 20.5607 4.18934C20.2794 3.90804 19.8978 3.75 19.5 3.75ZM16.2825 10.2806L11.0325 15.5306C10.9628 15.6004 10.8801 15.6557 10.7891 15.6934C10.698 15.7312 10.6004 15.7506 10.5019 15.7506C10.4033 15.7506 10.3057 15.7312 10.2147 15.6934C10.1236 15.6557 10.0409 15.6004 9.97125 15.5306L7.72125 13.2806C7.58052 13.1399 7.50146 12.949 7.50146 12.75C7.50146 12.551 7.58052 12.3601 7.72125 12.2194C7.86198 12.0786 8.05285 11.9996 8.25187 11.9996C8.4509 11.9996 8.64177 12.0786 8.7825 12.2194L10.5 13.9397L15.2194 9.21937C15.2891 9.14969 15.3718 9.09442 15.4628 9.0567C15.5539 9.01899 15.6515 8.99958 15.75 8.99958C15.8485 8.99958 15.9461 9.01899 16.0372 9.0567C16.1282 9.09442 16.2109 9.14969 16.2806 9.21937C16.3503 9.28906 16.4056 9.37178 16.4433 9.46283C16.481 9.55387 16.5004 9.65145 16.5004 9.75C16.5004 9.84855 16.481 9.94613 16.4433 10.0372C16.4056 10.1282 16.3503 10.2109 16.2806 10.2806H16.2825Z" fill="#008836"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.38325 14.2667C8.11658 14.5333 7.79992 14.6667 7.43325 14.6667C7.06659 14.6667 6.74992 14.5333 6.48325 14.2667L1.71659 9.50001C1.46103 9.24445 1.33325 8.93057 1.33325 8.55834C1.33325 8.18612 1.46103 7.87223 1.71659 7.61668L7.58325 1.73334C7.70547 1.61112 7.84992 1.5139 8.01658 1.44168C8.18325 1.36945 8.36103 1.33334 8.54992 1.33334H13.3166C13.6833 1.33334 13.9971 1.4639 14.2583 1.72501C14.5194 1.98612 14.6499 2.30001 14.6499 2.66668V7.43334C14.6499 7.62223 14.6138 7.80001 14.5416 7.96668C14.4694 8.13334 14.3721 8.27779 14.2499 8.40001L8.38325 14.2667ZM11.6499 5.33334C11.9277 5.33334 12.1638 5.23612 12.3583 5.04168C12.5527 4.84723 12.6499 4.61112 12.6499 4.33334C12.6499 4.05557 12.5527 3.81945 12.3583 3.62501C12.1638 3.43057 11.9277 3.33334 11.6499 3.33334C11.3721 3.33334 11.136 3.43057 10.9416 3.62501C10.7471 3.81945 10.6499 4.05557 10.6499 4.33334C10.6499 4.61112 10.7471 4.84723 10.9416 5.04168C11.136 5.23612 11.3721 5.33334 11.6499 5.33334ZM7.43325 13.3333L13.3166 7.43334V2.66668H8.54992L2.66659 8.56668L7.43325 13.3333Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

11
packages/icons/svgs/sliders.svg Executable file
View File

@@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66699 13.9999V9.33325" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.66699 6.66667V2" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 14V8" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 5.33333V2" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.333 14.0001V10.6667" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.333 8V2" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M0.666992 9.33325H4.66699" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 5.33325H10" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.333 10.6667H15.333" stroke="#181818" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 8C8 8.13261 7.94732 8.25979 7.85355 8.35355C7.75979 8.44732 7.63261 8.5 7.5 8.5H3C2.86739 8.5 2.74021 8.44732 2.64645 8.35355C2.55268 8.25979 2.5 8.13261 2.5 8C2.5 7.86739 2.55268 7.74021 2.64645 7.64645C2.74021 7.55268 2.86739 7.5 3 7.5H7.5C7.63261 7.5 7.75979 7.55268 7.85355 7.64645C7.94732 7.74021 8 7.86739 8 8ZM3 4.5H11.5C11.6326 4.5 11.7598 4.44732 11.8536 4.35355C11.9473 4.25979 12 4.13261 12 4C12 3.86739 11.9473 3.74021 11.8536 3.64645C11.7598 3.55268 11.6326 3.5 11.5 3.5H3C2.86739 3.5 2.74021 3.55268 2.64645 3.64645C2.55268 3.74021 2.5 3.86739 2.5 4C2.5 4.13261 2.55268 4.25979 2.64645 4.35355C2.74021 4.44732 2.86739 4.5 3 4.5ZM6.5 11.5H3C2.86739 11.5 2.74021 11.5527 2.64645 11.6464C2.55268 11.7402 2.5 11.8674 2.5 12C2.5 12.1326 2.55268 12.2598 2.64645 12.3536C2.74021 12.4473 2.86739 12.5 3 12.5H6.5C6.63261 12.5 6.75979 12.4473 6.85355 12.3536C6.94732 12.2598 7 12.1326 7 12C7 11.8674 6.94732 11.7402 6.85355 11.6464C6.75979 11.5527 6.63261 11.5 6.5 11.5ZM14.3538 10.1462C14.3073 10.0998 14.2522 10.0629 14.1915 10.0377C14.1308 10.0126 14.0657 9.99961 14 9.99961C13.9343 9.99961 13.8692 10.0126 13.8085 10.0377C13.7478 10.0629 13.6927 10.0998 13.6462 10.1462L12 11.7931V7C12 6.86739 11.9473 6.74021 11.8536 6.64645C11.7598 6.55268 11.6326 6.5 11.5 6.5C11.3674 6.5 11.2402 6.55268 11.1464 6.64645C11.0527 6.74021 11 6.86739 11 7V11.7931L9.35375 10.1462C9.25993 10.0524 9.13268 9.99972 9 9.99972C8.86732 9.99972 8.74007 10.0524 8.64625 10.1462C8.55243 10.2401 8.49972 10.3673 8.49972 10.5C8.49972 10.6327 8.55243 10.7599 8.64625 10.8538L11.1462 13.3538C11.1927 13.4002 11.2478 13.4371 11.3085 13.4623C11.3692 13.4874 11.4343 13.5004 11.5 13.5004C11.5657 13.5004 11.6308 13.4874 11.6915 13.4623C11.7522 13.4371 11.8073 13.4002 11.8538 13.3538L14.3538 10.8538C14.4002 10.8073 14.4371 10.7522 14.4623 10.6915C14.4874 10.6308 14.5004 10.5657 14.5004 10.5C14.5004 10.4343 14.4874 10.3692 14.4623 10.3085C14.4371 10.2478 14.4002 10.1927 14.3538 10.1462Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE --><path fill="currentColor" d="M40 128a8 8 0 0 1 8-8h72a8 8 0 0 1 0 16H48a8 8 0 0 1-8-8m8-56h56a8 8 0 0 0 0-16H48a8 8 0 0 0 0 16m136 112H48a8 8 0 0 0 0 16h136a8 8 0 0 0 0-16m45.66-101.66l-40-40a8 8 0 0 0-11.32 0l-40 40a8 8 0 0 0 11.32 11.32L176 67.31V144a8 8 0 0 0 16 0V67.31l26.34 26.35a8 8 0 0 0 11.32-11.32"/></svg>

After

Width:  |  Height:  |  Size: 505 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 6.5C14 6.63261 13.9473 6.75979 13.8536 6.85355C13.7598 6.94732 13.6326 7 13.5 7C13.3674 7 13.2402 6.94732 13.1464 6.85355C13.0527 6.75979 13 6.63261 13 6.5V3.7075L8.85437 7.85375C8.76055 7.94757 8.63331 8.00028 8.50062 8.00028C8.36794 8.00028 8.2407 7.94757 8.14688 7.85375C8.05305 7.75993 8.00035 7.63268 8.00035 7.5C8.00035 7.36732 8.05305 7.24007 8.14688 7.14625L12.2925 3H9.5C9.36739 3 9.24021 2.94732 9.14645 2.85355C9.05268 2.75979 9 2.63261 9 2.5C9 2.36739 9.05268 2.24021 9.14645 2.14645C9.24021 2.05268 9.36739 2 9.5 2H13.5C13.6326 2 13.7598 2.05268 13.8536 2.14645C13.9473 2.24021 14 2.36739 14 2.5V6.5ZM11.5 8C11.3674 8 11.2402 8.05268 11.1464 8.14645C11.0527 8.24021 11 8.36739 11 8.5V13H3V5H7.5C7.63261 5 7.75979 4.94732 7.85355 4.85355C7.94732 4.75979 8 4.63261 8 4.5C8 4.36739 7.94732 4.24021 7.85355 4.14645C7.75979 4.05268 7.63261 4 7.5 4H3C2.73478 4 2.48043 4.10536 2.29289 4.29289C2.10536 4.48043 2 4.73478 2 5V13C2 13.2652 2.10536 13.5196 2.29289 13.7071C2.48043 13.8946 2.73478 14 3 14H11C11.2652 14 11.5196 13.8946 11.7071 13.7071C11.8946 13.5196 12 13.2652 12 13V8.5C12 8.36739 11.9473 8.24021 11.8536 8.14645C11.7598 8.05268 11.6326 8 11.5 8Z" fill="#181818"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1253_14370)">
<path d="M5.74163 9.31794C5.90053 9.22204 6.09947 9.22204 6.25837 9.31794L8.6935 10.7877C9.07216 11.0162 9.53928 10.6767 9.4388 10.246L8.79256 7.4759C8.7504 7.29515 8.81182 7.10592 8.9521 6.98439L11.1043 5.11994C11.4386 4.83034 11.2599 4.28121 10.8192 4.24382L7.98643 4.00349C7.80164 3.98781 7.64071 3.87114 7.56834 3.70039L6.46036 1.08618C6.28807 0.67967 5.71194 0.67967 5.53964 1.08618L4.43166 3.70039C4.35929 3.87114 4.19836 3.98781 4.01357 4.00349L1.18082 4.24382C0.740103 4.28121 0.561398 4.83034 0.895697 5.11994L3.0479 6.98439C3.18818 7.10592 3.2496 7.29515 3.20744 7.4759L2.56121 10.246C2.46073 10.6767 2.92784 11.0162 3.3065 10.7877L5.74163 9.31794Z" fill="#E5C131"/>
</g>
<defs>
<clipPath id="clip0_1253_14370">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 928 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.99992 1.33331L10.0599 5.50665L14.6666 6.17998L11.3333 9.42665L12.1199 14.0133L7.99992 11.8466L3.87992 14.0133L4.66659 9.42665L1.33325 6.17998L5.93992 5.50665L7.99992 1.33331Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 377 B

View File

@@ -0,0 +1,18 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1174_4412)">
<path d="M5.71445 8.09522C7.02941 8.09522 8.0954 7.02923 8.0954 5.71427C8.0954 4.3993 7.02941 3.33331 5.71445 3.33331C4.39948 3.33331 3.3335 4.3993 3.3335 5.71427C3.3335 7.02923 4.39948 8.09522 5.71445 8.09522Z" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.71436 0.476196V1.42858" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.71436 10V10.9524" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.00977 2.00952L2.68596 2.68571" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.74268 8.74286L9.41887 9.41905" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M0.476074 5.71429H1.42846" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 5.71429H10.9524" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.00977 9.41905L2.68596 8.74286" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.74268 2.68571L9.41887 2.00952" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1174_4412">
<rect width="11.4286" height="11.4286" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 4H3.33333H14" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.6668 4.00001V13.3333C12.6668 13.687 12.5264 14.0261 12.2763 14.2762C12.0263 14.5262 11.6871 14.6667 11.3335 14.6667H4.66683C4.31321 14.6667 3.97407 14.5262 3.72402 14.2762C3.47397 14.0261 3.3335 13.687 3.3335 13.3333V4.00001M5.3335 4.00001V2.66668C5.3335 2.31305 5.47397 1.97392 5.72402 1.72387C5.97407 1.47382 6.31321 1.33334 6.66683 1.33334H9.3335C9.68712 1.33334 10.0263 1.47382 10.2763 1.72387C10.5264 1.97392 10.6668 2.31305 10.6668 2.66668V4.00001" stroke="#666666" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 769 B

Some files were not shown because too many files have changed in this diff Show More