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
41 changes: 30 additions & 11 deletions React/Components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getBookmarks } from "React/Utils/getBookmarks";
import { BeautitabPluginSettings } from "src/Settings/Settings";
import getQuote from "React/Utils/getQuote";
import { BackgroundTheme } from "src/Types/Enums";
import { CachedBackground } from "../../../src/Types/Interfaces";

/**
* Given an icon name, converts a Obsidian icon to a usable SVG string and embeds it into a span.
Expand Down Expand Up @@ -44,24 +45,42 @@ const App = ({
const [settings, setSettings] = useState<BeautitabPluginSettings>(
settingsObservable.getValue()
);
const [bg, setBg] = useState<CachedBackground | null>(null);
const [time, setTime] = useState(getTime(settings.timeFormat));
const mainDivRef = useRef<HTMLDivElement>(null);

const obsidian = useObsidian();
const background = useMemo(
() =>
getBackground(
settings.backgroundTheme,
settings.customBackground,
settings.localBackgrounds
),
[
const background = useMemo(async () => {
return await getBackground(
settings.backgroundTheme,
settings.customBackground,
settings.localBackgrounds,
]
);
settings.apiKey,
settings.cachedBackground
);
}, [
settings.backgroundTheme,
settings.customBackground,
settings.localBackgrounds,
settings.apiKey,
settings.cachedBackground,
]);
const getResult = async () => {
setBg(settings.cachedBackground ?? null);
const bg = await background;
setBg(bg);
};
useEffect(() => {
getResult();
}, [background]);

if (
(bg && bg.date !== settings.cachedBackground?.date) ||
(bg && bg.theme !== settings.cachedBackground?.theme)
) {
plugin.settings.cachedBackground = bg;
plugin.saveSettings();
}
const allVaultFiles = obsidian?.vault.getAllLoadedFiles();
const latestModifiedMarkdownFiles = useMemo(() => {
const files = allVaultFiles?.filter(
Expand Down Expand Up @@ -142,7 +161,7 @@ const App = ({
`}
// @ts-ignore
style={{
backgroundImage: `url("${background}")`,
backgroundImage: `url("${bg?.url}")`,
}}
onKeyDown={(e) => {
if (!e.ctrlKey && !e.altKey && /^[A-Za-z0-9]$/.test(e.key)) {
Expand Down
80 changes: 66 additions & 14 deletions React/Utils/getBackground.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { BackgroundTheme } from "src/Types/Enums";
import getEasterDate from "./getEasterDate";
import { isWithinDaysBefore } from "./isWithinXDays";
import { isWithinDaysBefore, isWithinHoursAfter } from "./isWithinXDays";
import { createApi } from 'unsplash-js';
//@ts-ignore - This is a polyfill for fetch and work using --lib dom
import { fetch as fetchPolyfill } from 'whatwg-fetch';
import { CachedBackground } from "../../src/Types/Interfaces";

enum MONTH {
JANUARY = 1,
Expand Down Expand Up @@ -147,30 +151,78 @@ const getSeasonalTag = (date: Date) => {
* @param backgroundTheme
* @param customBackground
*/
const getBackground = (
const getBackground = async (
backgroundTheme: BackgroundTheme,
customBackground: string,
localBackgrounds: string[]
) => {
localBackgrounds: string[],
apiKey: string,
cachedBackground?: CachedBackground
): Promise<CachedBackground | null> => {

switch (backgroundTheme) {
case BackgroundTheme.SEASONS_AND_HOLIDAYS:
if (
cachedBackground && cachedBackground.url.length > 0 && cachedBackground.theme === backgroundTheme &&
!isWithinHoursAfter(new Date(cachedBackground.date), 1, new Date())
)
return cachedBackground;
const seasonalTag = getSeasonalTag(new Date());
return `https://source.unsplash.com/random?${seasonalTag}&cachetag=${new Date()
.toDateString()
.replace(/ /g, "")}`;

if (apiKey.length === 0) return null;

const seasonHolidays = await createApi({
accessKey: apiKey,
fetch: fetchPolyfill,
}).photos.getRandom({
query: seasonalTag,
count: 1,
}).then((result) => {
return result.response;
});

if (seasonHolidays) {
if (seasonHolidays instanceof Array) {
return { url: seasonHolidays[0].urls.raw, date: new Date(), theme: backgroundTheme };
}
return { url: seasonHolidays.urls.raw, date: new Date(), theme: backgroundTheme };
}
return null;
case BackgroundTheme.CUSTOM:
return customBackground;
return { url: customBackground, date: new Date() };
case BackgroundTheme.LOCAL:
return localBackgrounds[
Math.floor(Math.random() * localBackgrounds.length)
];
return {
url: localBackgrounds[
Math.floor(Math.random() * localBackgrounds.length)],
date: new Date()
};
case BackgroundTheme.TRANSPARENT_WITH_SHADOWS:
case BackgroundTheme.TRANSPARENT:
return null;
default:
return `https://source.unsplash.com/random?${backgroundTheme}&cachetag=${new Date()
.toDateString()
.replace(/ /g, "")}`;
if (
cachedBackground && cachedBackground.url.length > 0 &&
backgroundTheme === cachedBackground.theme &&
!isWithinHoursAfter(new Date(cachedBackground.date), 1, new Date())
) return cachedBackground;

if (apiKey.length === 0) return null;

const defRandom = await createApi({
accessKey: apiKey,
fetch: fetchPolyfill,
}).photos.getRandom({
count: 1,
query: backgroundTheme,
}).then((result) => {
return result.response;
});
if (defRandom) {
if (defRandom instanceof Array) {
return { url: defRandom[0].urls.raw, date: new Date(), theme: backgroundTheme };
}
return { url: defRandom.urls.raw, date: new Date(), theme: backgroundTheme };
}
return null;
}
};

Expand Down
20 changes: 19 additions & 1 deletion React/Utils/isWithinXDays.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Returns true if dateA within 5 days of dateB (dateB minus 5)
* Returns true if dateA within X days of dateB (dateB minus X)
* @param dateA
* @param days
* @param dateB
Expand Down Expand Up @@ -38,3 +38,21 @@ export const isWithinDaysAfter = (
timestampB < timestampA && timestampA - timestampB <= daysInMilliseconds
);
};

