Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"dot-notation": "error",
"eqeqeq": "error",
"max-lines": ["error"],
"multiline-comment-style": "error",
"no-console": "warn",
"no-duplicate-imports": "error",
"no-else-return": "warn",
Expand Down
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# What has been done

-

## To do

- [ ]

## Notes

-
13 changes: 0 additions & 13 deletions .github/templates/pull_request_template.md

This file was deleted.

Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.50.1",
"react-intersection-observer": "^9.13.1",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"uuid": "^10.0.0",
Expand Down
6 changes: 3 additions & 3 deletions src/components/Bookmarks/Bookmarks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { Bookmarks, bookmarks, tabs } from "webextension-polyfill";

import { filterBookmarks } from "@/src/services/bookmarks/filterBookmarks";
import { mapBookmarks } from "@/src/services/bookmarks/mapBookmarks";
import {
filterBookmarks,
mapBookmarks,
SortMode,
SortModes,
sortBookmarks,
} from "@/src/services/bookmarks/sortBookmarks";
} from "@/src/services/bookmarks";
import { cn } from "@/src/utils";

import BookmarkItem from "./partials/BookmarkItem";
Expand Down
11 changes: 7 additions & 4 deletions src/components/Homescreen/Homescreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { cn } from "@/src/utils";
import InfoWidget from "../InfoWidget/InfoWidget";
import Modals from "../Modals/Modals";
import Sidebar from "../Sidebar/Sidebar";
import ImageFadeIn from "../ui/ImageFadeIn";
import ImageBackgroundFadeIn from "../ui/ImageBackgroundFadeIn";

const Homescreen = () => {
const { data: settings, isPending, toggleSidebarSetting } = useSettings();
Expand All @@ -16,6 +16,9 @@ const Homescreen = () => {
const isSidebarOpen = settings?.sidebar?.isOpen;

useKeyPress(hotkeys.backslash, () => toggleSidebarSetting("isOpen"));
useKeyPress(hotkeys.greaterThan, () =>
window.open("/src/pages/history/index.html")
);
useEasterEggs();

if (isPending) {
Expand All @@ -30,8 +33,8 @@ const Homescreen = () => {
isExpanded={!!isSidebarOpen}
setIsExpanded={() => toggleSidebarSetting("isOpen")}
/>
<ImageFadeIn
asBackground={true}

<ImageBackgroundFadeIn
src={activeBg.src}
alt="A fancy background image"
className={cn(
Expand All @@ -49,7 +52,7 @@ const Homescreen = () => {
)}
/>
)}
</ImageFadeIn>
</ImageBackgroundFadeIn>
</div>
</>
);
Expand Down
5 changes: 1 addition & 4 deletions src/components/Modals/SettingsModal/partials/rows.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
HomescreenSettings,
SidebarSettings,
} from "@/src/services/settings/types";
import { HomescreenSettings, SidebarSettings } from "@/src/services/settings";

type SettingsRows = {
sidebar: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modals/ShortlinksModal/ShortlinksModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { v4 as uuidv4 } from "uuid";
import { Modals, useModalStore } from "@/src/hooks/stores/useModalStore";
import { useShortlinkStore } from "@/src/hooks/stores/useShortlinkStore";
import { addShortlink, deleteShortlink } from "@/src/services/shortlinks";
import { normalizeUrl } from "@/src/utils/normalizeUrl";
import { normalizeUrl } from "@/src/utils";

import FormField from "./partials/FormField";
import Button, { buttonVariants } from "../../ui/Button";
Expand Down
9 changes: 9 additions & 0 deletions src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ const Sidebar = ({ isExpanded, setIsExpanded }: Props) => {
<FeedbackPrompt />
</>
)}
<>
<p>&middot;</p>
<a
href="/src/pages/history/index.html"
className="text-black/70 underline hover:text-black hover:no-underline"
>
View history
</a>
</>
</div>
</div>
</div>
Expand Down
38 changes: 38 additions & 0 deletions src/components/ui/ImageBackgroundFadeIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ComponentProps, ReactNode, useEffect, useState } from "react";

import { cn } from "@/src/utils";

interface ImageBackgroundFadeInProps extends ComponentProps<"img"> {
src: string;
alt: string;
className?: string;
children: ReactNode;
}

const ImageBackgroundFadeIn = ({
className,
children,
...props
}: ImageBackgroundFadeInProps) => {
const [isLoaded, setIsLoaded] = useState(false);

useEffect(() => {
const image = new Image();
image.src = props.src;
image.onload = () => {
setIsLoaded(true);
};
}, [props.src]);

return (
<div
style={{ backgroundImage: `url('${props.src}')` }}
className={cn("duration-300", className, !isLoaded && "opacity-0 ")}
{...props}
>
{children}
</div>
);
};

