diff --git a/package.json b/package.json
index c6d92bfa..42b2e092 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"@sentry/react": "^7.17.2",
"embla-carousel-autoplay": "^7.0.3",
"embla-carousel-react": "^7.0.3",
+ "fast-blurhash": "^1.1.1",
"image-conversion": "^2.1.1",
"react": "^18.2.0",
"react-clock": "3.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3f18ba89..fe9bf7a4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,7 @@ specifiers:
embla-carousel-react: ^7.0.3
eslint: ^8.26.0
eslint-config-react-app: ^7.0.1
+ fast-blurhash: ^1.1.1
husky: ^8.0.1
image-conversion: ^2.1.1
prettier: ^2.7.1
@@ -45,6 +46,7 @@ dependencies:
'@sentry/react': 7.17.2_react@18.2.0
embla-carousel-autoplay: 7.0.3
embla-carousel-react: 7.0.3_react@18.2.0
+ fast-blurhash: 1.1.1
image-conversion: 2.1.1
react: 18.2.0
react-clock: 3.1.0_biqbaboplfbrettd7655fr4n2y
@@ -3605,6 +3607,10 @@ packages:
resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==}
dev: false
+ /fast-blurhash/1.1.1:
+ resolution: {integrity: sha512-U3mTWNRE92S4gKARJBbUmEpuYtnet+1BEeUf1qWrUHs54Db4+0aDqI9LBu7doCueFf2SRlfbR89bj+Cm89uw8A==}
+ dev: false
+
/fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
diff --git a/src/components/modals/main/settings/ChipSelect.jsx b/src/components/modals/main/settings/ChipSelect.jsx
new file mode 100644
index 00000000..ec7c2547
--- /dev/null
+++ b/src/components/modals/main/settings/ChipSelect.jsx
@@ -0,0 +1,56 @@
+import { useState, memo, useEffect } from 'react';
+import { useTheme } from '@mui/material/styles';
+import Box from '@mui/material/Box';
+import OutlinedInput from '@mui/material/OutlinedInput';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Chip from '@mui/material/Chip';
+
+function ChipSelect({ label, options, name }) {
+ const [optionsSelected, setoptionsSelected] = useState([]);
+
+ const handleChange = (event) => {
+ const {
+ target: { value },
+ } = event;
+ setoptionsSelected(
+ typeof value === 'string' ? value.split(',') : value,
+ );
+ localStorage.setItem('apiCategories', optionsSelected)
+ };
+ console.log(localStorage.getItem('apiCategories'))
+
+
+ return (
+
+
+ {label}
+ }
+ renderValue={(optionsSelected) => (
+
+ {optionsSelected.map((value) => (
+
+ ))}
+
+ )}
+ >
+ {options.map((option) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default memo(ChipSelect);
diff --git a/src/components/modals/main/settings/sections/background/Background.jsx b/src/components/modals/main/settings/sections/background/Background.jsx
index 2ead80c4..1131a7d7 100644
--- a/src/components/modals/main/settings/sections/background/Background.jsx
+++ b/src/components/modals/main/settings/sections/background/Background.jsx
@@ -5,6 +5,7 @@ import { MdSource, MdOutlineKeyboardArrowRight, MdOutlineAutoAwesome } from 'rea
import Header from '../../Header';
import Checkbox from '../../Checkbox';
+import ChipSelect from '../../ChipSelect';
import Dropdown from '../../Dropdown';
import Slider from '../../Slider';
import Radio from '../../Radio';
@@ -125,16 +126,25 @@ export default class BackgroundSettings extends PureComponent {
>
) : (
-
- {this.state.backgroundCategories.map((category) => (
-
- ))}
-
+ <>
+ {/*
+ {this.state.backgroundCategories.map((category) => (
+
+ ))}
+
+
+ */}
+ >
)}
{
- backgroundImage.classList.remove('backgroundPreload');
+ // // once image has loaded, add the fade-in transition
+ // preloader.addEventListener('load', () => {
+ // backgroundImage.classList.remove('backgroundPreload');
+ // backgroundImage.classList.add('fade-in');
+
+ // backgroundImage.style.background = `url(${url})`;
+ // // remove the preloader element we created earlier
+ // preloader.remove();
+
+ // if (photoInformation) {
+ // photoInformation.classList.remove('backgroundPreload');
+ // photoInformation.classList.add('fade-in');
+ // }
+ // });
+
+ if (this.state.photoInfo.blur_hash) {
+ backgroundImage.style.backgroundColor = this.state.photoInfo.colour;
backgroundImage.classList.add('fade-in');
+ const canvas = document.createElement('canvas');
+ canvas.width = 32;
+ canvas.height = 32;
+ const ctx = canvas.getContext('2d');
+ const imageData = ctx.createImageData(32, 32);
+ imageData.data.set(decodeBlurHash(this.state.photoInfo.blur_hash, 32, 32));
+ ctx.putImageData(imageData, 0, 0);
+ // let blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
+ // const blobUrl = URL.createObjectURL(blob);
+ backgroundImage.style.backgroundImage = `url(${canvas.toDataURL()})`;
+ // backgroundImage.style.backgroundImage = `url(${blobUrl})`;
+ }
- backgroundImage.style.background = `url(${url})`;
- // remove the preloader element we created earlier
- preloader.remove();
-
- if (photoInformation) {
- photoInformation.classList.remove('backgroundPreload');
- photoInformation.classList.add('fade-in');
- }
- });
+ // const img = new Image();
+ // img.fetchPriority = 'high';
+ // img.decoding = 'async';
+ // img.src = url;
+ // await img.decode();
+ // this.state.photoInfo.width = img.width;
+ // this.state.photoInfo.height = img.height;
+ const blobUrl = URL.createObjectURL(await (await fetch(url)).blob()); // TODO: revoke this later
+ backgroundImage.classList.add('backgroundTransform');
+ backgroundImage.style.backgroundImage = `url(${blobUrl})`;
+ // img.remove();
+ // URL.revokeObjectURL(blobUrl);
} else {
// custom colour
backgroundImage.setAttribute('style', this.state.style);
@@ -113,6 +143,14 @@ export default class Background extends PureComponent {
return setFavourited(favourited);
}
+ let apiCategories;
+
+ try {
+ let apiCategories = JSON.parse(localStorage.getItem('apiCategories'))
+ } catch (error) {
+ let apiCategories = localStorage.getItem('apiCategories')
+ }
+
const type = localStorage.getItem('backgroundType');
switch (type) {
case 'api':
@@ -122,20 +160,19 @@ export default class Background extends PureComponent {
// API background
const backgroundAPI = localStorage.getItem('backgroundAPI');
- const apiCategories = JSON.parse(localStorage.getItem('apiCategories'));
const apiQuality = localStorage.getItem('apiQuality');
let requestURL, data;
switch (backgroundAPI) {
case 'unsplash':
- requestURL = `${variables.constants.API_URL}/images/unsplash?category=${apiCategories}&quality=${apiQuality}`;
+ requestURL = `${variables.constants.API_URL}/images/unsplash?categories=${apiCategories}&quality=${apiQuality}`;
break;
case 'pexels':
requestURL = `${variables.constants.API_URL}/images/pexels?quality=${apiQuality}`;
break;
// Defaults to Mue
default:
- requestURL = `${variables.constants.API_URL}/images/random?category=${apiCategories}&quality=${apiQuality}`;
+ requestURL = `${variables.constants.API_URL}/images/random?categories=${apiCategories}&quality=${apiQuality}`;
break;
}
@@ -172,6 +209,9 @@ export default class Background extends PureComponent {
downloads: data.downloads || null,
likes: data.likes || null,
description: data.description || null,
+ colour: data.colour,
+ blur_hash: data.blur_hash,
+ pun: data.pun || null,
},
};
diff --git a/src/components/widgets/background/PhotoInformation.jsx b/src/components/widgets/background/PhotoInformation.jsx
index 1389477b..ce1f026e 100644
--- a/src/components/widgets/background/PhotoInformation.jsx
+++ b/src/components/widgets/background/PhotoInformation.jsx
@@ -97,15 +97,15 @@ function PhotoInformation({ info, url, api }) {
const ddgProxy = localStorage.getItem('ddgProxy') === 'true';
// get resolution
- const img = new Image();
- img.onload = (event) => {
- setWidth(event.target.width);
- setHeight(event.target.height);
- };
- img.src =
- ddgProxy && !info.offline && !url.startsWith('data:')
- ? variables.constants.DDG_IMAGE_PROXY + url
- : url;
+// const img = new Image();
+// img.onload = (event) => {
+// setWidth(event.target.width);
+// setHeight(event.target.height);
+// };
+// img.src =
+// ddgProxy && !info.offline && !url.startsWith('data:')
+// ? variables.constants.DDG_IMAGE_PROXY + url
+// : url;
// info is still there because we want the favourite button to work
if (localStorage.getItem('photoInformation') === 'false') {
@@ -132,7 +132,6 @@ function PhotoInformation({ info, url, api }) {
return null;
}
- const zoom = 12;
const tile = variables.constants.API_URL + `/map?latitude=${info.latitude}&longitude=${info.longitude}`;
showingPhotoMap = true;
@@ -318,4 +317,4 @@ function PhotoInformation({ info, url, api }) {
);
}
-export default memo(PhotoInformation);
+export default memo(PhotoInformation);
\ No newline at end of file
diff --git a/src/components/widgets/background/scss/_photoinformation.scss b/src/components/widgets/background/scss/_photoinformation.scss
index c2ce41b9..d29c4802 100644
--- a/src/components/widgets/background/scss/_photoinformation.scss
+++ b/src/components/widgets/background/scss/_photoinformation.scss
@@ -23,7 +23,7 @@
}
.concept-stats {
display: flex;
- padding-top: 5px;
+ padding-top: 5px;
gap: 20px;
@include themed() {
color: t($subColor);
@@ -61,6 +61,23 @@
}
}
+.mapOn {
+ width: 100%;
+ height: 150px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ img {
+ flex-shrink: 0;
+ min-width: 100%;
+ min-height: 100%;
+ }
+ svg {
+ display: none;
+ }
+}
+
.photoInformation-legacy {
font-size: 1.36em;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
@@ -293,7 +310,7 @@
}
.photoInformation-content {
- line-height: 2em;
+ line-height: 2em;
margin-right: 3px;
display: flex;
flex-flow: column;
diff --git a/src/components/widgets/background/scss/index.scss b/src/components/widgets/background/scss/index.scss
index e3a9fed4..41252e79 100644
--- a/src/components/widgets/background/scss/index.scss
+++ b/src/components/widgets/background/scss/index.scss
@@ -10,6 +10,21 @@
zoom: 100% !important;
}
+.backgroundTransform {
+ @include animation('fadein2 2s');
+ transition: background 2s;
+}
+
+@include keyframes(fadein2) {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
.backgroundPreload {
opacity: 0;
}