/**
* Returns true if the hours of dateA are within the hours of dateB
* Aka dateA is *before* dateB and their hours of difference is more than 1 hours
* @param dateA {Date} - The "cached" date
* @param hours {number} - The number of hours to compare
* @param dateB {Date} - The "current" date
* @returns {boolean}
*/
export const isWithinHoursAfter = (dateA: Date, hours: number, dateB: Date): boolean => {
//return true if cached date is before the current date
const dayA = new Date(dateA.getFullYear(), dateA.getMonth(), dateA.getDate());
const dayB = new Date(dateB.getFullYear(), dateB.getMonth(), dateB.getDate());
if (dayA < dayB) return true;
const hoursA = dateA.getHours();
const hoursB = dateB.getHours();
return hoursA < hoursB && hoursB - hoursA >= hours;
};
3 changes: 2 additions & 1 deletion Views/ReactView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Observable from "src/Utils/Observable";
import BeautitabPlugin from "main";

export const BEAUTITAB_REACT_VIEW = "beautitab-react-view";
const Translate = i18next.t.bind(i18next);

export class ReactView extends FileView {
root: Root | null = null;
Expand All @@ -31,7 +32,7 @@ export class ReactView extends FileView {
}

getDisplayText() {
return "New tab";
return Translate("interface.label-new-tab");
}

getIcon() {
Expand Down
2 changes: 1 addition & 1 deletion esbuild.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import builtins from "builtin-modules";
import { sassPlugin } from "esbuild-sass-plugin";
import copyStaticFiles from "esbuild-copy-static-files";
import path from "path";
import packageJson from "./package.json" assert { type: "json" };
import packageJson from "./package.json" with { type: "json" };

const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
Expand Down
24 changes: 9 additions & 15 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Notice, Plugin, requestUrl } from "obsidian";
import { Notice, Platform, Plugin, InternalPluginName, requestUrl } from "obsidian";
import { ReactView, BEAUTITAB_REACT_VIEW } from "./Views/ReactView";
import Observable from "src/Utils/Observable";
import {
Expand Down Expand Up @@ -45,21 +45,19 @@ export default class BeautitabPlugin extends Plugin {
);

if (process.env.NODE_ENV === "development") {
// @ts-ignore
if (process.env.EMULATE_MOBILE && !this.app.isMobile) {
// @ts-ignore
if (process.env.EMULATE_MOBILE && !Platform.isMobile) {
this.app.emulateMobile(true);
}

// @ts-ignore
if (!process.env.EMULATE_MOBILE && this.app.isMobile) {
// @ts-ignore
if (!process.env.EMULATE_MOBILE && Platform.isMobile) {
this.app.emulateMobile(false);
}
}
}

onunload() {}
onunload() {
console.log("unloading Beautitab");
}

/**
* Load data from disk, stored in data.json in plugin folder
Expand Down Expand Up @@ -132,13 +130,9 @@ export default class BeautitabPlugin extends Plugin {
*/
openSwitcherCommand(command: string): void {
const pluginID = command.split(":")[0];
//@ts-ignore
const plugins = this.app.plugins.plugins;
//@ts-ignore
const internalPlugins = this.app.internalPlugins.plugins;

if (plugins[pluginID] || internalPlugins[pluginID]?.enabled) {
//@ts-ignore
const communitySwitcher = this.app.plugins.enabledPlugins.has(pluginID);
const internalSwitcher = this.app.internalPlugins.getEnabledPluginById(pluginID as InternalPluginName);
if (communitySwitcher || internalSwitcher) {
this.app.commands.executeCommandById(command);
} else {
new Notice(
Expand Down
4 changes: 2 additions & 2 deletions manifest-beta.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"id": "beautitab",
"name": "Beautitab",
"version": "1.6.0-beta.2",
"version": "1.6.1",
"minAppVersion": "0.15.0",
"description": "Creates a customizable new tab view with beautiful backgrounds, quotes, search, and more.",
"author": "Andrew McGivery",
"authorUrl": "https://github.com/andrewmcgivery",
"fundingUrl": "https://www.buymeacoffee.com/andrewmcgivery",
"isDesktopOnly": false
}
}
Loading