export default ImageBackgroundFadeIn;
34 changes: 7 additions & 27 deletions src/components/ui/ImageFadeIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,25 @@ interface ImageProps extends ComponentProps<"img"> {
src: string;
alt: string;
className?: string;
asBackground?: boolean;
}

const ImageFadeIn = ({
className,
children,
asBackground = false,
...props
}: ImageProps) => {
const ImageFadeIn = ({ className, ...props }: ImageProps) => {
const [isLoaded, setIsLoaded] = useState(false);

useEffect(() => {
if (!asBackground) {
return;
}

const image = new Image();
image.src = props.src;
image.onload = () => {
setIsLoaded(true);
};
}, [asBackground, props.src]);

const classes = cn("duration-300", className, !isLoaded && "opacity-0 ");

if (asBackground) {
return (
<div
style={{ backgroundImage: `url('${props.src}')` }}
className={classes}
{...props}
>
{children}
</div>
);
}
}, [props.src]);

return (
<img className={classes} onLoad={() => setIsLoaded(true)} {...props} />
<img
className={cn("duration-300", className, !isLoaded && "opacity-0 ")}
onLoad={() => setIsLoaded(true)}
{...props}
/>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Spinner.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cn } from "@/src/utils";

type Props = {
className: string;
className?: string;
};

const Spinner = ({ className }: Props) => (
Expand Down
39 changes: 39 additions & 0 deletions src/hooks/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Via: https://gist.github.com/KristofferEriksson/2d78b69401be23e05f8b1ac12a998da4

import { useEffect, useState } from "react";

/**
* useDebounce hook
* This hook allows you to debounce any fast changing value. The debounced value will only
* reflect the latest value when the useDebounce hook has not been called for the specified delay period.
*
* @param value - The value to be debounced.
* @param delay - The delay in milliseconds for the debounce.
* @returns The debounced value.
*/
export function useDebounce<T>(value: T, delay: number): { debouncedValue: T } {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
if (typeof value === "string" && value.trim().length === 0) {
setDebouncedValue(value);
return;
}

// Update debounced value after the specified delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);

/*
* Cancel the timeout if value changes (also on delay change or unmount)
* This is how we prevent debounced value from updating if value is changed within the delay period
*/
return () => {
clearTimeout(handler);
};
}, [value, delay]); // Only re-call effect if value or delay changes

return { debouncedValue };
}
1 change: 1 addition & 0 deletions src/hooks/useKeyPress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const hotkeys = {
questionMark: "?",
left: "ArrowLeft",
right: "ArrowRight",
greaterThan: ">",
} as const;

type Hotkeys = (typeof hotkeys)[keyof typeof hotkeys];
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useRandomBackground.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";

import { dailyRandomNumber } from "@/src/utils/dailyRandomNumber";
import { dailyRandomNumber } from "@/src/utils";
// import useKeyPress from "./useKeyPress";

type Background = {
Expand Down
8 changes: 4 additions & 4 deletions src/hooks/useSettings.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { defaultSettings } from "../services/settings/defaultSettings";
import { editSettings } from "../services/settings/editSettings";
import { getSettings } from "../services/settings/getSettings";
import {
defaultSettings,
editSettings,
getSettings,
HomescreenSettings,
Settings,
SidebarSettings,
} from "../services/settings/types";
} from "@/src/services/settings";

export const useSettings = () => {
const queryClient = useQueryClient();
Expand Down
7 changes: 5 additions & 2 deletions src/hooks/useUpdateNotification.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useEffect, useState } from "react";

import { getUpdateNotification } from "@/src/services/updateNotification/getUpdateNotification";
import { setUpdateNotification } from "@/src/services/updateNotification/setUpdateNotification";
import {
getUpdateNotification,
setUpdateNotification,
} from "@/src/services/updateNotification";

export const useUpdateNotification = () => {
const [isVisible, setIsVisible] = useState(false);
Expand All @@ -16,6 +18,7 @@ export const useUpdateNotification = () => {
setUpdateNotification(false);
};

// TODO: Refactor in TanStack Query
useEffect(() => {
const fetchData = async () => {
const data = await getUpdateNotification();
Expand Down
2 changes: 1 addition & 1 deletion src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const manifest: Manifest.WebExtensionManifest = {
},
manifest_version: 3,
name: "UpTab",
permissions: ["storage", "geolocation", "bookmarks"],
permissions: ["storage", "geolocation", "bookmarks", "history"],
version: pkg.version,
web_accessible_resources: [
{
Expand Down
Loading