Compare commits

..

168 Commits
5.3.1 ... 6.0.5

Author SHA1 Message Date
David Ralph
e0820c6b2a chore: release 6.0.5 2022-04-08 14:43:25 +01:00
David Ralph
f58d74146d fix: icon fixes, react 18 support 2022-04-07 21:49:43 +01:00
David Ralph
81b10d9795 feat: multiline messages, add react-icons etc 2022-04-07 10:25:01 +01:00
Aksal
faacd68e44 feat(translations): Add Indonesian translation (#254) 2022-04-07 09:10:20 +01:00
dependabot[bot]
86ec24736f chore(deps): bump @mui/icons-material from 5.5.1 to 5.6.0 (#253)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.5.1 to 5.6.0.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.6.0/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-06 08:26:54 +00:00
dependabot[bot]
f219242966 chore(deps): bump @mui/material from 5.5.3 to 5.6.0 (#252)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.5.3 to 5.6.0.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.6.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-06 08:24:20 +00:00
dependabot[bot]
5853925121 chore(deps): bump @mui/material from 5.5.2 to 5.5.3 (#251)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.5.2 to 5.5.3.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.3/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-29 08:13:13 +00:00
dependabot[bot]
40ec029429 chore(deps): bump @mui/material from 5.5.1 to 5.5.2 (#250)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.5.1 to 5.5.2.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.2/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-22 08:15:26 +00:00
dependabot[bot]
3d1ab88a25 chore(deps): bump @mui/icons-material from 5.5.0 to 5.5.1 (#249)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.5.0 to 5.5.1.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.1/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-15 08:17:44 +00:00
dependabot[bot]
6269a72df6 chore(deps): bump @mui/material from 5.5.0 to 5.5.1 (#248)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.5.0 to 5.5.1.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.1/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-15 08:15:08 +00:00
dependabot[bot]
dc379563f1 chore(deps): bump @mui/material from 5.4.4 to 5.5.0 (#247)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.4.4 to 5.5.0.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-08 08:15:38 +00:00
dependabot[bot]
482330c76b chore(deps): bump @mui/icons-material from 5.4.4 to 5.5.0 (#246)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.4.4 to 5.5.0.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.5.0/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-08 08:13:05 +00:00
David Ralph
a3790094b8 Merge branch 'main' of https://github.com/mue/mue 2022-03-06 17:29:10 +00:00
David Ralph
66da158840 fix: close #245, port various fixes from 7.0 2022-03-06 17:28:25 +00:00
dependabot[bot]
0a32b25bc8 chore(deps): bump @mui/icons-material from 5.4.2 to 5.4.4 (#243)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.4.2 to 5.4.4.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.4.4/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-06 17:06:53 +00:00
dependabot[bot]
66e22b05ef chore(deps): bump @mui/material from 5.4.2 to 5.4.4 (#244)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.4.2 to 5.4.4.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.4.4/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-06 17:04:26 +00:00
L
3044961de3 Adding github action for automated submission and dependabot upkeep (#242) 2022-03-05 16:05:40 +00:00
dependabot[bot]
4857b2e17a chore(deps): bump @mui/icons-material from 5.3.1 to 5.4.2 (#240)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.3.1 to 5.4.2.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.4.2/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 16:36:47 +00:00
dependabot[bot]
deaaca537a chore(deps): bump @mui/material from 5.4.0 to 5.4.2 (#239)
Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.4.0 to 5.4.2.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v5.4.2/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 12:17:50 +00:00
dependabot[bot]
17541d269f chore(deps): bump react-toastify from 8.1.0 to 8.2.0 (#238)
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 8.1.0 to 8.2.0.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v8.1.0...v8.2.0)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 12:17:44 +00:00
dependabot[bot]
f82a283b19 chore(deps): bump react-clock from 3.0.0 to 3.1.0 (#235)
Bumps [react-clock](https://github.com/wojtekmaj/react-clock) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/wojtekmaj/react-clock/releases)
- [Commits](https://github.com/wojtekmaj/react-clock/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: react-clock
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 12:17:34 +00:00
dependabot[bot]
6129f4c186 chore(deps): bump @mui/material from 5.3.1 to 5.4.0 (#234)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.4.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-02 12:13:32 +00:00
dependabot[bot]
97756ca5e9 chore(deps): bump @mui/material from 5.2.8 to 5.3.1 (#231)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.8 to 5.3.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.3.1/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-25 12:29:21 +00:00
dependabot[bot]
ac092ee2dc chore(deps): bump @mui/icons-material from 5.2.5 to 5.3.1 (#232)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.2.5 to 5.3.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.3.1/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-25 11:21:57 +00:00
dependabot[bot]
21e197a0d9 chore(deps): bump @mui/material from 5.2.7 to 5.2.8 (#228)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.7 to 5.2.8.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.8/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-11 09:32:35 +00:00
dependabot[bot]
0548f6a3cf chore(deps): bump @mui/material from 5.2.6 to 5.2.7 (#226)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.6 to 5.2.7.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.7/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-07 15:12:29 +00:00
David Ralph
c6ce382188 fix: zero-padded time, custom background settings ui 2022-01-07 15:12:06 +00:00
David Ralph
df26dff9cc chore: release 6.0.4 2022-01-04 09:20:48 +00:00
David Ralph
bb9b4cd3c7 fix: #225 2022-01-04 09:19:09 +00:00
dependabot[bot]
d3b7088653 chore(deps): bump @mui/material from 5.2.2 to 5.2.6 (#224)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.2 to 5.2.6.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.6/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-02 16:02:27 +00:00
dependabot[bot]
a5c966aa72 chore(deps): bump @mui/icons-material from 5.2.0 to 5.2.5 (#222)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.2.0 to 5.2.5.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.5/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-02 16:01:06 +00:00
David Ralph
94a2608462 Update LICENSE 2022-01-01 15:37:56 +00:00
David Ralph
862b9d9a39 chore: move logo 2021-12-18 22:36:21 +00:00
dependabot[bot]
00961b85c8 chore(deps-dev): bump eslint-config-react-app from 6.0.0 to 7.0.0 (#221)
Bumps [eslint-config-react-app](https://github.com/facebook/create-react-app/tree/HEAD/packages/eslint-config-react-app) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/facebook/create-react-app/releases)
- [Changelog](https://github.com/facebook/create-react-app/blob/main/CHANGELOG-1.x.md)
- [Commits](https://github.com/facebook/create-react-app/commits/eslint-config-react-app@7.0.0/packages/eslint-config-react-app)

---
updated-dependencies:
- dependency-name: eslint-config-react-app
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-17 20:50:28 +00:00
dependabot[bot]
1b48d59b4c chore(deps): bump @mui/material from 5.2.1 to 5.2.2 (#216)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.1 to 5.2.2.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.2/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-30 09:40:52 +00:00
David Ralph
a170981772 chore: release 6.0.3 2021-11-28 20:01:16 +00:00
David Ralph
14d3589551 fix: create tab
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-11-28 20:00:22 +00:00
David Ralph
c736dcf57a fix: enable photo map and update, fix welcome error, fix preview 2021-11-28 14:13:24 +00:00
David Ralph
623b54eca0 fix: create tab, modal ui
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-11-28 12:39:54 +00:00
David Ralph
1dc0389a96 fix: autocomplete search 2021-11-28 11:31:00 +00:00
David Ralph
3c7be2d64d fix: background categories dropdown 2021-11-27 23:11:40 +00:00
David Ralph
5703abb685 fix: marketplace item page responsiveness 2021-11-27 21:54:58 +00:00
dependabot[bot]
8f08b4d09d chore(deps): bump @mui/material from 5.2.0 to 5.2.1 (#215)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.1/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-26 10:58:57 +00:00
dependabot[bot]
441d440c74 chore(deps): bump @mui/icons-material from 5.1.1 to 5.2.0 (#213)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.1.1 to 5.2.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.0/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-24 10:40:07 +00:00
dependabot[bot]
fe5f15be24 chore(deps): bump @mui/material from 5.1.1 to 5.2.0 (#212)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.1.1 to 5.2.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.2.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-24 10:36:45 +00:00
David Ralph
bd941896aa chore: release 6.0.2 2021-11-23 18:39:43 +00:00
David Ralph
d9563ce343 build: fix demo 2021-11-23 18:22:24 +00:00
David Ralph
af2edeb737 fix: various ui fixes, fix create tab
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-11-23 18:11:36 +00:00
David Ralph
f8ee23eb40 fix: notes breaking mue when there are many rows 2021-11-22 22:41:17 +00:00
dependabot[bot]
234d489a29 chore(deps-dev): bump copy-webpack-plugin from 9.1.0 to 10.0.0 (#209)
Bumps [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin) from 9.1.0 to 10.0.0.
- [Release notes](https://github.com/webpack-contrib/copy-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/copy-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v9.1.0...v10.0.0)

---
updated-dependencies:
- dependency-name: copy-webpack-plugin
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-22 14:02:54 +00:00
Vicente
7881e47590 fix(translations): fix typo (#211) 2021-11-18 17:59:03 +00:00
Vicente
40397ac33c feat(translations): update spanish translation (#210)
* feat(translations): update spanish translations

* feat(translations): update spanish translations
2021-11-18 17:58:24 +00:00
David Ralph
9da0cb611e chore: release 6.0.1 2021-11-18 15:08:33 +00:00
David Ralph
7c7994c63f fix: greeting date picker, addons sort dropdown 2021-11-18 14:49:20 +00:00
David Ralph
42f89b3fc3 chore: release 6.0, fix firefox bug 2021-11-17 22:10:07 +00:00
David Ralph
da6c1bba63 chore: comment out unfinished things 2021-11-17 21:50:34 +00:00
dependabot[bot]
f96399c9df chore(deps): bump @mui/icons-material from 5.1.0 to 5.1.1 (#207)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.1.0 to 5.1.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.1.1/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-17 10:03:20 +00:00
dependabot[bot]
d17948f744 chore(deps): bump @mui/material from 5.1.0 to 5.1.1 (#208)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.1.0 to 5.1.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.1.1/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-17 09:08:31 +00:00
David Ralph
cf39845892 fix(translations): add missing translations 2021-11-14 16:01:45 +00:00
David Ralph
a3fb4a6522 fix: update experimental tab 2021-11-14 14:44:16 +00:00
David Ralph
f4e88cef2e fix: widget order 2021-11-12 20:20:34 +00:00
David Ralph
e786ad654c fix: background filters, addons ui, photoinformation 2021-11-12 18:34:03 +00:00
David Ralph
a356c8fe61 fix: favourite button, greeting, lightbox etc (thanks @eartharoid) 2021-11-11 22:38:10 +00:00
David Ralph
c627599590 fix: various widget fixes and cleanup etc
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-11-11 20:43:33 +00:00
4a6f93e701 refractor(widgets): Change one-lined if statements 2021-11-11 15:26:25 +01:00
David Ralph
8aca9ae31c fix: settings fix, keybinds fix (WIP), modal ui fix 2021-11-11 10:51:45 +00:00
dependabot[bot]
8966336b93 chore(deps): bump react-modal from 3.14.3 to 3.14.4 (#206)
Bumps [react-modal](https://github.com/reactjs/react-modal) from 3.14.3 to 3.14.4.
- [Release notes](https://github.com/reactjs/react-modal/releases)
- [Changelog](https://github.com/reactjs/react-modal/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reactjs/react-modal/compare/v3.14.3...v3.14.4)

---
updated-dependencies:
- dependency-name: react-modal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-11 09:13:20 +00:00
David Ralph
41750ff0e8 fix: modal ui fixes, search and quote widget fix 2021-11-10 16:20:40 +00:00
dependabot[bot]
62066fef05 chore(deps): bump @mui/icons-material from 5.0.5 to 5.1.0 (#204)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.5 to 5.1.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.1.0/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-10 15:29:25 +00:00
dependabot[bot]
eb0ffc3cc2 chore(deps): bump @mui/material from 5.0.6 to 5.1.0 (#205)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.6 to 5.1.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.1.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-10 15:06:53 +00:00
David Ralph
3bc1409f4f fix: custom video backgrounds 2021-11-06 11:00:25 +00:00
David Ralph
c15f9d20f8 Merge branch 'main' of https://github.com/mue/mue 2021-11-04 13:58:56 +00:00
David Ralph
7f5b826683 fix: various modal things, improve ui, add missing translations etc 2021-11-04 13:58:53 +00:00
dependabot[bot]
cb2c5e3117 chore(deps): bump react-toastify from 8.0.3 to 8.1.0 (#203)
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 8.0.3 to 8.1.0.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v8.0.3...v8.1.0)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-04 11:45:24 +00:00
David Ralph
2824e7c995 feat: improve custom settings ui 2021-11-02 22:53:17 +00:00
dependabot[bot]
8888cb2144 chore(deps): bump @mui/icons-material from 5.0.4 to 5.0.5 (#200)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.5/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-01 13:28:30 +00:00
dependabot[bot]
1c80d37bda chore(deps): bump @mui/material from 5.0.4 to 5.0.6 (#202)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.4 to 5.0.6.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.6/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-01 13:25:21 +00:00
David Ralph
1b4b37d4b1 feat: improved settings and marketplace ui, better custom background support, fix webpack
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-11-01 13:24:09 +00:00
dependabot[bot]
8820343628 chore(deps): bump @mui/icons-material from 5.0.3 to 5.0.4 (#197)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.4/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-15 09:21:55 +01:00
dependabot[bot]
00f30c306e chore(deps): bump @mui/material from 5.0.3 to 5.0.4 (#198)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.4/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-15 09:13:44 +01:00
David Ralph
ed964c1354 feat: add preview mue button to welcome modal 2021-10-13 20:00:40 +01:00
David Ralph
bc8ef0d9f2 feat: new sliders, dropdowns, text inputs, update settings ui, fix language bug
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-10-12 22:18:47 +01:00
dependabot[bot]
14121fb975 chore(deps): bump @mui/material from 5.0.2 to 5.0.3 (#194)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.2 to 5.0.3.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.3/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-11 18:47:13 +01:00
dependabot[bot]
bd8d9fb8e4 chore(deps): bump @mui/icons-material from 5.0.1 to 5.0.3 (#195)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.1 to 5.0.3.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.3/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-11 18:46:14 +01:00
dependabot[bot]
2a6505799b chore(deps-dev): bump eslint from 7.32.0 to 8.0.0 (#196)
Bumps [eslint](https://github.com/eslint/eslint) from 7.32.0 to 8.0.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.32.0...v8.0.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-11 18:46:02 +01:00
David Ralph
33ef113f6d feat: add show navbar on hover setting back 2021-09-30 19:35:02 +01:00
David Ralph
a5dc2c98a0 fix: various settings tabs 2021-09-30 17:48:38 +01:00
David Ralph
c9854d5362 fix: settings tab bugs 2021-09-30 17:40:36 +01:00
dependabot[bot]
9a6119e861 chore(deps): bump @mui/material from 5.0.1 to 5.0.2 (#193)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.2/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-30 09:11:40 +01:00
David Ralph
9ac410d989 fix: background 2021-09-29 19:19:03 +01:00
David Ralph
80a7b6a56c refactor: cleanup 2021-09-28 23:04:04 +01:00
David Ralph
883f025fbb feat(translations): placeholder support, fix weather text 2021-09-27 18:37:16 +01:00
David Ralph
d1b23dc07b Merge branch 'main' of https://github.com/mue/mue 2021-09-27 17:58:34 +01:00
David Ralph
364fb4b0d7 perf: reduce custom background lag on large images, improve h3 style 2021-09-27 17:58:28 +01:00
dependabot[bot]
cef4026b97 chore(deps-dev): bump @eartharoid/deep-merge from 0.0.1 to 0.0.2 (#191)
Bumps [@eartharoid/deep-merge](https://github.com/eartharoid/deep-merge) from 0.0.1 to 0.0.2.
- [Release notes](https://github.com/eartharoid/deep-merge/releases)
- [Commits](https://github.com/eartharoid/deep-merge/compare/v0.0.1...v0.0.2)

---
updated-dependencies:
- dependency-name: "@eartharoid/deep-merge"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 10:17:44 +01:00
dependabot[bot]
5702c45187 chore(deps): bump react-toastify from 8.0.2 to 8.0.3 (#190)
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 8.0.2 to 8.0.3.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v8.0.2...v8.0.3)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 10:17:34 +01:00
David Ralph
e7dc9f04d1 feat: new settings tab header, update keybinds and widget order ui
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-09-26 18:03:32 +01:00
David Ralph
bc9f68e0c1 fix: first load not working 2021-09-23 15:56:41 +01:00
dependabot[bot]
d2d7083d3d chore(deps): bump @mui/icons-material from 5.0.0 to 5.0.1 (#188)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.1/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-23 09:23:09 +01:00
dependabot[bot]
43ad2c31f8 chore(deps): bump @mui/material from 5.0.0 to 5.0.1 (#189)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.1/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-23 09:14:58 +01:00
David Ralph
fa485c35c3 Merge branch 'main' of https://github.com/mue/mue 2021-09-20 21:23:42 +01:00
David Ralph
231966546f feat: improve settings tabs and sidebar 2021-09-20 21:23:34 +01:00
BigTear
95c6216b0c feat(translations): Update Chinese translation (#187)
Add new items translation and fix some localized words
2021-09-20 10:16:03 +01:00
David Ralph
52745a267f feat: background interval for custom 2021-09-19 20:10:22 +01:00
David Ralph
cbbc911cc3 feat: create tab local quote pack/photo pack import (WIP) 2021-09-19 19:50:55 +01:00
David Ralph
e78611cb05 chore: username change 2021-09-19 16:11:19 +01:00
David Ralph
2049359a96 feat(translations): lazy load 2021-09-19 11:42:37 +01:00
David Ralph
96f26042d2 fix: toast duration setting, create quote pack section 2021-09-19 11:22:53 +01:00
David Ralph
f7ba4c0ed9 fix: reset button 2021-09-18 21:03:44 +01:00
David Ralph
4ad9d4810e feat: add create quote pack (WIP) 2021-09-18 20:51:00 +01:00
David Ralph
94e9c5d65e feat: random colour/gradient background, fix toasts 2021-09-17 19:40:22 +01:00
David Ralph
e3edc3d89e fix: quote widget zoom, add missing translations 2021-09-17 14:38:13 +01:00
David Ralph
8b4d1d18f1 feat: multiple custom quotes, fix background settings 2021-09-17 14:36:47 +01:00
David Ralph
0fd50e949c refactor(translations): cleanup and fix import settings text 2021-09-17 14:13:31 +01:00
dependabot[bot]
42b4aa1d62 chore(deps): bump @mui/icons-material from 5.0.0-rc.0 to 5.0.0 (#185)
Bumps [@mui/icons-material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-icons-material) from 5.0.0-rc.0 to 5.0.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.0/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-17 13:41:14 +01:00
dependabot[bot]
39fbd9336f chore(deps): bump @mui/material from 5.0.0-rc.0 to 5.0.0 (#186)
Bumps [@mui/material](https://github.com/mui-org/material-ui/tree/HEAD/packages/mui-material) from 5.0.0-rc.0 to 5.0.0.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.0/packages/mui-material)

---
updated-dependencies:
- dependency-name: "@mui/material"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-17 13:40:18 +01:00
David Ralph
93ba1cd9bf feat: random messages 2021-09-17 13:39:55 +01:00
David Ralph
a946d07c9c fix(translations): no longer crashes on welcome or file upload 2021-09-16 12:47:53 +01:00
David Ralph
3f3ee2dd82 fix: no animations setting not working on some things 2021-09-15 23:27:26 +01:00
David Ralph
4953298b9f fix(translations): add missing translated text 2021-09-15 22:39:29 +01:00
David Ralph
f931abf3fb feat: quick links custom icon and text only options, message widget, fix error 2021-09-15 22:38:24 +01:00
David Ralph
b97b925978 fix: translation and colour picker bugs 2021-09-14 20:15:15 +01:00
David Ralph
1c65447c55 fix: optimise background settings, add missing translation 2021-09-11 13:33:26 +01:00
David Ralph
66a3629b51 fix: photo information undefined text 2021-09-10 19:33:56 +01:00
David Ralph
7e3fc8085e refactor: cleanup background and keybinds, add translation for add custom background 2021-09-10 19:25:09 +01:00
David Ralph
6cd934acdc chore: switch from material-ui to mui 2021-09-10 19:00:45 +01:00
David Ralph
a7e7743028 feat: better remove background button
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-09-10 18:52:51 +01:00
dependabot[bot]
27668172ec chore(deps): bump react-hot-keys from 2.7.0 to 2.7.1 (#184)
Bumps [react-hot-keys](https://github.com/jaywcjlove/react-hotkeys) from 2.7.0 to 2.7.1.
- [Release notes](https://github.com/jaywcjlove/react-hotkeys/releases)
- [Commits](https://github.com/jaywcjlove/react-hotkeys/compare/v2.7.0...v2.7.1)

---
updated-dependencies:
- dependency-name: react-hot-keys
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-10 17:08:06 +01:00
David Ralph
b0eeff1bf8 feat(translations): new translation system 2021-09-10 16:38:53 +01:00
David Ralph
941c168486 fix: about tab images 2021-09-09 15:18:59 +01:00
xXFreeFunXx
aceba529ba Update german translation (#183)
The Github link on the setup page needs to be adjusted.
More details in the Discord.
2021-09-09 14:48:20 +01:00
David Ralph
2d7db1558d fix: custom background settings 2021-09-08 21:30:03 +01:00
David Ralph
102078744e feat: multiple custom backgrounds (WIP) 2021-09-08 20:58:07 +01:00
David Ralph
6bb461b8a2 fix: use constants, improve photoinformation ui 2021-09-08 11:05:34 +01:00
David Ralph
2984e162cc feat: check for addon updates, add attribution to photo location map 2021-09-07 20:42:56 +01:00
David Ralph
b86e73f2fc feat: clicking on location map now opens in openstreetmap 2021-09-07 19:10:04 +01:00
David Ralph
22ef3ad139 feat: allow duckduckgo proxy on map 2021-09-06 19:55:04 +01:00
David Ralph
26ae76accc feat: map for background location
Co-authored-by: Alex Sparkes <turbomarshmello@gmail.com>
2021-09-06 19:35:31 +01:00
dependabot[bot]
da2c70f897 chore(deps): bump react-hot-keys from 2.6.2 to 2.7.0 (#182)
Bumps [react-hot-keys](https://github.com/jaywcjlove/react-hotkeys) from 2.6.2 to 2.7.0.
- [Release notes](https://github.com/jaywcjlove/react-hotkeys/releases)
- [Commits](https://github.com/jaywcjlove/react-hotkeys/compare/v2.6.2...v2.7.0)

---
updated-dependencies:
- dependency-name: react-hot-keys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-06 09:29:06 +01:00
David Ralph
c63a13a4c2 feat: update addons, sideload error modal, show reminder for preset settings 2021-09-05 20:52:26 +01:00
David Ralph
5baf067ff1 refactor: css cleanup 2021-09-05 14:19:19 +01:00
David Ralph
7f71321e67 feat: better keybinds ui, fix notes, improve search dropdown etc 2021-09-04 12:20:58 +01:00
David Ralph
3cc8031c84 fix: search dropdown selected hover effects 2021-09-03 12:34:34 +01:00
David Ralph
b5c3ca201e fix: demo 2021-09-03 12:31:12 +01:00
David Ralph
604834c4d7 fix: notes position, navbar hot reload 2021-09-02 15:27:00 +01:00
David Ralph
d368270553 Merge branch 'main' of https://github.com/mue/mue 2021-09-02 13:55:51 +01:00
David Ralph
8cbe3b909b fix: responsive welcome modal on smaller resolutions 2021-09-02 13:55:42 +01:00
dependabot[bot]
b0399b6314 chore(deps): bump react-toastify from 8.0.0 to 8.0.2 (#181)
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 8.0.0 to 8.0.2.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v8.0.0...v8.0.2)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-01 11:12:36 +01:00
David Ralph
a00037747b fix: modal navbar tab not working 2021-08-29 18:02:25 +01:00
David Ralph
5af8dfac11 style: change about and search to use recent code 2021-08-29 11:02:55 +01:00
David Ralph
21f8b63b80 fix: search dropdown select, cleanup functional components 2021-08-28 19:14:22 +01:00
David Ralph
67ab7c8674 feat: new refresh button options 2021-08-28 18:56:59 +01:00
David Ralph
6b23e56bd6 chore: update readme 2021-08-28 18:04:00 +01:00
David Ralph
8b25175b9c fix: search dropdown css 2021-08-28 16:59:09 +01:00
David Ralph
06038a201e refactor: webpack alias imports 2021-08-28 15:34:12 +01:00
David Ralph
4db47d9fec refactor: cleanup, use createRef etc 2021-08-27 23:08:32 +01:00
David Ralph
fcff3e44a6 refactor: codacy and some style changes etc 2021-08-27 19:42:40 +01:00
David Ralph
abe70617d8 fix: console error and codacy 2021-08-27 18:27:11 +01:00
dependabot[bot]
feb7e1d93c chore(deps): bump react-toastify from 7.0.4 to 8.0.0 (#179)
Bumps [react-toastify](https://github.com/fkhadra/react-toastify) from 7.0.4 to 8.0.0.
- [Release notes](https://github.com/fkhadra/react-toastify/releases)
- [Commits](https://github.com/fkhadra/react-toastify/compare/v7.0.4...v8.0.0)

---
updated-dependencies:
- dependency-name: react-toastify
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-27 18:12:40 +01:00
David Ralph
de4ffbcb0a fix: add hover effect to search dropdown, custom support etc 2021-08-26 19:48:20 +01:00
David Ralph
e5f8cf3e66 feat: add #143 2021-08-25 13:55:20 +01:00
David Ralph
10f27d24b0 feat: new keybinds, language support etc 2021-08-25 13:28:41 +01:00
David Ralph
4a4e4604e8 feat: add no animations setting back, text shadow/border option 2021-08-25 12:01:48 +01:00
David Ralph
3ed2171a34 feat: keybinds (WIP) 2021-08-25 11:25:46 +01:00
dependabot[bot]
d33a879281 chore(deps): bump @material-ui/core from 5.0.0-beta.4 to 5.0.0-beta.5 (#178)
Bumps [@material-ui/core](https://github.com/mui-org/material-ui/tree/HEAD/packages/material-ui) from 5.0.0-beta.4 to 5.0.0-beta.5.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/next/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.0-beta.5/packages/material-ui)

---
updated-dependencies:
- dependency-name: "@material-ui/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-25 10:29:19 +01:00
dependabot[bot]
d91b939135 chore(deps): bump @material-ui/icons from 5.0.0-beta.4 to 5.0.0-beta.5 (#177)
Bumps [@material-ui/icons](https://github.com/mui-org/material-ui/tree/HEAD/packages/material-ui-icons) from 5.0.0-beta.4 to 5.0.0-beta.5.
- [Release notes](https://github.com/mui-org/material-ui/releases)
- [Changelog](https://github.com/mui-org/material-ui/blob/next/CHANGELOG.md)
- [Commits](https://github.com/mui-org/material-ui/commits/v5.0.0-beta.5/packages/material-ui-icons)

---
updated-dependencies:
- dependency-name: "@material-ui/icons"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-25 10:28:11 +01:00
David Ralph
daee291aa9 fix: welcome text, remove old buggy global widget zoom 2021-08-23 15:52:05 +01:00
David Ralph
30768053eb chore: remove umami, release 5.3.2 2021-08-23 15:33:09 +01:00
147 changed files with 5635 additions and 3088 deletions

27
.github/workflows/automerge.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: automerge
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "14.x"
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
automerge:
needs: build
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- uses: fastify/github-action-merge-dependabot@v3.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

27
.github/workflows/submit.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Submit
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to submit, i.e 6.0.5"
required: true
jobs:
submit:
runs-on: ubuntu-latest
steps:
- name: Setup Chrome
uses: browser-actions/setup-chrome@latest
with:
chrome-version: latest
- name: Download Github Release Assets
uses: plasmo-corp/download-release-asset@v1.0.0
with:
tag: ${{ github.event.inputs.tag }}
- name: Browser Plugin Publish
uses: plasmo-corp/bpp@v1
env:
PUPPETEER_EXECUTABLE_PATH: /opt/hostedtoolcache/chromium/latest/x64/chrome
with:
keys: ${{ secrets.SUBMIT_KEYS }}

4
.gitignore vendored
View File

@@ -9,4 +9,6 @@ yarn-error.log
.eslintcache
stats.json
yarn.lock
*.zip
*.zip
keys.json

View File

@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2018-2021 The Mue Authors
Copyright (c) 2018-2022 The Mue Authors
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -1,4 +1,4 @@
<img src="https://raw.githubusercontent.com/mue/branding/main/logo/logo_round.png" align="left" width="180px" height="180px"/>
<img src="assets/logo.png" align="left" width="180px" height="180px"/>
<img align="left" width="0" height="192px" hspace="10"/>
> <a href="https://muetab.com/">Mue</a>
@@ -12,7 +12,7 @@ Mue is a fast, open and free-to-use browser extension that gives a new, fresh an
<br>
## Table of contents
* [Screenshot](#screenshot)
* [Screenshots](#screenshot)
* [Features](#features)
* [Planned Features](#planned-features)
* [Installation](#installation)
@@ -37,13 +37,13 @@ Mue is a fast, open and free-to-use browser extension that gives a new, fresh an
* Supports multiple browsers
* Actively developed and open source
* Automatically updating [API](https://github.com/mue/api) with new photos, quotes and offline mode
* Widgets such as searchbar, weather, quick links, clock, date, quote, greeting
* Widgets such as search bar, weather, quick links, clock, date, quote, greeting
* Settings - enable/disable various features and customise parts of Mue
* Navbar with copy button, favourite background, notes feature etc
* [Marketplace](https://github.com/mue/marketplace) - download custom photo packs, quote packs and preset settings made by the community
### Planned Features
Please see our [roadmap](https://github.com/mue/mue/projects)
Please see our [roadmap](https://trello.com/b/w7zhS7Hi/mue-50).
## Installation
*A demo of the tab can be found [here](https://demo.muetab.com), and the latest GitHub commit build [here](https://mue.vercel.app)*
@@ -74,7 +74,7 @@ Please see the [documentation](https://docs.muetab.com/translations).
## Credits
### Developers
[David Ralph](https://github.com/davidjcralph) - Lead development, photographer <br/>
[David Ralph](https://github.com/davidcralph) - Lead development, photographer <br/>
[Alex Sparkes](https://github.com/alexsparkes) - Name, lead design, photographer <br/>
[Isaac Saunders](https://github.com/eartharoid) - QA, development, photographer <br/>
[Wessel Tip](https://github.com/Wessel) - Development <br/>
@@ -86,6 +86,7 @@ Please see the [documentation](https://docs.muetab.com/translations).
[Vicente](https://github.com/Vicente015) - Spanish <br/>
[Austin Huang](https://github.com/austinhuang0131) - Chinese (Simplified) <br/>
[FreeFun](https://github.com/xXFreeFunXx) - German <br/>
[Aksal](https://github.com/aksalsf) - Indonesian <br/>
### Contributors
Many thanks to the photographers [here](https://api.muetab.com/images/photographers) for letting us use their wonderful photographs.

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

View File

@@ -2,5 +2,5 @@ module.exports = {
presets: ['@babel/preset-env', ['@babel/preset-react', {
runtime: 'automatic'
}]],
plugins: ['@babel/plugin-proposal-class-properties', '@babel/transform-runtime', '@babel/plugin-transform-react-inline-elements', 'babel-plugin-transform-react-class-to-function', '@babel/plugin-transform-react-constant-elements']
plugins: ['@babel/transform-runtime', '@babel/plugin-transform-react-inline-elements', '@babel/plugin-transform-react-constant-elements']
};

View File

@@ -4,7 +4,7 @@
"default_locale": "en",
"name": "__MSG_name__",
"description": "__MSG_description__",
"version": "5.3.1",
"version": "6.0.5",
"homepage_url": "https://muetab.com",
"browser_action": {
"default_icon": "icons/128x128.png"

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Mue",
"description": "Fast, open and free-to-use new tab page for modern browsers.",
"version": "5.3.1",
"version": "6.0.5",
"homepage_url": "https://muetab.com",
"browser_action": {
"default_icon": "icons/128x128.png"

View File

@@ -9,50 +9,50 @@
"homepage": "https://muetab.com",
"bugs": "https://github.com/mue/mue/issues/new?assignees=&labels=bug&template=bug-report.md&title=%5BBUG%5D",
"license": "BSD-3-Clause",
"version": "5.3.1",
"version": "6.0.5",
"dependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@eartharoid/i18n": "1.0.2",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@fontsource/lexend-deca": "4.4.5",
"@fontsource/montserrat": "4.4.5",
"@material-ui/core": "5.0.0-beta.4",
"@material-ui/icons": "5.0.0-beta.4",
"react": "17.0.2",
"react-clock": "3.0.0",
"@mui/material": "5.6.0",
"react": "18.0.0",
"react-clock": "3.1.0",
"react-color-gradient-picker": "0.1.2",
"react-dom": "17.0.2",
"react-modal": "3.14.3",
"react-dom": "18.0.0",
"react-hot-keys": "2.7.1",
"react-icons": "^4.3.1",
"react-modal": "3.14.4",
"react-sortable-hoc": "2.0.0",
"react-toastify": "7.0.4",
"weather-icons-react": "1.2.0"
"react-toastify": "8.2.0"
},
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/eslint-parser": "^7.15.0",
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-transform-react-constant-elements": "^7.14.5",
"@babel/plugin-transform-react-inline-elements": "^7.14.5",
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@eartharoid/deep-merge": "^0.0.1",
"babel-loader": "^8.2.2",
"babel-plugin-transform-react-class-to-function": "^1.2.2",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.2.0",
"eslint": "^7.32.0",
"eslint-config-react-app": "^6.0.0",
"html-webpack-plugin": "^5.3.2",
"mini-css-extract-plugin": "^2.2.0",
"sass": "^1.38.0",
"sass-loader": "^12.1.0",
"source-map-loader": "^3.0.0",
"webpack": "^5.51.1",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.0.0"
"@babel/core": "^7.17.9",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-transform-react-constant-elements": "^7.17.6",
"@babel/plugin-transform-react-inline-elements": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@eartharoid/deep-merge": "^0.0.2",
"babel-loader": "^8.2.4",
"copy-webpack-plugin": "9.1.0",
"css-loader": "^6.7.1",
"eslint": "^8.12.0",
"eslint-config-react-app": "^7.0.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.0",
"sass": "^1.50.0",
"sass-loader": "^12.6.0",
"source-map-loader": "^3.0.1",
"webpack": "^5.71.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.8.1"
},
"scripts": {
"start": "webpack serve",
"updatetranslations": "cd scripts && node updatetranslations.js",
"build": "webpack --mode=production",
"chrome": "cp manifest/chrome.json build/manifest.json && cp -r manifest/_locales build/_locales && cp manifest/background-chrome.js build/background-chrome.js",
"firefox": "rm -rf build/_locales && cp manifest/firefox.json build/manifest.json"

View File

@@ -1,3 +1,4 @@
// tl;dr this function merges the translation file with the english file in order to add untranslated strings
const fs = require('fs');
const merge = require('@eartharoid/deep-merge');
@@ -8,5 +9,6 @@ fs.readdirSync('../src/translations').forEach((file) => {
const newdata = merge(require('../src/translations/en_GB.json'), require('../src/translations/' + file));
fs.writeFileSync('../src/translations/' + file, JSON.stringify(newdata, null, 2));
// add new line
fs.appendFileSync('../src/translations/' + file, '\n');
});

View File

@@ -1,13 +1,14 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { ToastContainer } from 'react-toastify';
import Background from './components/widgets/background/Background';
import Widgets from './components/widgets/Widgets';
import Modals from './components/modals/Modals';
import Background from 'components/widgets/background/Background';
import Widgets from 'components/widgets/Widgets';
import Modals from 'components/modals/Modals';
import { loadSettings, moveSettings } from './modules/helpers/settings';
import { loadSettings, moveSettings } from 'modules/helpers/settings';
import EventBus from './modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class App extends PureComponent {
componentDidMount() {
@@ -27,7 +28,7 @@ export default class App extends PureComponent {
}
});
window.stats.tabLoad();
variables.stats.tabLoad();
}
render() {

View File

@@ -1,6 +1,6 @@
import { PureComponent } from 'react';
import EventBus from '../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
import './autocomplete.scss';
@@ -35,7 +35,12 @@ export default class Autocomplete extends PureComponent {
input: e.target.innerText
});
this.props.onClick(e);
this.props.onClick({
preventDefault: () => e.preventDefault(),
target: {
value: e.target.innerText
}
});
};
componentDidMount() {
@@ -48,7 +53,7 @@ export default class Autocomplete extends PureComponent {
});
}
componentWillUnount() {
componentWillUnmount() {
EventBus.off('refresh');
}
@@ -59,26 +64,18 @@ export default class Autocomplete extends PureComponent {
if (this.state.filtered.length > 0 && this.state.input.length > 0) {
autocomplete = (
<ul className='suggestions'>
{this.state.filtered.map((suggestion) => {
return (
<li key={suggestion} onClick={this.onClick}>
{suggestion}
</li>
);
})}
{this.state.filtered.map((suggestion) => (
<li key={suggestion} onClick={this.onClick}>
{suggestion}
</li>
))}
</ul>
);
}
return (
<>
<input
type='text'
onChange={this.onChange}
value={this.state.input}
placeholder={this.props.placeholder || ''}
autoComplete='off'
id={this.props.id || ''} />
<input type='text' onChange={this.onChange} value={this.state.input} placeholder={this.props.placeholder || ''} autoComplete='off' id={this.props.id || ''} />
{autocomplete}
</>
);

View File

@@ -0,0 +1,15 @@
import variables from 'modules/variables';
import './preview.scss';
export default function Preview(props) {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<div className='preview-mode'>
<h1>{getMessage('modals.main.settings.reminder.title')}</h1>
<p>{getMessage('modals.welcome.preview.description')}</p>
<button className='pinNote' onClick={() => props.setup()}>{getMessage('modals.welcome.preview.continue')}</button>
</div>
);
}

View File

@@ -0,0 +1,17 @@
.preview-mode {
position: absolute;
bottom: 20px;
right: 20px;
padding: 15px;
color: var(--modal-text);
background: var(--background);
max-width: 300px;
border-radius: .7em;
z-index: 999;
text-align: left;
cursor: default;
h1 {
font-size: 1rem;
}
}

View File

@@ -1,10 +1,10 @@
import './tooltip.scss';
export default function Tooltip(props) {
export default function Tooltip({ children, title }) {
return (
<div className='tooltip'>
{props.children}
<span className='tooltipTitle'>{props.title}</span>
{children}
<span className='tooltipTitle'>{title}</span>
</div>
);
}

View File

@@ -6,7 +6,7 @@
.tooltipTitle {
min-width: 60px;
background-color: rgba(255, 255, 255, 0.89);
color: #000000;
color: #000;
text-align: center;
font-size: 0.6rem;
border-radius: 6px;
@@ -33,5 +33,5 @@
.dark .tooltipTitle {
background-color: rgba(0, 0, 0, 0.79);
color: #ffffff;
color: #fff;
}

View File

@@ -1,5 +1,6 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { ErrorOutline } from '@material-ui/icons';
import { MdErrorOutline } from 'react-icons/md';
export default class ErrorBoundary extends PureComponent {
constructor(props) {
@@ -7,12 +8,11 @@ export default class ErrorBoundary extends PureComponent {
this.state = {
error: false
};
this.language = window.language.modals.main.error_boundary;
}
static getDerivedStateFromError(error) {
console.log(error);
window.stats.postEvent('modal', 'Error occurred');
variables.stats.postEvent('modal', 'Error occurred');
return {
error: true
};
@@ -23,10 +23,10 @@ export default class ErrorBoundary extends PureComponent {
return (
<div className='emptyitems'>
<div className='emptyMessage'>
<ErrorOutline/>
<h1>{this.language.title}</h1>
<p>{this.language.message}</p>
<button className='refresh' onClick={() => window.location.reload()}>{this.language.refresh}</button>
<MdErrorOutline/>
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.title')}</h1>
<p>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.message')}</p>
<button className='refresh' onClick={() => window.location.reload()}>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.refresh')}</button>
</div>
</div>
);

View File

@@ -1,16 +1,15 @@
import { PureComponent, Suspense, lazy } from 'react';
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Modal from 'react-modal';
//import Hotkeys from 'react-hot-keys';
import Main from './main/Main';
import Feedback from './feedback/Feedback';
import Navbar from '../widgets/navbar/Navbar';
import Preview from '../helpers/preview/Preview';
import EventBus from '../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
// Welcome modal is lazy loaded as the user won't use it every time they open a tab
// We used to lazy load the main and feedback modals, but doing so broke the modal open animation on first click
const Welcome = lazy(() => import('./welcome/Welcome'));
const renderLoader = () => <></>;
import Welcome from './welcome/Welcome';
export default class Modals extends PureComponent {
constructor() {
@@ -19,7 +18,7 @@ export default class Modals extends PureComponent {
mainModal: false,
updateModal: false,
welcomeModal: false,
feedbackModal: false
preview: false
};
}
@@ -28,7 +27,15 @@ export default class Modals extends PureComponent {
this.setState({
welcomeModal: true
});
window.stats.postEvent('modal', 'Opened welcome');
variables.stats.postEvent('modal', 'Opened welcome');
}
if (window.location.search === '?nointro=true') {
if (localStorage.getItem('showWelcome') === 'true') {
localStorage.setItem('showWelcome', false);
EventBus.dispatch('refresh', 'widgets');
EventBus.dispatch('refresh', 'backgroundwelcome');
}
}
// hide refresh reminder once the user has refreshed the page
@@ -40,17 +47,28 @@ export default class Modals extends PureComponent {
this.setState({
welcomeModal: false
});
EventBus.dispatch('refresh', 'widgetsWelcomeDone');
EventBus.dispatch('refresh', 'widgets');
EventBus.dispatch('refresh', 'backgroundwelcome');
}
previewWelcome() {
localStorage.setItem('showWelcome', false);
localStorage.setItem('welcomePreview', true);
this.setState({
welcomeModal: false,
preview: true
});
EventBus.dispatch('refresh', 'widgetsWelcome');
}
toggleModal(type, action) {
this.setState({
[type]: action
});
if (action !== false) {
window.stats.postEvent('modal', `Opened ${type.replace('Modal', '')}`);
variables.stats.postEvent('modal', `Opened ${type.replace('Modal', '')}`);
}
}
@@ -61,14 +79,11 @@ export default class Modals extends PureComponent {
<Modal closeTimeoutMS={300} id='modal' onRequestClose={() => this.toggleModal('mainModal', false)} isOpen={this.state.mainModal} className='Modal mainModal' overlayClassName='Overlay' ariaHideApp={false}>
<Main modalClose={() => this.toggleModal('mainModal', false)}/>
</Modal>
<Suspense fallback={renderLoader()}>
<Modal closeTimeoutMS={300} onRequestClose={() => this.closeWelcome()} isOpen={this.state.welcomeModal} className='Modal welcomemodal mainModal' overlayClassName='Overlay welcomeoverlay' shouldCloseOnOverlayClick={false} ariaHideApp={false}>
<Welcome modalClose={() => this.closeWelcome()}/>
</Modal>
<Modal closeTimeoutMS={300} onRequestClose={() => this.toggleModal('feedbackModal', false)} isOpen={this.state.feedbackModal} className='Modal mainModal' overlayClassName='Overlay' ariaHideApp={false}>
<Feedback modalClose={() => this.toggleModal('feedbackModal', false)}/>
</Modal>
</Suspense>
<Modal closeTimeoutMS={300} onRequestClose={() => this.closeWelcome()} isOpen={this.state.welcomeModal} className='Modal welcomemodal mainModal' overlayClassName='Overlay welcomeoverlay' shouldCloseOnOverlayClick={false} ariaHideApp={false}>
<Welcome modalClose={() => this.closeWelcome()} modalSkip={() => this.previewWelcome()}/>
</Modal>
{this.state.preview ? <Preview setup={() => window.location.reload()}/> : null}
{/*variables.keybinds.toggleModal && variables.keybinds.toggleModal !== '' ? <Hotkeys keyName={variables.keybinds.toggleModal} onKeyDown={() => this.toggleModal('mainModal', (this.state.mainModal === true ? false : true))}/> : null*/}
</>
);
}

View File

@@ -1,93 +0,0 @@
import { PureComponent } from 'react';
import './feedback.scss';
export default class FeedbackModal extends PureComponent {
constructor() {
super();
this.state = {
questionone: 5,
questionthree: 5,
questiontwoerror: '',
questionfourerror: '',
formsubmit: ''
};
this.language = window.language.modals.feedback;
}
async submitForm () {
let questiontwoerror, questionfourerror;
if (document.getElementById('questiontwo').value.length <= 0) {
questiontwoerror = this.language.not_filled;
}
if (document.getElementById('questionfour').value.length <= 0) {
questionfourerror = this.language.not_filled;
}
if (questiontwoerror || questionfourerror) {
this.setState({
questiontwoerror: questiontwoerror,
questionfourerror: questionfourerror
});
} else {
this.setState({
questiontwoerror: '',
questionfourerror: ''
});
await fetch(window.constants.FEEDBACK_FORM, {
method: 'POST'
});
this.setState({
formsubmit: this.language.success
});
setTimeout(() => {
this.props.modalClose();
}, 5000);
}
}
render() {
return (
<div className='feedback'>
<h1>{this.language.title}</h1>
<span className='closeModal' onClick={this.props.modalClose}>&times;</span>
<>
<input type='hidden' name='version' value={window.constants.VERSION} />
<>
<label>{this.language.question_one}</label>
<br/><br/>
<label className='values'>0</label>
<input className='range' type='range' min='0' max='10' name='question1' value={this.state.questionone} onChange={(e) => this.setState({ questionone: e.target.value })}/>
<label className='values'>10 ({this.state.questionone})</label>
</>
<br/><br/>
<>
<label>{this.language.question_two}</label>
<textarea name='question2' id='questiontwo'/>
<p className='feedbackerror'>{this.state.questiontwoerror}</p>
</>
<>
<label>{this.language.question_three}</label>
<br/><br/>
<label className='values'>0</label>
<input className='range' type='range' min='0' max='10' name='question3' value={this.state.questionthree} onChange={(e) => this.setState({ questionthree: e.target.value })}/>
<label className='values'>10 ({this.state.questionthree})</label>
</>
<br/><br/>
<>
<label>{this.language.question_four}</label>
<textarea name='question4' id='questionfour'/>
<p className='feedbackerror'>{this.state.questionfourerror}</p>
</>
<p>{this.state.formsubmit}</p>
<button onClick={() => this.submitForm()}>{this.language.submit}</button>
</>
</div>
);
}
}

View File

@@ -1,68 +0,0 @@
@import '../main/scss/index.scss';
#feedbackmodal {
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 400px;
height: 100px;
}
.feedback {
width: 400px;
padding: 5px;
h1,
.closeModal {
font-size: 2.5em;
}
span {
font-size: 6em;
}
button {
width: 50%;
border-radius: 48px;
outline: none;
border: none;
padding: 15px 20px;
font-size: 1.5em;
background: #5352ed;
color: #fff;
text-transform: uppercase;
cursor: pointer;
&:hover {
background: rgba(83, 82, 237, 0.8);
}
}
input[type=text] {
width: 100%;
font-size: 1em;
}
input[type=range] {
margin-left: 20px;
margin-right: 20px;
vertical-align: middle;
}
label.values {
font-weight: 700;
}
textarea {
width: 80%;
padding: 10px;
background-color: var(--sidebar) !important;
}
.feedbackerror {
color: red;
}
}

View File

@@ -1,3 +1,4 @@
import variables from 'modules/variables';
import { Suspense, lazy } from 'react';
import Tabs from './tabs/backend/Tabs';
@@ -11,10 +12,10 @@ const Marketplace = lazy(() => import('./tabs/Marketplace'));
const renderLoader = () => (
<Tabs>
<div label={window.language.modals.main.loading}>
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.loading')}>
<div className='emptyitems'>
<div className='emptyMessage'>
<h1>{window.language.modals.main.loading}</h1>
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.loading')}</h1>
</div>
</div>
</div>
@@ -22,29 +23,34 @@ const renderLoader = () => (
</Tabs>
);
export default function MainModal(props) {
const language = window.language.modals.main.navbar;
export default function MainModal({ modalClose }) {
const display = (localStorage.getItem('showReminder') === 'true') ? 'block' : 'none';
return (
<>
<span className='closeModal' onClick={props.modalClose}>&times;</span>
<span className='closeModal' onClick={modalClose}>&times;</span>
<Tabs navbar={true}>
<div label={language.settings} name='settings'>
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.settings')} name='settings'>
<Suspense fallback={renderLoader()}>
<Settings/>
</Suspense>
</div>
<div label={language.addons} name='addons'>
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.addons')} name='addons'>
<Suspense fallback={renderLoader()}>
<Addons/>
</Suspense>
</div>
<div label={language.marketplace} name='marketplace'>
<div label={variables.language.getMessage(variables.languagecode, 'modals.main.navbar.marketplace')} name='marketplace'>
<Suspense fallback={renderLoader()}>
<Marketplace/>
</Suspense>
</div>
</Tabs>
<div className='reminder-info' style={{ display }}>
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.reminder.title')}</h1>
<p>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.reminder.message')}</p>
<button className='pinNote' onClick={() => window.location.reload()}>{variables.language.getMessage(variables.languagecode, 'modals.main.error_boundary.refresh')}</button>
</div>
</>
);
}

View File

@@ -1,19 +1,33 @@
import { PureComponent } from 'react';
import { ArrowBack } from '@material-ui/icons';
import variables from 'modules/variables';
import { PureComponent, Fragment } from 'react';
import { toast } from 'react-toastify';
import { MdArrowBack } from 'react-icons/md';
import Modal from 'react-modal';
import { install, uninstall } from 'modules/helpers/marketplace';
import Lightbox from './Lightbox';
export default class Item extends PureComponent {
constructor() {
super();
constructor(props) {
super(props);
this.state = {
showLightbox: false
showLightbox: false,
showUpdateButton: (this.props.addonInstalled === true && this.props.addonInstalledVersion !== this.props.data.version)
};
}
updateAddon() {
uninstall(this.props.data.type, this.props.data.display_name);
install(this.props.data.type, this.props.data);
toast(variables.language.getMessage(variables.languagecode, 'toasts.updated'));
this.setState({
showUpdateButton: false
});
}
render() {
const language = window.language.modals.main.marketplace.product;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
if (!this.props.data.display_name) {
return null;
@@ -24,35 +38,48 @@ export default class Item extends PureComponent {
warningHTML = (
<div className='productInformation'>
<ul>
<li className='header'>{language.quote_warning.title}</li>
<li id='updated'>{language.quote_warning.description}</li>
<li className='header'>{getMessage('modals.main.marketplace.product.quote_warning.title')}</li>
<li id='updated'>{getMessage('modals.main.marketplace.product.quote_warning.description')}</li>
</ul>
</div>
);
}
// prevent console error
let iconsrc = window.constants.DDG_IMAGE_PROXY + this.props.data.icon;
let iconsrc = variables.constants.DDG_IMAGE_PROXY + this.props.data.icon;
if (!this.props.data.icon) {
iconsrc = null;
}
let updateButton;
if (this.state.showUpdateButton) {
updateButton = (
<Fragment key='update'>
<br/><br/>
<button className='removeFromMue' onClick={() => this.updateAddon()}>
{getMessage('modals.main.addons.product.buttons.update_addon')}
</button>
</Fragment>
);
}
return (
<div id='item'>
<br/>
<ArrowBack className='backArrow' onClick={this.props.toggleFunction}/>
<MdArrowBack className='backArrow' onClick={this.props.toggleFunction}/>
<br/>
<h1>{this.props.data.display_name}</h1>
{this.props.button}
{updateButton}
<br/><br/>
{iconsrc ? <img alt='product' draggable='false' src={iconsrc} onClick={() => this.setState({ showLightbox: true })}/> : null}
<div className='side'>
<div className='productInformation'>
<ul>
<li className='header'>{language.version}</li>
<li>{this.props.data.version}</li>
<li className='header'>{getMessage('modals.main.marketplace.product.version')}</li>
{updateButton ? <li>{this.props.data.version} (Installed: {this.props.data.addonInstalledVersion})</li> : <li>{this.props.data.version}</li>}
<br/>
<li className='header'>{language.author}</li>
<li className='header'>{getMessage('modals.main.marketplace.product.author')}</li>
<li>{this.props.data.author}</li>
</ul>
</div>
@@ -63,7 +90,7 @@ export default class Item extends PureComponent {
<br/><br/>
</div>
<div className='informationContainer'>
<h1 className='overview'>{language.overview}</h1>
<h1 className='overview'>{getMessage('modals.main.marketplace.product.overview')}</h1>
<p className='description' dangerouslySetInnerHTML={{ __html: this.props.data.description }}></p>
</div>
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showLightbox: false })} isOpen={this.state.showLightbox} className='Modal lightboxmodal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>

View File

@@ -1,9 +1,11 @@
export default function Items(props) {
import variables from 'modules/variables';
export default function Items({ items, toggleFunction }) {
return (
<div className='items'>
{props.items.map((item) => (
<div className='item' onClick={() => props.toggleFunction(item.name)} key={item.name}>
<img alt='icon' draggable='false' src={window.constants.DDG_IMAGE_PROXY + item.icon_url} />
{items.map((item) => (
<div className='item' onClick={() => toggleFunction(item.name)} key={item.name}>
<img alt='icon' draggable='false' src={variables.constants.DDG_IMAGE_PROXY + item.icon_url} />
<div className='details'>
<h4>{item.display_name || item.name}</h4>
<p>{item.author}</p>

View File

@@ -1,10 +1,12 @@
export default function Lightbox(props) {
window.stats.postEvent('modal', 'Opened lightbox');
import variables from 'modules/variables';
export default function Lightbox({ modalClose, img }) {
variables.stats.postEvent('modal', 'Opened lightbox');
return (
<>
<span className='closeModal' onClick={props.modalClose}>&times;</span>
<img src={props.img} className='lightboximg' draggable={false} alt='Item screenshot'/>
<span className='closeModal' onClick={modalClose}>&times;</span>
<img src={img} className='lightboximg' draggable={false} alt='Item screenshot'/>
</>
);
}

View File

@@ -0,0 +1,20 @@
import variables from 'modules/variables';
import { MdClose } from 'react-icons/md';
export default function SideloadFailedModal({ modalClose, reason }) {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<h1>{getMessage('modals.main.error_boundary.title')}</h1>
<span>{getMessage('modals.main.addons.sideload.failed')}</span>
<br/><br/>
<span>{reason}</span>
<div className='resetfooter'>
<button className='round import' style={{ marginLeft: '-30px' }} onClick={modalClose}>
<MdClose/>
</button>
</div>
</>
);
}

View File

@@ -1,14 +1,17 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { LocalMall } from '@material-ui/icons';
import { MdLocalMall } from 'react-icons/md';
import { toast } from 'react-toastify';
import Item from '../Item';
import Items from '../Items';
import Dropdown from '../../settings/Dropdown';
import { uninstall, urlParser } from '../../../../../modules/helpers/marketplace';
import { uninstall, urlParser } from 'modules/helpers/marketplace';
export default class Added extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
@@ -17,9 +20,8 @@ export default class Added extends PureComponent {
button: ''
};
this.buttons = {
uninstall: <button className='removeFromMue' onClick={() => this.uninstall()}>{window.language.modals.main.marketplace.product.buttons.remove}</button>,
uninstall: <button className='removeFromMue' onClick={() => this.uninstall()}>{this.getMessage('modals.main.marketplace.product.buttons.remove')}</button>,
};
this.language = window.language.modals.main.addons;
}
toggle(type, data) {
@@ -41,7 +43,7 @@ export default class Added extends PureComponent {
},
button: this.buttons.uninstall
});
window.stats.postEvent('marketplace', 'Item viewed');
variables.stats.postEvent('marketplace', 'Item viewed');
} else {
this.setState({
item: {}
@@ -52,14 +54,14 @@ export default class Added extends PureComponent {
uninstall() {
uninstall(this.state.item.type, this.state.item.display_name);
toast(window.language.toasts.uninstalled);
toast(this.getMessage('toasts.uninstalled'));
this.setState({
button: '',
installed: JSON.parse(localStorage.getItem('installed'))
});
window.stats.postEvent('marketplace', 'Uninstall');
variables.stats.postEvent('marketplace', 'Uninstall');
}
sortAddons(value, sendEvent) {
@@ -86,7 +88,25 @@ export default class Added extends PureComponent {
});
if (sendEvent) {
window.stats.postEvent('marketplace', 'Sort');
variables.stats.postEvent('marketplace', 'Sort');
}
}
updateCheck() {
let updates = 0;
this.state.installed.forEach(async (item) => {
const data = await (await fetch(variables.constants.MARKETPLACE_URL + '/item/' + item.name)).json();
if (data.version !== item.version) {
updates++;
}
});
if (updates > 0) {
toast(this.getMessage('modals.main.addons.updates_available', {
amount: updates
}));
} else {
toast(this.getMessage('modals.main.addons.no_updates'));
}
}
@@ -99,9 +119,9 @@ export default class Added extends PureComponent {
return (
<div className='emptyitems'>
<div className='emptyMessage'>
<LocalMall/>
<h1>{this.language.empty.title}</h1>
<p className='description'>{this.language.empty.description}</p>
<MdLocalMall/>
<h1>{this.getMessage('modals.main.addons.empty.title')}</h1>
<p className='description'>{this.getMessage('modals.main.addons.empty.description')}</p>
</div>
</div>
);
@@ -113,12 +133,13 @@ export default class Added extends PureComponent {
return (
<>
<Dropdown label={this.language.sort.title} name='sortAddons' onChange={(value) => this.sortAddons(value)}>
<option value='newest'>{this.language.sort.newest}</option>
<option value='oldest'>{this.language.sort.oldest}</option>
<option value='a-z'>{this.language.sort.a_z}</option>
<option value='z-a'>{this.language.sort.z_a}</option>
<Dropdown label={this.getMessage('modals.main.addons.sort.title')} name='sortAddons' onChange={(value) => this.sortAddons(value)}>
<option value='newest'>{this.getMessage('modals.main.addons.sort.newest')}</option>
<option value='oldest'>{this.getMessage('modals.main.addons.sort.oldest')}</option>
<option value='a-z'>{this.getMessage('modals.main.addons.sort.a_z')}</option>
<option value='z-a'>{this.getMessage('modals.main.addons.sort.z_a')}</option>
</Dropdown>
<button className='addToMue sideload updateCheck' onClick={() => this.updateCheck()}>{this.getMessage('modals.main.addons.check_updates')}</button>
<br/>
<Items items={this.state.installed} toggleFunction={(input) => this.toggle('item', input)} />
</>

View File

@@ -1,15 +1,19 @@
/* eslint-disable no-unused-vars */
import variables from 'modules/variables';
import { PureComponent } from 'react';
import {
SettingsRounded as Settings,
PhotoOutlined as Photos,
FormatQuoteOutlined as Quotes
} from '@material-ui/icons';
import {
MdSettings as Settings,
MdOutlineInsertPhoto as Photos,
MdOutlineFormatQuote as Quotes,
MdUpload as ImportIcon,
MdDownload as ExportIcon
} from 'react-icons/md';
import { TextField } from '@mui/material';
import { toast } from 'react-toastify';
import { saveFile } from '../../../../../modules/helpers/settings/modals';
import { saveFile } from 'modules/helpers/settings/modals';
import FileUpload from '../../settings/FileUpload';
import Dropdown from '../../settings/Dropdown';
import '../../../welcome/welcome.scss';
@@ -54,7 +58,8 @@ export default class Create extends PureComponent {
const data = input || localStorage;
let settings = {};
Object.keys(data).forEach((key) => {
if (key === 'statsData' || key === 'firstRun' || key === 'showWelcome' || key === 'language' || key === 'installed' || key === 'stats') {
if (key === 'statsData' || key === 'firstRun' || key === 'showWelcome' || key === 'language' || key === 'installed' || key === 'stats' || key === 'backup_settings' || key === 'showReminder'
|| key === 'experimental' || key === 'debugtimeout' || key === 'quotelanguage') {
return;
}
settings[key] = localStorage.getItem(key);
@@ -63,19 +68,95 @@ export default class Create extends PureComponent {
this.setState({
addonData: settings,
settingsClasses: {
current: input ? 'toggle lightTheme' : 'toggle lightTheme active',
current: input ? 'toggle lightTheme active' : 'toggle lightTheme',
json: input ? 'toggle lightTheme active' : 'toggle lightTheme'
}
});
toast('Imported settings!');
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
}
updateQuotePackType(type) {
if (type === 'quotePack') {
this.setState({
addonMetadata: {
type,
name: this.state.addonMetadata.name,
description: this.state.addonMetadata.description,
version: this.state.addonMetadata.version,
author: this.state.addonMetadata.author,
icon_url: this.state.addonMetadata.icon_url,
screenshot_url: this.state.addonMetadata.screenshot_url,
quotes: []
}
});
} else {
this.setState({
addonMetadata: {
type,
name: this.state.addonMetadata.name,
description: this.state.addonMetadata.description,
version: this.state.addonMetadata.version,
author: this.state.addonMetadata.author,
icon_url: this.state.addonMetadata.icon_url,
screenshot_url: this.state.addonMetadata.screenshot_url
},
addonData: {
url: '',
name: '',
author: ''
}
});
}
}
updateQuotePackAPI(type, data) {
this.setState({
addonData: {
url: (type === 'url') ? data : this.state.addonData.url || '',
name: (type === 'name') ? data : this.state.addonData.name || '',
author: (type === 'author') ? data : this.state.addonData.author || '',
}
});
}
importQuotes() {
this.setState({
addonData: JSON.parse(localStorage.getItem('customQuote')) || []
});
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
}
importPhotos() {
let data = [];
try {
const current = JSON.parse(localStorage.getItem('customBackground')) || [];
data = current.map((item) => {
return {
photographer: '???',
location: '???',
url: {
default: item
}
}
});
toast(variables.language.getMessage(variables.languagecode, 'toasts.imported'));
} catch (e) {
console.log(e);
toast(variables.language.getMessage(variables.languagecode, 'toasts.error'));
}
this.setState({
addonData: data
});
}
downloadAddon() {
saveFile({
name: this.state.addonMetadata.name,
description: this.state.addonMetadata.description,
type: this.state.addonMetadata.type,
type: (this.state.addonMetadata.type === 'quote_api') ? 'quotes' : this.state.addonMetadata.type,
version: this.state.addonMetadata.version,
author: this.state.addonMetadata.author,
icon_url: this.state.addonMetadata.icon_url,
@@ -87,27 +168,24 @@ export default class Create extends PureComponent {
render() {
let tabContent;
const { time } = window.language.modals.main.settings.sections;
const { marketplace, addons } = window.language.modals.main;
const { welcome } = window.language.modals;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const chooseType = (
<>
<h3>{time.type}</h3>
<h3>{getMessage('modals.main.settings.sections.time.type')}</h3>
<div className='themesToggleArea'>
<div className='options'>
{/* <div className='toggle lightTheme' onClick={() => this.changeTab(2, 'photos')}>
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'photos')}>
<Photos/>
<span>{marketplace.photo_packs}</span>
<span>{getMessage('modals.main.marketplace.photo_packs')}</span>
</div>
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'quotes')}>
<Quotes/>
<span>{marketplace.quote_packs}</span>
<span>{getMessage('modals.main.marketplace.quote_packs')}</span>
</div>
*/}
<div className='toggle lightTheme' onClick={() => this.changeTab(2, 'settings')}>
<Settings/>
<span>{marketplace.preset_settings}</span>
<span>{getMessage('modals.main.marketplace.preset_settings')}</span>
</div>
</div>
</div>
@@ -133,26 +211,20 @@ export default class Create extends PureComponent {
type: this.state.addonMetadata.type
}
});
}
};
const writeDescription = (
<>
<h3>{marketplace.product.information}</h3>
<p>{addons.create.metadata.name}</p>
<input type='text' value={this.state.addonMetadata.name} onInput={(e) => setMetadata(e.target.value, 'name')}/>
<p>{marketplace.product.version}</p>
<input type='text' value={this.state.addonMetadata.version} onInput={(e) => setMetadata(e.target.value, 'version')}/>
<p>{marketplace.product.author}</p>
<input type='text' value={this.state.addonMetadata.author} onInput={(e) => setMetadata(e.target.value, 'author')}/>
<p>{addons.create.metadata.icon_url}</p>
<input type='text' value={this.state.addonMetadata.icon_url} onInput={(e) => setMetadata(e.target.value, 'icon_url')}/>
<p>{addons.create.metadata.screenshot_url}</p>
<input type='text' value={this.state.addonMetadata.screenshot_url} onInput={(e) => setMetadata(e.target.value, 'screenshot_url')}/>
<p>{addons.create.metadata.description}</p>
<textarea className='settingsTextarea' value={this.state.addonMetadata.description} onInput={(e) => setMetadata(e.target.value, 'description')}></textarea>
<h3>{getMessage('modals.main.marketplace.product.information')}</h3>
<TextField label={getMessage('modals.main.addons.create.metadata.name')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.name} onInput={(e) => setMetadata(e.target.value, 'name')}/>
<TextField label={getMessage('modals.main.marketplace.product.version')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.version} onInput={(e) => setMetadata(e.target.value, 'version')}/>
<TextField label={getMessage('modals.main.marketplace.product.author')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.author} onInput={(e) => setMetadata(e.target.value, 'author')}/>
<TextField label={getMessage('modals.main.addons.create.metadata.icon_url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.icon_url} onInput={(e) => setMetadata(e.target.value, 'icon_url')}/>
<TextField label={getMessage('modals.main.addons.create.metadata.screenshot_url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonMetadata.screenshot_url} onInput={(e) => setMetadata(e.target.value, 'screenshot_url')}/>
<TextField label={getMessage('modals.main.addons.create.metadata.description')} varient='outlined' InputLabelProps={{ shrink: true }} multiline spellCheck={false} rows={4} value={this.state.addonMetadata.description} onInput={(e) => setMetadata(e.target.value, 'description')}/>
<br/>
<button onClick={() => this.changeTab(1)} className='uploadbg' style={{ marginRight: '10px' }}>{welcome.buttons.previous}</button>
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg' disabled={nextDescriptionDisabled}>{welcome.buttons.next}</button>
<button onClick={() => this.changeTab(1)} className='uploadbg' style={{ marginRight: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg' disabled={nextDescriptionDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
</>
);
@@ -160,44 +232,88 @@ export default class Create extends PureComponent {
const nextSettingsDisabled = (this.state.addonData === '') ? true : false;
const importSettings = (
<>
<h3>{welcome.sections.settings.title}</h3>
<div className='themesToggleArea'>
<div className='options'>
<h3>{getMessage('modals.welcome.sections.settings.title')}</h3>
<div className='themesToggleArea' >
<div className='options' style={{ maxWidth: '512px' }}>
<div className={this.state.settingsClasses.current} onClick={() => this.importSettings()}>
<span>{addons.create.settings.current}</span>
<ExportIcon/>
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
</div>
<div className={this.state.settingsClasses.json} onClick={() => document.getElementById('file-input').click()}>
<span>{addons.create.settings.json}</span>
<ImportIcon/>
<span>{getMessage('modals.main.addons.create.settings.json')}</span>
</div>
</div>
</div>
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => this.importSettings(JSON.parse(e.target.result))} />
<br/><br/>
<button onClick={() => this.changeTab(2)} className='uploadbg' style={{ marginRight: '10px' }}>{welcome.buttons.previous}</button>
<button onClick={() => this.changeTab(3)} className='uploadbg' disabled={nextSettingsDisabled}>{welcome.buttons.next}</button>
<button onClick={() => this.changeTab(2)} className='uploadbg' style={{ margin: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextSettingsDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
</>
);
// quotes
const nextQuotesDisabled = ((this.state.addonMetadata.type === 'quote_api' && this.state.addonData.url !== '' && this.state.addonData.name !== '' && this.state.addonData.author !== '')
|| (this.state.addonMetadata.type === 'quotes' && this.state.addonData.quotes !== '')) ? false : true;
const addQuotes = (
<>
<h3>{addons.create.quotes.title}</h3>
<h3>{getMessage('modals.main.addons.create.quotes.title')}</h3>
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} noSetting onChange={(e) => this.updateQuotePackType(e)}>
<option value='quotes'>{getMessage('modals.main.addons.create.quotes.local.title')}</option>
<option value='quote_api'>{getMessage('modals.main.addons.create.quotes.api.title')}</option>
</Dropdown>
{this.state.addonMetadata.type === 'quote_api' ? <>
<TextField label={getMessage('modals.main.addons.create.quotes.api.url')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.url} onInput={(e) => this.updateQuotePack(e.target.value, 'url')}/>
<TextField label={getMessage('modals.main.addons.create.quotes.api.name')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.name} onInput={(e) => this.updateQuotePack(e.target.value, 'name')}/>
<TextField label={getMessage('modals.main.addons.create.quotes.api.author')} varient='outlined' InputLabelProps={{ shrink: true }} value={this.state.addonData.author} onInput={(e) => this.updateQuotePack(e.target.value, 'author')}/>
<br/><br/>
</> : <>
<div className='themesToggleArea'>
<div className='options'>
<div onClick={() => this.importQuotes()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
<ExportIcon/>
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
</div>
</div>
</div>
<br/>
</>}
<button onClick={() => this.changeTab(2)} className='uploadbg'>{getMessage('modals.welcome.buttons.previous')}</button>
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextQuotesDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
</>
);
// photos
const nextPhotosDisabled = (this.state.addonData.photos !== '' && this.state.addonData.photos !== []) ? false : true;
const addPhotos = (
<>
<h3>{addons.create.photos.title}</h3>
<h3>{getMessage('modals.main.addons.create.photos.title')}</h3>
<div className='themesToggleArea'>
<div className='options'>
<div onClick={() => this.importPhotos()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
<ExportIcon/>
<span>{getMessage('modals.main.addons.create.settings.current')}</span>
</div>
</div>
</div>
<br/>
<button onClick={() => this.changeTab(2)} className='uploadbg'>{getMessage('modals.welcome.buttons.previous')}</button>
<button onClick={() => this.changeTab(3)} className='uploadbg' style={{ margin: '10px' }} disabled={nextPhotosDisabled}>{getMessage('modals.welcome.buttons.next')}</button>
</>
);
const downloadAddon = (
<>
<h3>{addons.create.finish.title}</h3>
<button onClick={() => this.downloadAddon()} className='upload'>{addons.create.finish.download}</button>
<br/><br/>
<button onClick={() => this.changeTab(this.state.addonMetadata.type)} className='uploadbg' style={{ marginRight: '10px' }}>{welcome.buttons.previous}</button>
<div className='themesToggleArea'>
<div className='options'>
<div onClick={() => this.downloadAddon()} className='toggle lightTheme' style={{ width: '60%', margin: '10px 0 10px 0' }}>
<ExportIcon/>
<span>{getMessage('modals.main.addons.create.finish.download')}</span>
</div>
</div>
</div>
<br/>
<button onClick={() => this.changeTab((this.state.addonMetadata.type === 'quote_api') ? 'quotes' : this.state.addonMetadata.type)} className='uploadbg' style={{ marginRight: '10px' }}>{getMessage('modals.welcome.buttons.previous')}</button>
</>
);
@@ -212,7 +328,7 @@ export default class Create extends PureComponent {
return (
<>
<h2>{addons.create.other_title}</h2>
<h2>{getMessage('modals.main.addons.create.other_title')}</h2>
{tabContent}
</>
);

View File

@@ -1,14 +1,17 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { WifiOff, LocalMall } from '@material-ui/icons';
import { MdWifiOff, MdLocalMall } from 'react-icons/md';
import Item from '../Item';
import Items from '../Items';
import Dropdown from '../../settings/Dropdown';
import { install, urlParser, uninstall } from '../../../../../modules/helpers/marketplace';
import { install, urlParser, uninstall } from 'modules/helpers/marketplace';
export default class Marketplace extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
@@ -19,10 +22,9 @@ export default class Marketplace extends PureComponent {
item: {}
};
this.buttons = {
uninstall: <button className='removeFromMue' onClick={() => this.manage('uninstall')}>{window.language.modals.main.marketplace.product.buttons.remove}</button>,
install: <button className='addToMue' onClick={() => this.manage('install')}>{window.language.modals.main.marketplace.product.buttons.addtomue}</button>
uninstall: <button className='removeFromMue' onClick={() => this.manage('uninstall')}>{this.getMessage('modals.main.marketplace.product.buttons.remove')}</button>,
install: <button className='addToMue' onClick={() => this.manage('install')}>{this.getMessage('modals.main.marketplace.product.buttons.addtomue')}</button>
};
this.language = window.language.modals.main.marketplace;
this.controller = new AbortController();
}
@@ -31,10 +33,10 @@ export default class Marketplace extends PureComponent {
let info;
// get item info
try {
info = await (await fetch(`${window.constants.MARKETPLACE_URL}/item/${this.props.type}/${data}`, { signal: this.controller.signal })).json();
info = await (await fetch(`${variables.constants.MARKETPLACE_URL}/item/${this.props.type}/${data}`, { signal: this.controller.signal })).json();
} catch (e) {
if (this.controller.signal.aborted === false) {
return toast(window.language.toasts.error);
return toast(this.getMessage('toasts.error'));
}
}
@@ -44,11 +46,20 @@ export default class Marketplace extends PureComponent {
// check if already installed
let button = this.buttons.install;
let addonInstalled = false;
let addonInstalledVersion;
const installed = JSON.parse(localStorage.getItem('installed'));
if (installed.some((item) => item.name === info.data.name)) {
button = this.buttons.uninstall;
addonInstalled = true;
for (let i = 0; i < installed.length; i++) {
if (installed[i].name === info.data.name) {
addonInstalledVersion = installed[i].version;
break;
}
}
}
this.setState({
@@ -60,12 +71,14 @@ export default class Marketplace extends PureComponent {
//updated: info.updated,
version: info.data.version,
icon: info.data.screenshot_url,
data: info.data
data: info.data,
addonInstalled,
addonInstalledVersion
},
button: button
});
window.stats.postEvent('marketplace-item', `${this.state.item.display_name} viewed`);
variables.stats.postEvent('marketplace-item', `${this.state.item.display_name} viewed`);
} else {
this.setState({
item: {}
@@ -74,8 +87,8 @@ export default class Marketplace extends PureComponent {
}
async getItems() {
const { data } = await (await fetch(window.constants.MARKETPLACE_URL + '/items/' + this.props.type, { signal: this.controller.signal })).json();
const featured = await (await fetch(window.constants.MARKETPLACE_URL + '/featured', { signal: this.controller.signal })).json();
const { data } = await (await fetch(variables.constants.MARKETPLACE_URL + '/items/' + this.props.type, { signal: this.controller.signal })).json();
const featured = await (await fetch(variables.constants.MARKETPLACE_URL + '/featured', { signal: this.controller.signal })).json();
if (this.controller.signal.aborted === true) {
return;
@@ -98,13 +111,13 @@ export default class Marketplace extends PureComponent {
uninstall(this.state.item.type, this.state.item.display_name);
}
toast(window.language.toasts[type + 'ed']);
toast(this.getMessage('toasts.' + type + 'ed'));
this.setState({
button: (type === 'install') ? this.buttons.uninstall : this.buttons.install
});
window.stats.postEvent('marketplace-item', `${this.state.item.display_name} ${(type === 'install' ? 'installed': 'uninstalled')}`);
window.stats.postEvent('marketplace', (type === 'install' ? 'Install': 'Uninstall'));
variables.stats.postEvent('marketplace-item', `${this.state.item.display_name} ${(type === 'install' ? 'installed': 'uninstalled')}`);
variables.stats.postEvent('marketplace', (type === 'install' ? 'Install': 'Uninstall'));
}
sortMarketplace(value, sendEvent) {
@@ -131,7 +144,7 @@ export default class Marketplace extends PureComponent {
});
if (sendEvent) {
window.stats.postEvent('marketplace', 'Sort');
variables.stats.postEvent('marketplace', 'Sort');
}
}
@@ -161,21 +174,21 @@ export default class Marketplace extends PureComponent {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
return errorMessage(<>
<WifiOff/>
<h1>{this.language.offline.title}</h1>
<p className='description'>{this.language.offline.description}</p>
<MdWifiOff/>
<h1>{this.getMessage('modals.main.marketplace.offline.title')}</h1>
<p className='description'>{this.getMessage('modals.main.marketplace.offline.description')}</p>
</>);
}
if (this.state.done === false) {
return errorMessage(<h1>{window.language.modals.main.loading}</h1>);
return errorMessage(<h1>{this.getMessage('modals.main.loading')}</h1>);
}
const featured = () => {
const openFeatured = () => {
window.stats.postEvent('marketplace', 'Featured clicked');
variables.stats.postEvent('marketplace', 'Featured clicked');
window.open(this.state.featured.buttonLink);
}
};
return (
<div className='featured' style={{ backgroundColor: this.state.featured.colour }}>
@@ -191,27 +204,26 @@ export default class Marketplace extends PureComponent {
<>
{featured()}
{errorMessage(<>
<LocalMall/>
<h1>{window.language.modals.main.addons.empty.title}</h1>
<p className='description'>{this.language.no_items}</p>
<MdLocalMall/>
<h1>{this.getMessage('modals.main.addons.empty.title')}</h1>
<p className='description'>{this.getMessage('modals.main.marketplace.no_items')}</p>
</>)}
</>
);
}
if (this.state.item.display_name) {
return <Item data={this.state.item} button={this.state.button} toggleFunction={() => this.toggle()}/>;
return <Item data={this.state.item} button={this.state.button} toggleFunction={() => this.toggle()} addonInstalled={this.state.item.addonInstalled} addonInstalledVersion={this.state.item.addonInstalledVersion}/>;
}
return (
<>
{featured()}
<br/>
<Dropdown label={window.language.modals.main.addons.sort.title} name='sortMarketplace' onChange={(value) => this.sortMarketplace(value)}>
<option value='a-z'>{window.language.modals.main.addons.sort.a_z}</option>
<option value='z-a'>{window.language.modals.main.addons.sort.z_a}</option>
<Dropdown label={this.getMessage('modals.main.addons.sort.title')} name='sortMarketplace' onChange={(value) => this.sortMarketplace(value)}>
<option value='a-z'>{this.getMessage('modals.main.addons.sort.a_z')}</option>
<option value='z-a'>{this.getMessage('modals.main.addons.sort.z_a')}</option>
</Dropdown>
<br/>
<Items items={this.state.items} toggleFunction={(input) => this.toggle('item', input)} />
</>
);

View File

@@ -1,25 +1,67 @@
import { LocalMall } from '@material-ui/icons';
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { MdIntegrationInstructions } from 'react-icons/md';
import { toast } from 'react-toastify';
import Modal from 'react-modal';
import SideloadFailedModal from '../SideloadFailedModal';
import FileUpload from '../../settings/FileUpload';
import { install } from '../../../../../modules/helpers/marketplace';
import { install } from 'modules/helpers/marketplace';
export default class Sideload extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor(props) {
super(props);
this.state = {
showFailed: false,
failedReason: ''
}
}
installAddon(input) {
let failedReason = '';
if (!input.name) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_name');
} else if (!input.author) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_author');
} else if (!input.type) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_type');
} else if (!input.version) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.no_version');
} else if (input.type === 'photos' && (!input.photos || !input.photos.length || !input.photos[0].url || !input.photos[0].url.default || !input.photos[0].photographer || !input.photos[0].location)) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.invalid_photos');
} else if (input.type === 'quotes' && (!input.quotes || !input.quotes.length || !input.quotes[0].quote || !input.quotes[0].author)) {
failedReason = this.getMessage('modals.main.addons.sideload.errors.invalid_quotes');
}
if (failedReason !== '') {
return this.setState({
failedReason,
showFailed: true
});
}
export default function Sideload() {
const installAddon = (input) => {
install(input.type, input);
toast(window.language.toasts.installed);
window.stats.postEvent('marketplace', 'Sideload');
};
return (
<div className='emptyitems'>
<div className='emptyMessage'>
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => installAddon(JSON.parse(e.target.result))} />
<LocalMall/>
<h1>{window.language.modals.main.addons.sideload}</h1>
<button className='addToMue sideload' onClick={() => document.getElementById('file-input').click()}>{window.language.modals.main.settings.sections.background.source.upload}</button>
toast(this.getMessage('toasts.installed'));
variables.stats.postEvent('marketplace', 'Sideload');
}
render() {
return (
<div className='emptyitems'>
<div className='emptyMessage'>
<FileUpload id='file-input' type='settings' accept='application/json' loadFunction={(e) => this.installAddon(JSON.parse(e.target.result))} />
<MdIntegrationInstructions />
<h1>{this.getMessage('modals.main.addons.sideload.title')}</h1>
<button className='addToMue sideload' onClick={() => document.getElementById('file-input').click()}>{this.getMessage('modals.main.settings.sections.background.source.upload')}</button>
</div>
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showFailed: false })} isOpen={this.state.showFailed} className='Modal resetmodal mainModal sideloadModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
<SideloadFailedModal modalClose={() => this.setState({ showFailed: false })} reason={this.state.failedReason}/>
</Modal>
</div>
</div>
);
);
}
}

View File

@@ -1,12 +1,15 @@
@import '../../../../scss/variables';
@import 'modules/sidebar';
@import 'modules/navbar';
@import 'modules/tab-content';
@import 'modules/links';
@import 'modules/scrollbars';
@import 'settings/main';
@import 'settings/buttons';
@import 'settings/dropdown';
@import 'settings/daypicker';
@import 'marketplace/main';
@import 'marketplace/buttons';
.Modal {
color: var(--modal-text);
@@ -27,36 +30,6 @@
}
}
.mainModal {
padding: 25px;
}
.resetLink {
color: var(--modal-link);
cursor: pointer;
&:hover {
opacity: 0.8;
}
span {
font-size: 1.2rem;
color: var(--modal-link);
vertical-align: text-bottom;
margin-left: 5px;
}
}
.modalLink {
color: var(--modal-link);
cursor: pointer;
margin-left: 5px;
&:hover {
opacity: 0.8;
}
}
.closeModal {
position: absolute;
top: 1rem;
@@ -93,11 +66,11 @@
overflow-y: auto;
position: relative;
// animation
transform: scale(0);
transition: all 300ms cubic-bezier(0.47, 1.64, 0.41, 0.8);
}
/* modal transition */
.ReactModal__Content--after-open {
opacity: 1;
transform: scale(1);
@@ -115,61 +88,9 @@
}
}
ul.sidebar {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding-left: 0;
background: var(--sidebar);
border-radius: 12px 0 0 12px;
text-align: left;
font-size: 24px;
min-height: 100vh;
h1 {
text-align: center;
font-size: 1.8em;
}
svg {
vertical-align: middle;
padding: 5px;
}
hr {
height: 3px;
background: rgba(196, 196, 196, 0.74);
width: 75%;
outline: none;
border: none;
}
}
@media (max-height: 999px) and (min-height: 920px) {
ul.sidebar {
min-height: 160vh;
}
}
@media (max-height: 919px) and (min-height: 700px) {
ul.sidebar {
min-height: 200vh;
}
}
@media (max-height: 699px) and (min-height: 400px) {
ul.sidebar {
min-height: 260vh;
}
}
li {
list-style: none;
font-size: 24px;
padding: 5px 30px 5px 30px;
cursor: pointer;
margin-top: 2px;
/* main modal */
.mainModal {
padding: 25px;
}
#modal {
@@ -189,224 +110,7 @@ li {
}
}
.tab-list-active {
background: var(--tab-active);
}
@media only screen and (max-width: 1200px) {
li.tab-list-item {
span {
display: none;
}
}
ul.sidebar {
h1 {
display: none;
}
}
}
.tab-list-item {
&:hover {
background: var(--tab-active);
}
}
.tab-content {
position: absolute;
h3 {
text-transform: uppercase;
}
}
@media only screen and (min-width: 2300px) {
.tab-content {
left: 350px;
top: 7%;
}
}
@media only screen and (max-width: 1920px) {
.tab-content {
left: 120px;
top: 50px;
}
}
@media only screen and (min-width: 1920px) {
.tab-content {
left: 350px;
top: 7%;
}
}
@media only screen and (max-width: 1400px), (min-width: 1400px) {
.tab-content {
left: 350px;
top: 75px;
}
}
@media only screen and (max-width: 1200px) {
.tab-content {
left: 125px;
top: 75px;
}
}
.navbar-item {
font-size: 22px;
font-weight: 500;
display: inline-flex;
&:hover {
color: grey;
background: none;
}
span,
svg {
font-size: 1.1em !important;
}
svg {
font-size: 1.2em !important;
}
}
@supports (-webkit-hyphens: none) {
.navbar-item {
display: inline-block !important;
}
}
.modalNavbar {
position: absolute;
left: 20rem;
top: 1rem;
justify-content: center;
svg {
margin-right: 0.5rem;
padding: 3px;
vertical-align: middle;
}
}
@media only screen and (max-width: 1200px) {
.modalNavbar {
left: 6rem;
}
}
@media only screen and (max-width: 800px) {
li.navbar-item {
span {
display: none;
}
}
}
@media only screen and (min-width: 1200px) {
ul.sidebar {
width: 310px;
align-items: center;
}
}
.navbar-item-active {
background: map-get($theme-colours, 'gradient');
-webkit-background-clip: text;
background-clip: text;
color: transparent;
svg {
color: orange;
}
&:hover {
background: map-get($theme-colours, 'gradient');
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
}
::-webkit-scrollbar {
width: 6px;
height: 6px;
border-top-right-radius: map-get($modal, 'border-radius');
border-bottom-right-radius: map-get($modal, 'border-radius');
}
::-webkit-scrollbar-thumb {
background: #636e72;
border-top-right-radius: map-get($modal, 'border-radius');
border-bottom-right-radius: map-get($modal, 'border-radius');
}
.abouticon {
width: 96px;
height: auto;
border-radius: 50%;
padding-right: 5px;
}
.resetmodal {
min-height: 300px !important;
max-width: 300px !important;
margin: auto;
font-size: 1rem;
h4 {
cursor: initial;
font-size: 1.1rem;
}
}
.resetfooter {
position: absolute;
bottom: 20px;
width: 300px;
justify-content: center;
display: flex;
button.reset {
margin-right: 43px;
}
}
.resetoverlay {
background-color: rgba(0, 0, 0, 0.5);
}
.aboutIcon {
color: var(--modal-text) !important;
padding-right: 10px;
&:hover {
opacity: 0.8;
}
}
.aboutLink {
&:hover {
opacity: 0.8;
}
}
.aboutLogo {
height: 100px;
width: auto;
margin-left: -15px;
}
.MuiFormControl-root {
margin-top: 10px !important;
}
/* fixes for font size on extension */
label,
p,
span.modalLink {
@@ -414,7 +118,8 @@ span.modalLink {
}
h2 {
font-size: 1.5rem;
font-size: 2rem;
margin-bottom: 0;
}
h3 {
@@ -425,6 +130,12 @@ h5 {
font-size: 0.8rem;
}
.checkbox svg {
fill: var(--modal-text) !important;
}
.tab-content {
hr {
height: 5px;
background: rgba(196, 196, 196, 0.74);
outline: none;
border: none;
margin: 50px 0 30px 0;
}
}

View File

@@ -1,18 +1,7 @@
#item a {
color: var(--modal-link);
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
.emptyitems {
width: 25vw;
display: flex;
justify-content: center;
margin-top: 90px;
}
@import 'modules/item';
@import 'modules/buttons';
@import 'modules/featured';
@import 'modules/lightbox';
.items {
display: inline-grid;
@@ -25,11 +14,9 @@
height: 80px;
width: 260px;
background: var(--sidebar);
transition: 0.5s;
cursor: pointer;
margin-right: 20px;
margin-top: 20px;
box-shadow: 0 0 6px rgb(0 0 0 / 30%);
img {
height: 80px;
@@ -66,7 +53,7 @@
}
&:hover {
transform: scale(1.1);
background: var(--tab-active);
}
}
}
@@ -89,34 +76,11 @@
}
}
p.author {
margin-top: -5px;
}
#item {
h1 {
font-size: 40px;
line-height: 20px;
}
img {
float: left;
}
}
.side {
float: right;
margin-left: 20px;
}
#item>h1,
#item>.MuiSvgIcon-root {
display: inline;
}
p.description {
margin-top: 0px;
max-width: 800px;
.emptyitems {
width: 25vw;
display: flex;
justify-content: center;
margin-top: 90px;
}
.emptyMessage {
@@ -138,95 +102,28 @@ p.description {
}
}
.backArrow {
cursor: pointer;
width: 2rem !important;
height: 2rem !important;
&:hover {
color: grey;
}
p.author {
margin-top: -5px;
}
.informationContainer {
margin-top: 150px;
position: absolute;
}
.productInformation {
padding: 10px;
background: var(--sidebar);
width: 350px;
border-radius: 12px;
h4 {
cursor: initial !important;
}
li {
margin-left: -4px;
list-style: none;
font-size: 16px;
cursor: initial !important;
&.header {
text-transform: uppercase;
color: #787878;
margin-left: -5px;
}
}
}
#item>img, .updateimage, .updatechangelog>p>img {
#item>img,
.updateimage,
.updatechangelog>p>img {
border-radius: 12px;
height: 200px;
width: auto;
cursor: pointer;
}
.featured {
margin-top: 40px;
border-radius: 15px;
padding: 50px;
color: #fff;
box-shadow: 0 0 10px rgb(0 0 0 / 30%);
width: 85%;
button {
float: left;
margin-top: -7px;
border: 2px solid map-get($theme-colours, 'main');
color: map-get($theme-colours, 'main');
&:hover {
background: map-get($theme-colours, 'main');
color: #2d3436;
}
}
h1 {
margin-top: -20px;
font-size: 2rem;
}
/* sideload failed modal */
.sideloadModal {
min-width: 250px;
max-width: 250px;
overflow-x: hidden;
}
.lightboxmodal {
margin: auto;
max-width: 60%;
background: none !important;
box-shadow: none !important;
img {
height: auto;
width: 100%;
}
.closeModal {
color: #fff;
text-shadow: 0 0 20px rgb(0 0 0 / 30%);
@media (max-height: 1080px) {
.dropdownsortAddons {
margin-top: 40px !important;
}
}
.overview {
font-size: 30px !important;
}

View File

@@ -40,6 +40,7 @@
.addToMue {
@extend %storebutton;
float: right;
margin-top: -10px;
}
@@ -60,3 +61,7 @@ button.round {
vertical-align: middle;
padding: 10px;
}
.updateCheck {
margin-top: 15px;
}

View File

@@ -0,0 +1,25 @@
.featured {
margin-top: 40px;
border-radius: 15px;
padding: 50px;
color: #fff;
box-shadow: 0 0 10px rgb(0 0 0 / 30%);
width: 85%;
button {
float: left;
margin-top: -7px;
border: 2px solid map-get($theme-colours, 'main');
color: map-get($theme-colours, 'main');
&:hover {
background: map-get($theme-colours, 'main');
color: #2d3436;
}
}
h1 {
margin-top: -20px;
font-size: 2rem;
}
}

View File

@@ -0,0 +1,90 @@
#item {
h1 {
font-size: 40px;
line-height: 20px;
}
img {
float: left;
}
a {
color: var(--modal-link);
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
}
.side {
float: right;
margin-left: 20px;
}
#item>h1,
#item>svg {
display: inline;
}
p.description {
margin-top: 0px;
max-width: 800px;
}
.backArrow {
cursor: pointer;
width: 2rem !important;
height: 2rem !important;
&:hover {
color: grey;
}
}
.informationContainer {
margin-top: 150px;
position: absolute;
}
.productInformation {
padding: 10px;
background: var(--sidebar);
width: 350px;
border-radius: 12px;
min-height: 180px;
h4 {
cursor: initial !important;
}
li {
margin-left: -4px;
list-style: none;
font-size: 16px;
cursor: initial !important;
&.header {
text-transform: uppercase;
color: #787878;
margin-left: -5px;
}
}
}
@media only screen and (max-width: 1200px) {
.side {
margin-top: 222px;
float: none !important;
}
.overview {
margin-top: -160px !important;
}
}
.overview {
font-size: 30px !important;
margin-top: 33px;
}

View File

@@ -0,0 +1,16 @@
.lightboxmodal {
margin: auto;
max-width: 60%;
background: none !important;
box-shadow: none !important;
img {
height: auto;
width: 100%;
}
.closeModal {
color: #fff;
text-shadow: 0 0 20px rgb(0 0 0 / 30%);
}
}

View File

@@ -0,0 +1,25 @@
.resetLink {
color: var(--modal-link);
cursor: pointer;
&:hover {
opacity: 0.8;
}
span {
font-size: 1.2rem;
color: var(--modal-link);
vertical-align: text-bottom;
margin-left: 5px;
}
}
.modalLink {
color: var(--modal-link);
cursor: pointer;
margin-left: 5px;
&:hover {
opacity: 0.8;
}
}

View File

@@ -0,0 +1,72 @@
.navbar-item {
font-size: 22px;
font-weight: 500;
display: flex;
flex-direction: column;
align-items: center;
color: var(--photo-info);
&:hover {
svg {
background: var(--tab-active);
}
color: var(--modal-text)
}
span,
svg {
font-size: 1.1em !important;
}
svg {
font-size: 1.2em !important;
width: 60px;
padding: 5px;
border-radius: 20px;
color: var(--photo-info);
}
}
/* safari fix */
@supports (-webkit-hyphens: none) {
.navbar-item {
display: inline-block !important;
}
}
.modalNavbar {
position: absolute;
left: 20rem;
top: 1rem;
justify-content: center;
display: flex;
svg {
margin-right: 0.5rem;
padding: 3px;
vertical-align: middle;
}
}
@media only screen and (max-width: 1200px) {
.modalNavbar {
left: 6rem;
}
}
@media only screen and (max-width: 800px) {
li.navbar-item {
span {
display: none;
}
}
}
.navbar-item-active {
color: var(--modal-text);
svg {
background: var(--sidebar);
}
}

View File

@@ -0,0 +1,12 @@
::-webkit-scrollbar {
width: 6px;
height: 6px;
border-top-right-radius: map-get($modal, 'border-radius');
border-bottom-right-radius: map-get($modal, 'border-radius');
}
::-webkit-scrollbar-thumb {
background: #636e72;
border-top-right-radius: map-get($modal, 'border-radius');
border-bottom-right-radius: map-get($modal, 'border-radius');
}

View File

@@ -0,0 +1,87 @@
ul.sidebar {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding-left: 0;
background: var(--sidebar);
border-radius: 12px 0 0 12px;
text-align: left;
font-size: 24px;
min-height: 110vh;
h1 {
text-align: center;
font-size: 1.8em;
}
svg {
vertical-align: middle;
padding: 5px;
}
hr {
height: 3px;
background: rgba(196, 196, 196, 0.74);
width: 75%;
outline: none;
border: none;
}
}
@media (max-height: 999px) and (min-height: 920px) {
ul.sidebar {
min-height: 160vh;
}
}
@media (max-height: 919px) and (min-height: 700px) {
ul.sidebar {
min-height: 200vh;
}
}
@media (max-height: 699px) and (min-height: 400px) {
ul.sidebar {
min-height: 260vh;
}
}
@media only screen and (min-width: 1200px) {
ul.sidebar {
width: 310px;
align-items: center;
}
}
li {
list-style: none;
font-size: 24px;
padding: 5px 30px 5px 30px;
cursor: pointer;
margin-top: 2px;
}
.tab-list-active {
background: var(--tab-active);
}
@media only screen and (max-width: 1200px) {
li.tab-list-item {
span {
display: none;
}
}
ul.sidebar {
h1 {
display: none;
}
}
}
.tab-list-item {
&:hover {
background: var(--tab-active);
}
}

View File

@@ -0,0 +1,43 @@
.tab-content {
position: absolute;
h3 {
font-size: 1.5rem;
margin-bottom: 0;
}
}
@media only screen and (min-width: 2300px) {
.tab-content {
left: 350px;
top: 7%;
}
}
@media only screen and (max-width: 1920px) {
.tab-content {
left: 120px;
top: 60px;
}
}
@media only screen and (min-width: 1920px) {
.tab-content {
left: 350px;
top: 9%;
}
}
@media only screen and (max-width: 1400px),
(min-width: 1400px) {
.tab-content {
left: 350px;
}
}
@media only screen and (max-width: 1200px) {
.tab-content {
left: 125px;
top: 90px;
}
}

View File

@@ -24,7 +24,8 @@
}
}
.add {
.add,
.close {
@extend %settingsButton;
background-color: map-get($button-colours, 'other');
@@ -37,30 +38,39 @@
}
.close {
@extend %settingsButton;
padding: 10px 50px 10px 50px;
background-color: map-get($button-colours, 'other');
border: 2px solid map-get($button-colours, 'other');
&:hover {
color: map-get($button-colours, 'other');
border: 2px solid map-get($button-colours, 'other');
}
}
.export,
.uploadbg,
.import {
@extend %settingsButton;
background-color: map-get($button-colours, 'other');
color: map-get($theme-colours, 'primary');
border: 2px solid map-get($button-colours, 'other');
width: 440px;
height: 60px;
background-color: var(--sidebar);
border: none;
outline: none;
color: var(--modal-text);
border-radius: 12px;
margin-right: 25px;
width: 220px;
cursor: pointer;
border-radius: 24px;
border: 3px solid var(--tab-active);
font-size: 1rem;
&:hover {
color: map-get($button-colours, 'other');
border: 2px solid map-get($button-colours, 'other');
background-color: var(--tab-active);
}
&:disabled {
cursor: not-allowed;
background: none;
border: 1px solid var(--tab-active);
&:hover {
background: none;
border: 1px solid var(--tab-active);
}
}
}
@@ -69,32 +79,43 @@
margin-left: 20px;
}
.MuiIconButton-label > svg.MuiSvgIcon-root {
color: var(--modal-text) !important;
.round-small {
height: 10px !important;
width: 10px !important;
}
.sortableitem {
background: var(--sidebar) !important;
padding: 10px 80px;
padding-left: 10px;
border-radius: 15px;
margin-bottom: 10px;
font-size: 1.325rem;
color: var(--modal-text) !important;
cursor: move;
width: 150px;
z-index: 999 !important;
.data-buttons-row {
width: 350px;
display: flex;
flex-direction: row;
svg {
font-size: 1.3rem;
}
button {
background: var(--sidebar);
text-align: center;
border-radius: 20px;
padding: 20px;
border: 3px solid var(--tab-active);
height: 40px;
font-size: 1rem;
margin: 0 10px 10px 0;
display: flex;
flex-direction: column-reverse;
align-items: center;
color: var(--modal-text);
&:hover {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.15);
transition: 0.3s;
svg {
font-size: 2em;
}
&:hover {
background: var(--tab-active);
cursor: pointer;
}
}
}
.MuiTouchRipple-root {
background: transparent;
.customvideoicon {
position: absolute;
margin-bottom: 45px;
font-size: 3em !important;
}

View File

@@ -1,26 +0,0 @@
.DayPickerInput,
.input-container {
input {
width: 200px;
color: var(--modal-text) !important;
background: var(--sidebar);
border: none;
padding: 10px 10px;
border-radius: 5px;
}
}
.DayPicker-Day--selected {
background-color: #ff4757 !important;
color: white;
}
.DayPicker-Months,
.DayPickerInput-Overlay {
background-color: var(--background) !important;
color: var(--modal-text) !important;
}
.DayPicker:not(.DayPicker--interactionDisabled) .DayPicker-Day:not(.DayPicker-Day--disabled):not(.DayPicker-Day--selected):not(.DayPicker-Day--outside):hover {
color: black !important;
}

View File

@@ -1,37 +0,0 @@
select {
margin-left: 10px;
width: 120px;
color: var(--modal-text);
background: var(--sidebar);
border: none;
padding: 10px 10px;
border-radius: 5px;
}
// firefox dropdown
@supports (-moz-appearance: none) {
select {
-moz-appearance: none !important;
background: url("data:image/svg+xml;utf8,<svg fill='black' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>") right center no-repeat, var(--sidebar) !important;
}
.dark select {
background: url("data:image/svg+xml;utf8,<svg fill='white' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>") right center no-repeat, var(--sidebar) !important;
}
option {
font: -moz-pull-down-menu !important;
}
}
// safari dropdown
@supports (-webkit-hyphens: none) {
select {
-webkit-appearance: none !important;
background: url("data:image/svg+xml;utf8,<svg fill='black' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>") right center no-repeat, var(--sidebar) !important;
}
.dark select {
background: url("data:image/svg+xml;utf8,<svg fill='white' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>") right center no-repeat, var(--sidebar) !important;
}
}

View File

@@ -1,13 +1,13 @@
input {
&[type=text] {
width: 200px;
color: var(--modal-text);
background: var(--sidebar);
border: none;
padding: 10px 10px;
border-radius: 5px;
}
@import 'modules/resetmodal';
@import 'modules/material-ui';
@import 'modules/reminder';
@import 'modules/tabs/about';
@import 'modules/tabs/changelog';
@import 'modules/tabs/order';
input {
/* colour picker */
&[type=color] {
border-radius: 100%;
height: 30px;
@@ -28,6 +28,7 @@ input {
}
}
/* firefox fixes for colour picker (using "," didn't work) */
&[type=color]::-moz-color-swatch {
border-radius: 100%;
height: 30px;
@@ -48,16 +49,24 @@ input {
}
}
/* date picker */
&[type=date] {
width: 200px;
width: 280px;
color: var(--modal-text);
background: var(--sidebar);
border: none;
padding: 10px 10px;
border-radius: 5px;
background: var(--background);
border: solid var(--modal-text) 1px;
padding: 15px 20px;
border-radius: 4px;
display: flex !important;
cursor: pointer;
&::-webkit-calendar-picker-indicator {
cursor: pointer;
}
}
}
/* dark theme date picker fix */
.dark {
::-webkit-calendar-picker-indicator {
filter: invert(1);
@@ -68,170 +77,10 @@ h4 {
cursor: pointer;
}
ul {
padding-left: 0px;
margin: 0;
.keybind-table {
text-align: left;
>label {
vertical-align: middle;
}
}
.range {
-webkit-appearance: none;
width: 200px;
height: 12px;
border-radius: 12px;
outline: none;
background: var(--sidebar);
box-shadow: 0 0 100px rgba(0, 0, 0, 0.3);
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 12px;
background: var(--modal-text);
cursor: pointer;
}
&::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 12px;
border: 0;
background: var(--modal-text);
cursor: pointer;
}
}
.settingsTextarea {
font-family: Consolas !important;
padding: 15px;
border-radius: 15px;
background-color: var(--sidebar) !important;
border: none;
margin-left: 0;
width: 400px;
height: 200px;
max-width: 60%;
}
.MuiCheckbox-colorPrimary.Mui-checked,
.MuiSwitch-colorPrimary.Mui-checked,
.MuIconButton-colorPrimary.Mui-checked,
.MuiSwitch-thumb,
.MuiRadio-colorSecondary.Mui-checked,
.PrivateSwitchBase-input-4,
.MuiRadio-root,
.aboutLink,
legend {
color: var(--modal-text) !important;
}
.MuiFormControlLabel-labelPlacementStart {
margin-left: 0px !important;
}
.MuiSwitch-colorPrimary.Mui-checked+.MuiSwitch-track {
background: darkgray !important;
}
.reminder-info {
position: absolute;
bottom: 20px;
right: 20px;
padding: 15px;
color: var(--modal-text);
background: var(--sidebar);
max-width: 300px;
border-radius: 0.7em;
h1 {
font-size: 1rem;
}
}
.radio-title {
text-transform: uppercase;
font-weight: bold;
font-size: 1.17rem;
}
.radio-title-small {
text-transform: uppercase;
font-weight: bold;
font-size: 1rem;
}
.sortableitem {
color: var(--modal-text) !important;
cursor: move;
}
.updatechangelog {
max-width: 75%;
li {
cursor: initial;
font-size: 1rem;
list-style-type: disc;
padding: 0;
margin-left: 20px;
}
a {
color: var(--modal-link);
&:hover {
opacity: 0.8;
}
}
}
.changelogtab {
h1 {
max-width: 85%;
font-size: 2rem;
}
img {
max-width: 95%;
}
}
.sliderText {
color: var(--modal-text);
background: none;
border: none;
border-radius: 0;
font-size: 1rem;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
.resetArea {
h2 {
font-size: 2rem !important;
}
h2,
span,
svg {
display: inline;
}
svg {
vertical-align: sub;
font-size: 1.4rem;
th {
padding-right: 10px;
}
}

View File

@@ -0,0 +1,103 @@
/* these are overrides for the material ui default styles */
.MuiCheckbox-colorPrimary.Mui-checked,
.MuiSwitch-colorPrimary.Mui-checked,
.MuIconButton-colorPrimary.Mui-checked,
.MuiSwitch-thumb,
.MuiRadio-colorSecondary.Mui-checked,
.PrivateSwitchBase-input-4,
.MuiRadio-root,
.aboutLink,
.MuiSlider-colorPrimary,
legend {
color: var(--modal-text) !important;
}
.MuiFormControlLabel-labelPlacementStart {
margin-left: 0px !important;
}
.MuiSwitch-colorPrimary.Mui-checked+.MuiSwitch-track {
background: darkgray !important;
}
.MuiIconButton-label>svg.MuiSvgIcon-root {
color: var(--modal-text) !important;
}
.MuiTouchRipple-root {
background: transparent;
}
.MuiFormControl-root {
margin-top: 10px !important;
}
.checkbox svg {
fill: var(--modal-text) !important;
}
.radio-title {
font-weight: bold;
font-size: 1.17rem;
}
.radio-title-small {
font-weight: bold;
font-size: 1rem;
}
.MuiSlider-root {
margin-bottom: 30px !important;
}
.MuiOutlinedInput-notchedOutline {
border-color: var(--modal-text) !important;
}
.MuiFormLabel-root-MuiInputLabel-root {
color: var(--modal-text) !important;
}
.MuiInputLabel-root,
.MuiSlider-markLabel,
.MuiInputLabel-root,
.MuiSelect-icon,
.MuiSelect-select,
.Mui-focused,
legend,
.MuiOutlinedInput-input {
color: var(--modal-text) !important;
}
.MuiMenu-list {
background-color: var(--background) !important;
color: var(--modal-text) !important;
}
.Mui-selected {
background-color: var(--tab-active) !important;
}
.MuiTextField-root,
.MuiFormControl-root,
.MuiSlider-root {
width: 300px !important;
display: flex !important;
}
.Mui-disabled {
color: #818181 !important;
cursor: not-allowed;
.checkbox svg {
fill: #818181 !important;
}
}
.MuiPaper-root {
background-color: var(--background) !important;
}
.MuiSlider-valueLabel {
background-color: var(--tab-active) !important;
}

View File

@@ -0,0 +1,14 @@
.reminder-info {
position: absolute;
bottom: 20px;
right: 20px;
padding: 15px;
color: var(--modal-text);
background: var(--sidebar);
max-width: 300px;
border-radius: 0.7em;
h1 {
font-size: 1rem;
}
}

View File

@@ -0,0 +1,27 @@
.resetmodal {
min-height: 300px !important;
max-width: 300px !important;
margin: auto;
font-size: 1rem;
h4 {
cursor: initial;
font-size: 1.1rem;
}
}
.resetfooter {
position: absolute;
bottom: 20px;
width: 300px;
justify-content: center;
display: flex;
button.reset {
margin-right: 43px;
}
}
.resetoverlay {
background-color: rgba(0, 0, 0, 0.5);
}

View File

@@ -0,0 +1,36 @@
.aboutIcon {
color: var(--modal-text) !important;
padding-right: 10px;
&:hover {
opacity: 0.8;
}
svg {
font-size: 1.5em;
}
}
.aboutLink {
&:hover {
opacity: 0.8;
}
}
.aboutLogo {
height: 100px;
width: auto;
margin-left: -15px;
}
.abouticon {
width: 96px;
height: auto;
border-radius: 50%;
padding-right: 5px;
}
.contacth3 {
font-size: 1.5rem;
margin-bottom: 0.8em !important;
}

View File

@@ -0,0 +1,35 @@
.updatechangelog {
max-width: 75%;
li {
cursor: initial;
font-size: 1rem;
list-style-type: disc;
padding: 0;
margin-left: 20px;
}
a {
color: var(--modal-link);
&:hover {
opacity: 0.8;
}
}
}
.changelogtab {
h1 {
max-width: 85%;
font-size: 2rem;
margin-bottom: -10px !important;
}
h5 {
line-height: 0px !important;
}
img {
max-width: 95%;
}
}

View File

@@ -0,0 +1,54 @@
.sortableitem {
background: var(--sidebar) !important;
padding: 10px 80px;
padding-left: 10px;
border-radius: 15px;
margin-bottom: 10px;
font-size: 1.325rem;
color: var(--modal-text) !important;
cursor: move;
width: 150px;
z-index: 999 !important;
svg {
font-size: 1.3rem;
}
&:hover {
background: var(--tab-active) !important;
}
}
ul {
padding-left: 0px;
margin: 0;
>label {
vertical-align: middle;
}
}
.images-row {
display: flex;
flex-wrap: wrap;
width: 500px;
div {
width: 100px;
height: 100px;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
background-color: var(--sidebar);
border: 20px solid var(--sidebar);
border-radius: 20px;
margin: 0 20px 20px 0;
display: flex;
align-items: flex-end;
justify-content: center;
svg {
font-size: 1.9em;
}
}
}

View File

@@ -31,3 +31,8 @@ div.color-preview-area > div > div:nth-child(5) {
.gradient-type-item.active::after {
border: 2px solid var(--modal-text) !important;
}
.text-input, .number-input {
background-color: var(--sidebar) !important;
color: var(--modal-text) !important;
}

View File

@@ -1,7 +1,8 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Checkbox as CheckboxUI, FormControlLabel } from '@material-ui/core';
import { Checkbox as CheckboxUI, FormControlLabel } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Checkbox extends PureComponent {
constructor(props) {
@@ -19,7 +20,11 @@ export default class Checkbox extends PureComponent {
checked: value
});
window.stats.postEvent('setting', `${this.props.name} ${(this.state.checked === true) ? 'enabled' : 'disabled'}`);
if (this.props.onChange) {
this.props.onChange(value);
}
variables.stats.postEvent('setting', `${this.props.name} ${(this.state.checked === true) ? 'enabled' : 'disabled'}`);
if (this.props.element) {
if (!document.querySelector(this.props.element)) {
@@ -35,7 +40,7 @@ export default class Checkbox extends PureComponent {
return (
<>
<FormControlLabel
control={<CheckboxUI name={this.props.name} color='primary' className='checkbox' checked={this.state.checked} onChange={this.handleChange} />}
control={<CheckboxUI name={this.props.name} color='primary' className='checkbox' checked={this.state.checked} onChange={this.handleChange} disabled={this.props.disabled || false} />}
label={this.props.text}
/>
<br/>

View File

@@ -1,35 +1,35 @@
import { PureComponent } from 'react';
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { InputLabel, MenuItem, FormControl, Select } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Dropdown extends PureComponent {
constructor(props) {
super(props);
this.state = {
value: localStorage.getItem(this.props.name) || '',
value: localStorage.getItem(this.props.name) || this.props.children[0].props.value,
title: ''
};
}
getLabel() {
return this.props.label ? <label>{this.props.label}</label> : null;
this.dropdown = createRef();
}
onChange = (e) => {
const { value } = e.target;
if (value === window.language.modals.main.loading) {
if (value === variables.language.getMessage(variables.languagecode, 'modals.main.loading')) {
return;
}
window.stats.postEvent('setting', `${this.props.name} from ${this.state.value} to ${value}`);
variables.stats.postEvent('setting', `${this.props.name} from ${this.state.value} to ${value}`);
this.setState({
value: value,
title: e.target[e.target.selectedIndex].text
value
});
localStorage.setItem(this.props.name, value);
if (!this.props.noSetting) {
localStorage.setItem(this.props.name, value);
}
if (this.props.onChange) {
this.props.onChange(value);
@@ -45,22 +45,19 @@ export default class Dropdown extends PureComponent {
EventBus.dispatch('refresh', this.props.category);
}
// todo: find a better way to do this
componentDidMount() {
const element = document.getElementById(this.props.name);
this.setState({
title: element[element.selectedIndex].text
});
}
render() {
const id = 'dropdown' + this.props.name;
const label = this.props.label || '';
return (
<>
{this.getLabel()}
<select id={this.props.name} value={this.state.value} onChange={this.onChange} style={{ width: `${(8*this.state.title.length) + 50}px` }}>
{this.props.children}
</select>
</>
<FormControl fullWidth className={id}>
<InputLabel id={id}>{label}</InputLabel>
<Select labelId={id} id={this.props.name} value={this.state.value} label={label} onChange={this.onChange} ref={this.dropdown} key={id}>
{this.props.manual ? this.props.children : this.props.children.map((e, index) => {
return e ? <MenuItem key={index} value={e.props ? e.props.value : ''}>{e.props ? e.props.children : ''}</MenuItem> : null
})}
</Select>
</FormControl>
);
}
}

View File

@@ -1,7 +1,10 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
export default class FileUpload extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
componentDidMount() {
document.getElementById(this.props.id).onchange = (e) => {
const reader = new FileReader();
@@ -12,7 +15,7 @@ export default class FileUpload extends PureComponent {
} else {
// background upload
if (file.size > 2000000) {
return toast(window.language.modals.main.file_upload_error);
return toast(this.getMessage('modals.main.file_upload_error'));
}
reader.readAsDataURL(file);

View File

@@ -0,0 +1,24 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Slider from './Slider';
import Switch from './Switch';
import { values } from 'modules/helpers/settings/modals';
export default class Header extends PureComponent {
render() {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<h2>{this.props.title}</h2>
<Switch name={this.props.setting} text={getMessage('modals.main.settings.enabled')} category={this.props.category} element={this.props.element || null} />
{this.props.zoomSetting ?
<><Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.widget_zoom')} name={this.props.zoomSetting} min='10' max='400' default='100' display='%' marks={values('zoom')} category={this.props.zoomCategory || this.props.category}/></>
: <br/>}
</>
);
}
}

View File

@@ -0,0 +1,24 @@
import variables from 'modules/variables';
import { MdCancel } from 'react-icons/md';
import { TextField } from '@mui/material';
export default function KeybindInput(props) {
const value = props.state[props.setting];
const getButton = () => {
if (!value) {
return <button className='cleanButton' style={{ visibility: 'hidden' }} onClick={() => props.action('reset', props.setting)}><Cancel/></button>;;
} else if (value === variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.keybinds.recording')) {
return <button className='cleanButton' onClick={() => props.action('cancel', props.setting)}><MdCancel/></button>;
} else {
return <button className='cleanButton' onClick={() => props.action('reset', props.setting)}><MdCancel/></button>;
}
}
return (
<>
<TextField label={props.name} onClick={() => props.action('listen', props.setting)} value={value || variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.keybinds.click_to_record')} readOnly spellCheck={false} varient='outlined' InputLabelProps={{ shrink: true }} />
{getButton()}
</>
);
}

View File

@@ -1,7 +1,8 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Radio as RadioUI, RadioGroup, FormControlLabel, FormControl, FormLabel } from '@material-ui/core';
import { Radio as RadioUI, RadioGroup, FormControlLabel, FormControl, FormLabel } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Radio extends PureComponent {
constructor(props) {
@@ -20,18 +21,22 @@ export default class Radio extends PureComponent {
if (this.props.name === 'language') {
// old tab name
if (localStorage.getItem('tabName') === window.language.tabname) {
localStorage.setItem('tabName', require(`../../../../translations/${value.replace('-', '_')}.json`).tabname);
if (localStorage.getItem('tabName') === variables.language.getMessage(variables.languagecode, 'tabname')) {
localStorage.setItem('tabName', require(`translations/${value.replace('-', '_')}.json`).tabname);
}
}
localStorage.setItem(this.props.name, value);
this.setState({
value: value
value
});
window.stats.postEvent('setting', `${this.props.name} from ${this.state.value} to ${value}`);
if (this.props.onChange) {
this.props.onChange(value);
}
variables.stats.postEvent('setting', `${this.props.name} from ${this.state.value} to ${value}`);
if (this.props.element) {
if (!document.querySelector(this.props.element)) {

View File

@@ -1,27 +1,26 @@
import { Close, Delete } from '@material-ui/icons';
import { setDefaultSettings } from '../../../../modules/helpers/settings';
export default function ResetModal(props) {
const language = window.language.modals.main.settings.sections.advanced.reset_modal;
import variables from 'modules/variables';
import { MdClose, MdRestartAlt } from 'react-icons/md';
import { setDefaultSettings } from 'modules/helpers/settings';
export default function ResetModal({ modalClose }) {
const reset = () => {
window.stats.postEvent('setting', 'Reset');
variables.stats.postEvent('setting', 'Reset');
setDefaultSettings('reset');
window.location.reload();
};
return (
<>
<h1 style={{ textAlign: 'center' }}>{language.title}</h1>
<span>{language.question}</span>
<h1 style={{ textAlign: 'center' }}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.title')}</h1>
<span>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.question')}</span>
<br/><br/>
<span>{language.information}</span>
<span>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.advanced.reset_modal.information')}</span>
<div className='resetfooter'>
<button className='round reset' style={{ marginLeft: 0 }} onClick={() => reset()}>
<Delete/>
<MdRestartAlt/>
</button>
<button className='round import' style={{ marginLeft: '5px' }} onClick={props.modalClose}>
<Close/>
<button className='round add' style={{ marginLeft: '5px' }} onClick={modalClose}>
<MdClose/>
</button>
</div>
</>

View File

@@ -1,22 +1,21 @@
// todo: find a better method to do width of number input
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { Slider } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Slider extends PureComponent {
export default class SliderComponent extends PureComponent {
constructor(props) {
super(props);
this.state = {
value: localStorage.getItem(this.props.name) || this.props.default,
numberWidth: localStorage.getItem(this.props.name) ? ((localStorage.getItem(this.props.name).length + 1) * ((this.props.toast === true) ? 7.75 : 7)) : 32
value: localStorage.getItem(this.props.name) || this.props.default
};
this.language = window.language.modals.main.settings;
this.widthCalculation = (this.props.toast === true) ? 7.75 : 7;
}
handleChange = (e, text) => {
let { value } = e.target;
value = Number(value);
if (text) {
if (value === '') {
@@ -25,19 +24,18 @@ export default class Slider extends PureComponent {
});
}
if (Number(value) > this.props.max) {
if (value > this.props.max) {
value = this.props.max;
}
if (Number(value) < this.props.min) {
if (value < this.props.min) {
value = this.props.min;
}
}
localStorage.setItem(this.props.name, value);
this.setState({
value: value,
numberWidth: ((value.length + 1) * this.widthCalculation)
value
});
if (this.props.element) {
@@ -56,16 +54,24 @@ export default class Slider extends PureComponent {
value: this.props.default || ''
}
});
toast(window.language.toasts.reset);
toast(variables.language.getMessage(variables.languagecode, 'toasts.reset'));
}
render() {
const text = <input className='sliderText' type='number' min={this.props.min} max={this.props.max} onChange={(e) => this.handleChange(e, 'text')} value={this.state.value} style={{ width: this.state.numberWidth }}/>;
return (
<>
<p>{this.props.title} ({text}{this.props.display}) <span className='modalLink' onClick={this.resetItem}>{this.language.buttons.reset}</span></p>
<input className='range' type='range' min={this.props.min} max={this.props.max} step={this.props.step || 1} value={this.state.value} onChange={this.handleChange} />
<p>{this.props.title}<span className='modalLink' onClick={this.resetItem}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.buttons.reset')}</span></p>
<Slider
value={Number(this.state.value)}
onChange={this.handleChange}
valueLabelDisplay='auto'
default={Number(this.props.default)}
min={Number(this.props.min)}
max={Number(this.props.max)}
step={Number(this.props.step) || 1}
getAriaValueText={(value) => `${value}`}
marks={this.props.marks || []}
/>
</>
);
}

View File

@@ -1,7 +1,8 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Switch as SwitchUI, FormControlLabel } from '@material-ui/core';
import { Switch as SwitchUI, FormControlLabel } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Switch extends PureComponent {
constructor(props) {
@@ -19,7 +20,7 @@ export default class Switch extends PureComponent {
checked: value
});
window.stats.postEvent('setting', `${this.props.name} ${(this.state.checked === true) ? 'enabled' : 'disabled'}`);
variables.stats.postEvent('setting', `${this.props.name} ${(this.state.checked === true) ? 'enabled' : 'disabled'}`);
if (this.props.element) {
if (!document.querySelector(this.props.element)) {
@@ -39,7 +40,6 @@ export default class Switch extends PureComponent {
label={this.props.text}
labelPlacement='start'
/>
<br/>
</>
);
}

View File

@@ -1,7 +1,9 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { TextField } from '@mui/material';
import EventBus from '../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Text extends PureComponent {
constructor(props) {
@@ -9,7 +11,6 @@ export default class Text extends PureComponent {
this.state = {
value: localStorage.getItem(this.props.name) || ''
};
this.language = window.language.modals.main.settings;
}
handleChange = (e) => {
@@ -22,7 +23,7 @@ export default class Text extends PureComponent {
localStorage.setItem(this.props.name, value);
this.setState({
value: value
value
});
if (this.props.element) {
@@ -41,17 +42,17 @@ export default class Text extends PureComponent {
value: this.props.default || ''
}
});
toast(window.language.toasts.reset);
toast(variables.language.getMessage(variables.languagecode, 'toasts.reset'));
}
render() {
return (
<>
<p>{this.props.title} <span className='modalLink' onClick={this.resetItem}>{this.language.buttons.reset}</span></p>
{(this.props.textarea === true) ?
<textarea className='settingsTextarea' spellCheck={false} value={this.state.value} onChange={this.handleChange}/>
: <input type='text' value={this.state.value} onChange={this.handleChange}/>
{(this.props.textarea === true) ?
<TextField label={this.props.title} value={this.state.value} onChange={this.handleChange} varient='outlined' multiline spellCheck={false} minRows={4} maxRows={10} InputLabelProps={{ shrink: true }} />
: <TextField label={this.props.title} value={this.state.value} onChange={this.handleChange} varient='outlined' InputLabelProps={{ shrink: true }} />
}
<span className='modalLink' onClick={this.resetItem}>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.buttons.reset')}</span>
</>
);
}

View File

@@ -1,22 +1,26 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Email, Twitter, Chat, Instagram, Facebook } from '@material-ui/icons';
import { MdEmail } from 'react-icons/md';
import { FaDiscord, FaTwitter } from 'react-icons/fa';
import { SiGithubsponsors, SiLiberapay, SiKofi, SiPatreon } from 'react-icons/si';
import Tooltip from '../../../../helpers/tooltip/Tooltip';
import Tooltip from 'components/helpers/tooltip/Tooltip';
const other_contributors = require('../../../../../modules/other_contributors.json');
const other_contributors = require('modules/other_contributors.json');
export default class About extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
contributors: [],
sponsors: [],
other_contributors: [],
photographers: window.language.modals.main.loading,
update: window.language.modals.main.settings.sections.about.version.checking_update,
loading: window.language.modals.main.loading
photographers: this.getMessage('modals.main.loading'),
update: this.getMessage('modals.main.settings.sections.about.version.checking_update'),
loading: this.getMessage('modals.main.loading')
};
this.language = window.language.modals.main.settings.sections.about;
this.controller = new AbortController();
}
@@ -24,40 +28,42 @@ export default class About extends PureComponent {
let contributors, sponsors, photographers, versionData;
try {
versionData = await (await fetch(window.constants.GITHUB_URL + '/repos/' + window.constants.ORG_NAME + '/' + window.constants.REPO_NAME + '/releases', { signal: this.controller.signal })).json();
contributors = await (await fetch(window.constants.GITHUB_URL + '/repos/'+ window.constants.ORG_NAME + '/' + window.constants.REPO_NAME + '/contributors', { signal: this.controller.signal })).json();
sponsors = (await (await fetch(window.constants.SPONSORS_URL + '/list', { signal: this.controller.signal })).json()).sponsors;
photographers = await (await fetch(window.constants.API_URL + '/images/photographers', { signal: this.controller.signal })).json();
versionData = await (await fetch(variables.constants.GITHUB_URL + '/repos/' + variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/releases', { signal: this.controller.signal })).json();
contributors = await (await fetch(variables.constants.GITHUB_URL + '/repos/'+ variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/contributors', { signal: this.controller.signal })).json();
sponsors = (await (await fetch(variables.constants.SPONSORS_URL + '/list', { signal: this.controller.signal })).json()).sponsors;
photographers = await (await fetch(variables.constants.API_URL + '/images/photographers', { signal: this.controller.signal })).json();
} catch (e) {
if (this.controller.signal.aborted === true) {
return;
}
return this.setState({
update: this.language.version.error.title,
loading: this.language.version.error.description
update: this.getMessage('modals.main.settings.sections.about.version.error.title'),
loading: this.getMessage('modals.main.settings.sections.about.version.error.description')
});
}
if (sponsors.length === 0) {
sponsors = [{ handle: 'empty' }];
}
if (this.controller.signal.aborted === true) {
return;
}
const newVersion = versionData[0].tag_name;
let updateMsg = this.language.version.no_update;
if (Number(window.constants.VERSION.replaceAll('.', '')) < Number(newVersion.replaceAll('.', ''))) {
updateMsg = `${this.language.version.update_available}: ${newVersion}`;
let update = this.getMessage('modals.main.settings.sections.about.version.no_update');
if (Number(variables.constants.VERSION.replaceAll('.', '')) < Number(newVersion.replaceAll('.', ''))) {
update = `${this.getMessage('modals.main.settings.sections.about.version.update_available')}: ${newVersion}`;
}
this.setState({
// exclude bots
contributors: contributors.filter((contributor) => !contributor.login.includes('bot')),
sponsors: sponsors,
update: updateMsg,
other_contributors: other_contributors,
sponsors,
update,
other_contributors,
photographers: photographers.sort().join(', '),
loading: null
});
@@ -66,8 +72,8 @@ export default class About extends PureComponent {
componentDidMount() {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
this.setState({
update: this.language.version.offline_mode,
loading: window.language.modals.main.marketplace.offline.description
update: this.getMessage('modals.main.settings.sections.about.version.checking_update'),
loading: this.getMessage('modals.main.marketplace.offline.description')
});
return;
}
@@ -83,57 +89,58 @@ export default class About extends PureComponent {
render() {
return (
<>
<h2>{this.language.title}</h2>
<h2>{this.getMessage('modals.main.settings.sections.about.title')}</h2>
<img draggable='false' className='aboutLogo' src='./././icons/logo_horizontal.png' alt='Logo'></img>
<p>{this.language.copyright} {window.constants.COPYRIGHT_YEAR}-{new Date().getFullYear()} <a href={'https://github.com/' + window.constants.ORG_NAME + '/' + window.constants.REPO_NAME + '/graphs/contributors'} className='aboutLink' target='_blank' rel='noopener noreferrer'>{window.constants.COPYRIGHT_NAME}</a> ({window.constants.COPYRIGHT_LICENSE})</p>
<p>{this.language.version.title} {window.constants.VERSION} ({this.state.update})</p>
<a href={window.constants.PRIVACY_URL} className='aboutLink' target='_blank' rel='noopener noreferrer' style={{ fontSize: '1rem' }}>{window.language.modals.welcome.sections.privacy.links.privacy_policy}</a>
<p>{this.getMessage('modals.main.settings.sections.about.copyright')} {variables.constants.COPYRIGHT_YEAR}-{new Date().getFullYear()} <a href={'https://github.com/' + variables.constants.ORG_NAME + '/' + variables.constants.REPO_NAME + '/graphs/contributors'} className='aboutLink' target='_blank' rel='noopener noreferrer'>{variables.constants.COPYRIGHT_NAME}</a> ({variables.constants.COPYRIGHT_LICENSE})</p>
<p>{this.getMessage('modals.main.settings.sections.about.version.title')} {variables.constants.VERSION} ({this.state.update})</p>
<a href={variables.constants.PRIVACY_URL} className='aboutLink' target='_blank' rel='noopener noreferrer' style={{ fontSize: '1rem' }}>{this.getMessage('modals.welcome.sections.privacy.links.privacy_policy')}</a>
<h3>{this.language.contact_us}</h3>
<a href={'mailto:' + window.constants.EMAIL} className='aboutIcon' target='_blank' rel='noopener noreferrer'><Email/></a>
<a href={'https://twitter.com/' + window.constants.TWITTER_HANDLE} className='aboutIcon' target='_blank' rel='noopener noreferrer'><Twitter/></a>
<a href={'https://instagram.com/' + window.constants.INSTAGRAM_HANDLE} className='aboutIcon' target='_blank' rel='noopener noreferrer'><Instagram/></a>
<a href={'https://facebook.com/' + window.constants.FACEBOOK_HANDLE} className='aboutIcon' target='_blank' rel='noopener noreferrer'><Facebook/></a>
<a href={'https://discord.gg/' + window.constants.DISCORD_SERVER} className='aboutIcon' target='_blank' rel='noopener noreferrer'><Chat/></a>
<h3 className='contacth3'>{this.getMessage('modals.main.settings.sections.about.contact_us')}</h3>
<a href={'mailto:' + variables.constants.EMAIL} className='aboutIcon' target='_blank' rel='noopener noreferrer'><MdEmail/></a>
<a href={'https://twitter.com/' + variables.constants.TWITTER_HANDLE} className='aboutIcon' target='_blank' rel='noopener noreferrer'><FaTwitter/></a>
<a href={'https://discord.gg/' + variables.constants.DISCORD_SERVER} className='aboutIcon' target='_blank' rel='noopener noreferrer'><FaDiscord/></a>
<h3>{this.language.support_mue}</h3>
<p>
<a href={'https://github.com/sponsors/' + window.constants.DONATE_USERNAME} className='aboutLink' target='_blank' rel='noopener noreferrer'>GitHub Sponsors</a>
&nbsp; &nbsp;<a href={'https://ko-fi.com/' + window.constants.DONATE_USERNAME} className='aboutLink' target='_blank' rel='noopener noreferrer'>Ko-Fi</a>
&nbsp; &nbsp;<a href={'https://patreon.com/' + window.constants.DONATE_USERNAME} className='aboutLink' target='_blank' rel='noopener noreferrer'>Patreon</a>
</p>
<h3 className='contacth3'>{this.getMessage('modals.main.settings.sections.about.support_mue')}</h3>
<a href={'https://github.com/sponsors/' + variables.constants.SPONSORS_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiGithubsponsors/></a>
<a href={'https://liberapay.com/' + variables.constants.LIBERAPAY_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiLiberapay/></a>
<a href={'https://ko-fi.com/' + variables.constants.KOFI_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiKofi/></a>
<a href={'https://patreon.com/' + variables.constants.PATREON_USERNAME} className='aboutIcon' target='_blank' rel='noopener noreferrer'><SiPatreon/></a>
<h3>{this.language.resources_used.title}</h3>
<h3>{this.getMessage('modals.main.settings.sections.about.resources_used.title')}</h3>
<p>
<a href='https://www.pexels.com' className='aboutLink' target='_blank' rel='noopener noreferrer'>Pexels</a>
, <a href='https://unsplash.com' className='aboutLink' target='_blank' rel='noopener noreferrer'>Unsplash</a> ({this.language.resources_used.bg_images})
, <a href='https://unsplash.com' className='aboutLink' target='_blank' rel='noopener noreferrer'>Unsplash</a> ({this.getMessage('modals.main.settings.sections.about.resources_used.bg_images')})
</p>
<p><a href='https://fonts.google.com/icons?selected=Material+Icons' className='aboutLink' target='_blank' rel='noopener noreferrer'>Google Fonts</a> ({this.language.resources_used.pin_icon})</p>
<p><a href='https://undraw.co' className='aboutLink' target='_blank' rel='noopener noreferrer'>Undraw</a> ({this.language.resources_used.welcome_img})</p>
<h3>{this.language.contributors}</h3>
<h3>{this.getMessage('modals.main.settings.sections.about.contributors')}</h3>
<p>{this.state.loading}</p>
{this.state.contributors.map((item) => (
<Tooltip title={item.login} key={item.login}>
<a href={'https://github.com/' + item.login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={item.avatar_url + '&size=128'} alt={item.login}/></a>
{this.state.contributors.map(({ login, id }) => (
<Tooltip title={login} key={login}>
<a href={'https://github.com/' + login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={'https://avatars.githubusercontent.com/u/' + id + '?s=128'} alt={login}></img></a>
</Tooltip>
))}
{ // for those who contributed without opening a pull request
this.state.other_contributors.map((item) => (
<Tooltip title={item.login} key={item.login}>
<a href={'https://github.com/' + item.login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={item.avatar_url + '&size=128'} alt={item.login}/></a>
this.state.other_contributors.map(({ login, avatar_url }) => (
<Tooltip title={login} key={login}>
<a href={'https://github.com/' + login} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={avatar_url + '&s=128'} alt={login}></img></a>
</Tooltip>
))}
<h3>{this.language.supporters}</h3>
<h3>{this.getMessage('modals.main.settings.sections.about.supporters')}</h3>
<p>{this.state.loading}</p>
{this.state.sponsors.map((item) => (
<Tooltip title={item.handle} key={item.handle}>
<a href={'https://github.com/' + item.handle} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={item.avatar + '&size=128'} alt={item.handle}></img></a>
</Tooltip>
))}
{this.state.sponsors.map(({ handle, avatar }) => {
if (handle === 'empty') {
return <p>{this.getMessage('modals.main.settings.sections.about.no_supporters')}</p>;
}
<h3>{this.language.photographers}</h3>
return (
<Tooltip title={handle} key={handle}>
<a href={'https://github.com/' + handle} target='_blank' rel='noopener noreferrer'><img draggable='false' className='abouticon' src={avatar.split('?')[0] + '?s=128'} alt={handle}></img></a>
</Tooltip>
)
})}
<h3>{this.getMessage('modals.main.settings.sections.about.photographers')}</h3>
<p>{this.state.photographers}</p>
</>
);

View File

@@ -1,7 +1,10 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Modal from 'react-modal';
import { MenuItem } from '@mui/material';
import { MdUpload as ImportIcon, MdDownload as ExportIcon, MdRestartAlt as ResetIcon } from 'react-icons/md';
import { exportSettings, importSettings } from '../../../../../modules/helpers/settings/modals';
import { exportSettings, importSettings } from 'modules/helpers/settings/modals';
import Checkbox from '../Checkbox';
import FileUpload from '../FileUpload';
@@ -10,7 +13,7 @@ import Switch from '../Switch';
import ResetModal from '../ResetModal';
import Dropdown from '../Dropdown';
const time_zones = require('../../../../widgets/time/timezones.json');
const time_zones = require('components/widgets/time/timezones.json');
export default class AdvancedSettings extends PureComponent {
constructor() {
@@ -18,37 +21,51 @@ export default class AdvancedSettings extends PureComponent {
this.state = {
resetModal: false
};
this.language = window.language.modals.main.settings;
}
render() {
const { advanced } = this.language.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<h2>{advanced.title}</h2>
<Checkbox name='offlineMode' text={advanced.offline_mode} element='.other' />
<Dropdown name='timezone' label={advanced.timezone.title} category='timezone'>
<option value='auto'>{advanced.timezone.automatic}</option>
<h2>{getMessage('modals.main.settings.sections.advanced.title')}</h2>
<Checkbox name='offlineMode' text={getMessage('modals.main.settings.sections.advanced.offline_mode')} element='.other' />
<Dropdown name='timezone' label={getMessage('modals.main.settings.sections.advanced.timezone.title')} category='timezone' manual={true}>
<MenuItem value='auto'>{getMessage('modals.main.settings.sections.advanced.timezone.automatic')}</MenuItem>
{time_zones.map((timezone) => (
<option value={timezone} key={timezone}>{timezone}</option>
<MenuItem value={timezone} key={timezone}>{timezone}</MenuItem>
))}
</Dropdown>
<h3>{advanced.data}</h3>
<button className='reset' onClick={() => this.setState({ resetModal: true })}>{this.language.buttons.reset}</button>
<button className='export' onClick={() => exportSettings()}>{this.language.buttons.export}</button>
<button className='import' onClick={() => document.getElementById('file-input').click()}>{this.language.buttons.import}</button>
{localStorage.getItem('welcomePreview') !== 'true' ?
<>
<h3>{getMessage('modals.main.settings.sections.advanced.data')}</h3>
<br/>
<div className='data-buttons-row'>
<button onClick={() => this.setState({ resetModal: true })}>
{getMessage('modals.main.settings.buttons.reset')}
<ResetIcon/>
</button>
<button onClick={() => exportSettings()}>
{getMessage('modals.main.settings.buttons.export')}
<ExportIcon/>
</button>
<button onClick={() => document.getElementById('file-input').click()}>
{getMessage('modals.main.settings.buttons.import')}
<ImportIcon/>
</button>
</div>
</>
: null}
<FileUpload id='file-input' accept='application/json' type='settings' loadFunction={(e) => importSettings(e)}/>
<h3>{advanced.customisation}</h3>
<Text title={advanced.tab_name} name='tabName' default={window.language.tabname} category='other'/>
<Text title={advanced.custom_js} name='customjs' textarea={true} category='other' element='other'/>
<Text title={advanced.custom_css} name='customcss' textarea={true} category='other'/>
<h3>{getMessage('modals.main.settings.sections.advanced.customisation')}</h3>
<Text title={getMessage('modals.main.settings.sections.advanced.tab_name')} name='tabName' default={getMessage('tabname')} category='other'/>
<Text title={getMessage('modals.main.settings.sections.advanced.custom_css')} name='customcss' textarea={true} category='other'/>
<h3>{this.language.sections.experimental.title}</h3>
<p style={{ maxWidth: '75%' }}>{advanced.experimental_warning}</p>
<Switch name='experimental' text={this.language.enabled} element='.other'/>
<h3>{getMessage('modals.main.settings.sections.experimental.title')}</h3>
<p style={{ maxWidth: '75%' }}>{getMessage('modals.main.settings.sections.advanced.experimental_warning')}</p>
<Switch name='experimental' text={getMessage('modals.main.settings.enabled')} element='.other'/>
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ resetModal: false })} isOpen={this.state.resetModal} className='Modal resetmodal mainModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
<ResetModal modalClose={() => this.setState({ resetModal: false })} />

View File

@@ -1,65 +1,62 @@
import variables from 'modules/variables';
import Checkbox from '../Checkbox';
import Dropdown from '../Dropdown';
import Radio from '../Radio';
import Slider from '../Slider';
import Text from '../Text';
import { values } from 'modules/helpers/settings/modals';
export default function AppearanceSettings() {
const { appearance } = window.language.modals.main.settings.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const themeOptions = [
{
name: appearance.theme.auto,
name: getMessage('modals.main.settings.sections.appearance.theme.auto'),
value: 'auto'
},
{
name: appearance.theme.light,
name: getMessage('modals.main.settings.sections.appearance.theme.light'),
value: 'light'
},
{
name: appearance.theme.dark,
name: getMessage('modals.main.settings.sections.appearance.theme.dark'),
value: 'dark'
}
];
return (
<>
<h2>{appearance.title}</h2>
<Radio name='theme' title={appearance.theme.title} options={themeOptions} category='other' />
<h2>{getMessage('modals.main.settings.sections.appearance.title')}</h2>
<Radio name='theme' title={getMessage('modals.main.settings.sections.appearance.theme.title')} options={themeOptions} category='other' />
<h3>{appearance.navbar.title}</h3>
<Checkbox name='notesEnabled' text={appearance.navbar.notes} category='navbar' />
<Checkbox name='refresh' text={appearance.navbar.refresh} category='navbar' />
<Slider title={appearance.accessibility.widget_zoom} name='zoomNavbar' min='10' max='400' default='100' display='%' category='navbar' />
<h3>{appearance.font.title}</h3>
<Text title={appearance.font.custom} name='font' upperCaseFirst={true} category='other' />
<h3>{getMessage('modals.main.settings.sections.appearance.font.title')}</h3>
<Text title={getMessage('modals.main.settings.sections.appearance.font.custom')} name='font' upperCaseFirst={true} category='other' />
<br/>
<Checkbox name='fontGoogle' text={appearance.font.google} category='other' />
<Dropdown label={appearance.font.weight.title} name='fontweight' category='other'>
<Checkbox name='fontGoogle' text={getMessage('modals.main.settings.sections.appearance.font.google')} category='other' />
<Dropdown label={getMessage('modals.main.settings.sections.appearance.font.weight.title')} name='fontweight' category='other'>
{/* names are taken from https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight */}
<option value='100'>{appearance.font.weight.thin}</option>
<option value='200'>{appearance.font.weight.extra_light}</option>
<option value='300'>{appearance.font.weight.light}</option>
<option value='400'>{appearance.font.weight.normal}</option>
<option value='500'>{appearance.font.weight.medium}</option>
<option value='600'>{appearance.font.weight.semi_bold}</option>
<option value='700'>{appearance.font.weight.bold}</option>
<option value='800'>{appearance.font.weight.extra_bold}</option>
<option value='100'>{getMessage('modals.main.settings.sections.appearance.font.weight.thin')}</option>
<option value='200'>{getMessage('modals.main.settings.sections.appearance.font.weight.extra_light')}</option>
<option value='300'>{getMessage('modals.main.settings.sections.appearance.font.weight.light')}</option>
<option value='400'>{getMessage('modals.main.settings.sections.appearance.font.weight.normal')}</option>
<option value='500'>{getMessage('modals.main.settings.sections.appearance.font.weight.medium')}</option>
<option value='600'>{getMessage('modals.main.settings.sections.appearance.font.weight.semi_bold')}</option>
<option value='700'>{getMessage('modals.main.settings.sections.appearance.font.weight.bold')}</option>
<option value='800'>{getMessage('modals.main.settings.sections.appearance.font.weight.extra_bold')}</option>
</Dropdown>
<br/><br/>
<Dropdown label={appearance.font.style.title} name='fontstyle' category='other'>
<option value='normal'>{appearance.font.style.normal}</option>
<option value='italic'>{appearance.font.style.italic}</option>
<option value='oblique'>{appearance.font.style.oblique}</option>
<Dropdown label={getMessage('modals.main.settings.sections.appearance.font.style.title')} name='fontstyle' category='other'>
<option value='normal'>{getMessage('modals.main.settings.sections.appearance.font.style.normal')}</option>
<option value='italic'>{getMessage('modals.main.settings.sections.appearance.font.style.italic')}</option>
<option value='oblique'>{getMessage('modals.main.settings.sections.appearance.font.style.oblique')}</option>
</Dropdown>
<h3>{appearance.accessibility.title}</h3>
{/* not supported on firefox */}
{(navigator.userAgent.includes('Chrome') && typeof InstallTrigger === 'undefined') ?
<Slider title={appearance.accessibility.widget_zoom} name='widgetzoom' default='100' step='10' min='50' max='200' display='%' category='other'/>
: null}
<Slider title={appearance.accessibility.toast_duration} name='toastDisplayTime' default='2500' step='100' min='500' max='5000' toast={true} display={' ' + appearance.accessibility.milliseconds} />
<h3>{getMessage('modals.main.settings.sections.appearance.accessibility.title')}</h3>
<Checkbox text={getMessage('modals.main.settings.sections.appearance.accessibility.text_shadow')} name='textBorder' category='other'/>
<Checkbox text={getMessage('modals.main.settings.sections.appearance.accessibility.animations')} name='animations' category='other'/>
<Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.toast_duration')} name='toastDisplayTime' default='2500' step='100' min='500' max='5000' marks={values('toast')} toast={true}
display={' ' + getMessage('modals.main.settings.sections.appearance.accessibility.milliseconds')} />
</>
);
}

View File

@@ -1,5 +1,6 @@
import { PureComponent } from 'react';
import { WifiOff } from '@material-ui/icons';
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { MdOutlineWifiOff } from 'react-icons/md';
import Modal from 'react-modal';
import Lightbox from '../../marketplace/Lightbox';
@@ -12,19 +13,20 @@ export default class Changelog extends PureComponent {
showLightbox: false,
lightboxImg: null
};
this.language = window.language.modals.update;
this.offlineMode = (localStorage.getItem('offlineMode') === 'true');
this.controller = new AbortController();
this.changelog = createRef();
}
async getUpdate() {
const data = await (await fetch(window.constants.BLOG_POST + '/index.json', { signal: this.controller.signal })).json();
const data = await (await fetch(variables.constants.BLOG_POST + '/index.json', { signal: this.controller.signal })).json();
if (this.controller.signal.aborted === true) {
return;
}
let date = new Date(data.date.split(' ')[0]);
date = date.toLocaleDateString(window.languagecode.replace('_', '-'), {
date = date.toLocaleDateString(variables.languagecode.replace('_', '-'), {
year: 'numeric',
month: 'long',
day: 'numeric'
@@ -32,16 +34,17 @@ export default class Changelog extends PureComponent {
this.setState({
title: data.title,
date: date,
date,
image: data.featured_image || null,
author: 'By ' + data.authors.join(', '),
author: variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.changelog.by', {
author: data.authors.join(', ')
}),
html: data.html
});
// lightbox etc
const content = document.querySelector('.tab-content');
const images = content.getElementsByTagName('img');
const links = content.getElementsByTagName('a');
const images = this.changelog.current.getElementsByTagName('img');
const links = this.changelog.current.getElementsByTagName('a');
for (const img of images) {
img.draggable = false;
@@ -53,6 +56,7 @@ export default class Changelog extends PureComponent {
};
}
// open in new tab
for (let link = 0; link < links.length; link++) {
links[link].target = '_blank';
links[link].rel = 'noopener noreferrer';
@@ -60,7 +64,7 @@ export default class Changelog extends PureComponent {
}
componentDidMount() {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
if (navigator.onLine === false || this.offlineMode) {
return;
}
@@ -73,6 +77,8 @@ export default class Changelog extends PureComponent {
}
render() {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const errorMessage = (msg) => {
return (
<div className='emptyitems'>
@@ -83,25 +89,23 @@ export default class Changelog extends PureComponent {
);
};
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
const language = window.language.modals.main.marketplace;
if (navigator.onLine === false || this.offlineMode) {
return errorMessage(<>
<WifiOff/>
<h1>{language.offline.title}</h1>
<p className='description'>{language.offline.description}</p>
<MdOutlineWifiOff/>
<h1>{getMessage('modals.main.marketplace.offline.title')}</h1>
<p className='description'>{getMessage('modals.main.marketplace.offline.description')}</p>
</>);
}
if (!this.state.title) {
return errorMessage(<h1>{window.language.modals.main.loading}</h1>);
return errorMessage(<h1>{getMessage('modals.main.loading')}</h1>);
}
return (
<div className='changelogtab'>
<h1 style={{ marginBottom: '-10px' }}>{this.state.title}</h1>
<h5 style={{ lineHeight: '0px' }}>{this.state.author} {this.state.date}</h5>
{this.state.image ? <img draggable='false' src={this.state.image} alt={window.language.modals.update.title} className='updateimage'/> : null}
<div className='changelogtab' ref={this.changelog}>
<h1>{this.state.title}</h1>
<h5>{this.state.author} {this.state.date}</h5>
{this.state.image ? <img draggable='false' src={this.state.image} alt={this.state.title} className='updateimage'/> : null}
<div className='updatechangelog' dangerouslySetInnerHTML={{ __html: this.state.html }}/>
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ showLightbox: false })} isOpen={this.state.showLightbox} className='Modal lightboxmodal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
<Lightbox modalClose={() => this.setState({ showLightbox: false })} img={this.state.lightboxImg}/>

View File

@@ -0,0 +1,66 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Dropdown from '../Dropdown';
export default class DateSettings extends PureComponent {
constructor() {
super();
this.state = {
dateType: localStorage.getItem('dateType') || 'long'
};
}
render() {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
let dateSettings;
const longSettings = (
<>
<Checkbox name='dayofweek' text={getMessage('modals.main.settings.sections.date.day_of_week')} category='date' />
<Checkbox name='datenth' text={getMessage('modals.main.settings.sections.date.datenth')} category='date' />
</>
);
const shortSettings = (
<>
<Dropdown label={getMessage('modals.main.settings.sections.date.short_format')} name='dateFormat' category='date'>
<option value='DMY'>DMY</option>
<option value='MDY'>MDY</option>
<option value='YMD'>YMD</option>
</Dropdown>
<Dropdown label={getMessage('modals.main.settings.sections.date.short_separator.title')} name='shortFormat' category='date'>
<option value='dash'>{getMessage('modals.main.settings.sections.date.short_separator.dash')}</option>
<option value='dots'>{getMessage('modals.main.settings.sections.date.short_separator.dots')}</option>
<option value='gaps'>{getMessage('modals.main.settings.sections.date.short_separator.gaps')}</option>
<option value='slashes'>{getMessage('modals.main.settings.sections.date.short_separator.slashes')}</option>
</Dropdown>
</>
);
if (this.state.dateType === 'long') {
dateSettings = longSettings;
} else {
dateSettings = shortSettings;
}
return (
<>
<Header title={getMessage('modals.main.settings.sections.date.title')} setting='date' category='date' element='.date' zoomSetting='zoomDate'/>
<Checkbox name='weeknumber' text={getMessage('modals.main.settings.sections.date.week_number')} category='date'/>
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} name='dateType' onChange={(value) => this.setState({ dateType: value })} category='date'>
<option value='long'>{getMessage('modals.main.settings.sections.date.type.long')}</option>
<option value='short'>{getMessage('modals.main.settings.sections.date.type.short')}</option>
</Dropdown>
<Checkbox name='datezero' text={getMessage('modals.main.settings.sections.time.digital.zero')} category='date'/>
{dateSettings}
</>
);
}
}

View File

@@ -1,26 +1,29 @@
import variables from 'modules/variables';
import { useState } from 'react';
import Checkbox from '../Checkbox';
import Slider from '../Slider';
import { TextField } from '@mui/material';
import EventBus from '../../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
import { values } from 'modules/helpers/settings/modals';
export default function ExperimentalSettings() {
const { experimental } = window.language.modals.main.settings.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const [eventType, setEventType] = useState();
const [eventName, setEventName] = useState();
return (
<>
<h2>{experimental.title}</h2>
<p>{experimental.warning}</p>
<Checkbox name='animations' text={window.language.modals.main.settings.sections.appearance.animations} element='.other'/>
<h3>{experimental.developer}</h3>
<h2>{getMessage('modals.main.settings.sections.experimental.title')}</h2>
<p>{getMessage('modals.main.settings.sections.experimental.warning')}</p>
<h3>{getMessage('modals.main.settings.sections.experimental.developer')}</h3>
<Checkbox name='debug' text='Debug hotkey (Ctrl + #)' element='.other'/>
<Slider title='Debug timeout' name='debugtimeout' min='0' max='5000' default='0' step='100' display=' miliseconds' element='.other' />
<br/>
<Slider title='Debug timeout' name='debugtimeout' min='0' max='5000' default='0' step='100' marks={values('experimental')} element='.other' />
<p>Send Event</p>
Type <input type='text' id='eventType'/>
<br/><br/>
Name <input type='text' id='eventName'/>
<br/><br/>
<button className='uploadbg' onClick={() => EventBus.dispatch(document.getElementById('eventType').value, document.getElementById('eventName').value)}>Send</button>
<TextField label={'Type'} value={eventType} onChange={(e) => setEventType(e.target.value)} spellCheck={false} varient='outlined' InputLabelProps={{ shrink: true }} />
<TextField label={'Name'} value={eventName} onChange={(e) => setEventName(e.target.value)} spellCheck={false} varient='outlined' InputLabelProps={{ shrink: true }} />
<br/>
<button className='uploadbg' onClick={() => EventBus.dispatch(eventType, eventName)}>Send</button>
<br/><br/>
<button className='reset' style={{ marginLeft: '0px' }} onClick={() => localStorage.clear()}>Clear LocalStorage</button>
</>

View File

@@ -1,9 +1,10 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Switch from '../Switch';
import Text from '../Text';
import Slider from '../Slider';
export default class GreetingSettings extends PureComponent {
constructor() {
@@ -11,34 +12,32 @@ export default class GreetingSettings extends PureComponent {
this.state = {
birthday: new Date(localStorage.getItem('birthday')) || new Date()
};
this.language = window.language.modals.main.settings;
}
changeDate = (e) => {
localStorage.setItem('birthday', e.target.value);
localStorage.setItem('birthday', e.target.value || new Date());
this.setState({
birthday: new Date(e.target.value)
birthday: e.target.value ? new Date(e.target.value) : new Date()
});
}
render() {
const { greeting } = this.language.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<h2>{greeting.title}</h2>
<Switch name='greeting' text={this.language.enabled} category='greeting' element='.greeting'/>
<Checkbox name='events' text={greeting.events} category='greeting'/>
<Checkbox name='defaultGreetingMessage' text={greeting.default} category='greeting'/>
<Text title={greeting.name} name='greetingName' category='greeting'/>
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomGreeting' min='10' max='400' default='100' display='%' category='greeting' />
<Header title={getMessage('modals.main.settings.sections.greeting.title')} setting='greeting' category='greeting' element='.greeting' zoomSetting='zoomGreeting'/>
<Checkbox name='events' text={getMessage('modals.main.settings.sections.greeting.events')} category='greeting'/>
<Checkbox name='defaultGreetingMessage' text={getMessage('modals.main.settings.sections.greeting.default')} category='greeting'/>
<Text title={getMessage('modals.main.settings.sections.greeting.name')} name='greetingName' category='greeting'/>
<h3>{greeting.birthday}</h3>
<Switch name='birthdayenabled' text={this.language.enabled} category='greeting'/>
<Checkbox name='birthdayage' text={greeting.birthday_age} category='greeting'/>
<p>{greeting.birthday_date}</p>
<input type='date' onChange={this.changeDate} value={this.state.birthday.toISOString().substr(0, 10)}/>
<h3>{getMessage('modals.main.settings.sections.greeting.birthday')}</h3>
<Switch name='birthdayenabled' text={getMessage('modals.main.settings.enabled')} category='greeting'/>
<br/>
<Checkbox name='birthdayage' text={getMessage('modals.main.settings.sections.greeting.birthday_age')} category='greeting'/>
<p>{getMessage('modals.main.settings.sections.greeting.birthday_date')}</p>
<input type='date' onChange={this.changeDate} value={this.state.birthday.toISOString().substr(0, 10)} required/>
</>
);
}

View File

@@ -0,0 +1,148 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Header from '../Header';
import KeybindInput from '../KeybindInput';
export default class KeybindSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
keybinds: JSON.parse(localStorage.getItem('keybinds')) || {},
cancelled: false
};
}
showReminder() {
document.querySelector('.reminder-info').style.display = 'none';
return localStorage.setItem('showReminder', false);
}
listen(type) {
const currentKeybinds = this.state.keybinds;
currentKeybinds[type] = this.getMessage('modals.main.settings.sections.keybinds.recording');
this.setState({
keybinds: currentKeybinds,
cancelled: false
});
this.forceUpdate();
let keys = '';
let previouskey = '';
this.keydown = document.addEventListener('keydown', (event) => {
if (event.key === previouskey && this.state.cancelled === true) {
return;
}
if (keys === '') {
keys = event.key;
} else {
keys = `${keys}+${event.key}`;
}
previouskey = event.key
});
this.keyup = document.addEventListener('keyup', () => {
if (this.state.cancelled === true) {
return;
}
document.removeEventListener('keydown', this.keydown);
const keybinds = this.state.keybinds;
keybinds[type] = keys.split('+').slice(0, 4).join('+');
localStorage.setItem('keybinds', JSON.stringify(keybinds));
this.setState({
keybinds: JSON.parse(localStorage.getItem('keybinds')) || {}
});
});
document.removeEventListener('keyup', this.keyup);
this.showReminder();
}
cancel(type) {
document.removeEventListener('keydown', this.keydown);
document.removeEventListener('keyup', this.keyup);
const currentKeybinds = this.state.keybinds;
delete currentKeybinds[type];
this.setState({
keybinds: currentKeybinds,
cancelled: true
});
this.forceUpdate();
}
reset(type) {
const keybinds = this.state.keybinds;
keybinds[type] = '';
localStorage.setItem('keybinds', JSON.stringify(keybinds));
this.setState({
keybinds: JSON.parse(localStorage.getItem('keybinds')) || {},
cancelled: true
});
this.showReminder();
}
action(action, e) {
switch (action) {
case 'listen':
this.listen(e);
break;
case 'cancel':
this.cancel(e);
break;
case 'reset':
this.reset(e);
break;
default:
break;
}
}
render() {
return (
<>
<Header title={this.getMessage('modals.main.settings.sections.keybinds.title')} setting='keybindsEnabled' element='.other' />
<table className='keybind-table'>
<tbody>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.background.favourite')} state={this.state.keybinds} setting='favouriteBackground' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.background.maximise')} state={this.state.keybinds} setting='maximiseBackground' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.background.download')} state={this.state.keybinds} setting='downloadBackground' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.background.show_info')} state={this.state.keybinds} setting='showBackgroundInformation' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.background.show_info')} state={this.state.keybinds} setting='showBackgroundInformation' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.quote.favourite')} state={this.state.keybinds} setting='favouriteQuote' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.quote.copy')} state={this.state.keybinds} setting='copyQuote' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.quote.tweet')} state={this.state.keybinds} setting='tweetQuote' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.notes.pin')} state={this.state.keybinds} setting='pinNotes' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.notes.copy')} state={this.state.keybinds} setting='copyNotes' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.search')} state={this.state.keybinds} setting='focusSearch' action={(type, e) => this.action(type, e)}/></th>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.quicklinks')} state={this.state.keybinds} setting='toggleQuicklinks' action={(type, e) => this.action(type, e)}/></th>
</tr>
<tr>
<th><KeybindInput name={this.getMessage('modals.main.settings.sections.keybinds.modal')} state={this.state.keybinds} setting='toggleModal' action={(type, e) => this.action(type, e)}/></th>
</tr>
</tbody>
</table>
</>
);
}
}

View File

@@ -1,15 +1,18 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Radio from '../Radio';
const languages = require('../../../../../modules/languages.json');
const languages = require('modules/languages.json');
export default class LanguageSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
export default class BackgroundSettings extends PureComponent {
constructor() {
super();
this.state = {
quoteLanguages: [{
name: window.language.modals.main.loading,
name: this.getMessage('modals.main.loading'),
value: 'loading'
}]
};
@@ -17,22 +20,22 @@ export default class BackgroundSettings extends PureComponent {
}
async getQuoteLanguages() {
const data = await (await fetch(window.constants.API_URL + '/quotes/languages', { signal: this.controller.signal })).json();
const data = await (await fetch(variables.constants.API_URL + '/quotes/languages', { signal: this.controller.signal })).json();
if (this.controller.signal.aborted === true) {
return;
}
let array = [];
const quoteLanguages = [];
data.forEach((item) => {
array.push({
quoteLanguages.push({
name: item,
value: item
});
});
this.setState({
quoteLanguages: array
quoteLanguages
});
}
@@ -40,7 +43,7 @@ export default class BackgroundSettings extends PureComponent {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
return this.setState({
quoteLanguages: [{
name: window.language.modals.main.marketplace.offline.description,
name: this.getMessage('modals.main.marketplace.offline.description'),
value: 'loading'
}]
});
@@ -55,13 +58,11 @@ export default class BackgroundSettings extends PureComponent {
}
render() {
const language = window.language.modals.main.settings.sections.language;
return (
<>
<h2>{language.title}</h2>
<h2>{this.getMessage('modals.main.settings.sections.language.title')}</h2>
<Radio name='language' options={languages} element='.other' />
<h3>{language.quote}</h3>
<h3>{this.getMessage('modals.main.settings.sections.language.quote')}</h3>
<Radio name='quotelanguage' options={this.state.quoteLanguages} category='quote' />
</>
);

View File

@@ -0,0 +1,81 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { MdCancel, MdAdd } from 'react-icons/md';
import { toast } from 'react-toastify';
import { TextField } from '@mui/material';
import Header from '../Header';
import EventBus from 'modules/helpers/eventbus';
export default class Message extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
messages: JSON.parse(localStorage.getItem('messages')) || [''],
};
}
reset = () => {
localStorage.setItem('messages', '[""]');
this.setState({
messages: ['']
});
toast(this.getMessage(this.languagecode, 'toasts.reset'));
EventBus.dispatch('refresh', 'message');
}
modifyMessage(type, index) {
const messages = this.state.messages;
if (type === 'add') {
messages.push('');
} else {
messages.splice(index, 1);
}
this.setState({
messages
});
this.forceUpdate();
localStorage.setItem('messages', JSON.stringify(messages));
}
message(e, text, index) {
const result = (text === true) ? e.target.value : e.target.result;
const messages = this.state.messages;
messages[index] = result;
this.setState({
messages
});
this.forceUpdate();
localStorage.setItem('messages', JSON.stringify(messages));
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
}
render() {
return (
<>
<Header title={this.getMessage('modals.main.settings.sections.message.title')} setting='message' category='message' element='.message' zoomSetting='zoomMessage'/>
<p>{this.getMessage('modals.main.settings.sections.message.text')}</p>
<div className='data-buttons-row'>
<button onClick={() => this.modifyMessage('add')}>{this.getMessage('modals.main.settings.sections.message.add')} <MdAdd/></button>
</div>
{this.state.messages.map((_url, index) => (
<div style={{ display: 'flex' }} key={index}>
<TextField value={this.state.messages[index]} onChange={(e) => this.message(e, true, index)} varient='outlined' />
{this.state.messages.length > 1 ? <button className='cleanButton' onClick={() => this.modifyMessage('remove', index)}>
<MdCancel/>
</button> : null}
</div>
))}
<br/>
</>
);
}
}

View File

@@ -0,0 +1,34 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Checkbox from '../Checkbox';
import Dropdown from '../Dropdown';
import Slider from '../Slider';
import { values } from 'modules/helpers/settings/modals';
export default class Navbar extends PureComponent {
render() {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<h2>{getMessage('modals.main.settings.sections.appearance.navbar.title')}</h2>
<Slider title={getMessage('modals.main.settings.sections.appearance.accessibility.widget_zoom')} name='zoomNavbar' min='10' max='400' default='100' display='%' marks={values('zoom')} category='navbar' />
<Checkbox name='navbarHover' text={getMessage('modals.main.settings.sections.appearance.navbar.hover')} category='navbar'/>
<Checkbox name='notesEnabled' text={getMessage('modals.main.settings.sections.appearance.navbar.notes')} category='navbar' />
<Checkbox name='view' text={getMessage('modals.main.settings.sections.background.buttons.view')} category='navbar' />
<Checkbox name='favouriteEnabled' text={getMessage('modals.main.settings.sections.background.buttons.favourite')} category='navbar' />
<Dropdown label={getMessage('modals.main.settings.sections.appearance.navbar.refresh')} name='refresh' category='navbar'>
<option value='false'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.none')}</option>
<option value='background'>{getMessage('modals.main.settings.sections.background.title')}</option>
<option value='quote'>{getMessage('modals.main.settings.sections.quote.title')}</option>
<option value='quotebackground'>{getMessage('modals.main.settings.sections.quote.title')} + {getMessage('modals.main.settings.sections.background.title')}</option>
{/* before it was just a checkbox */}
<option value='true'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.page')}</option>
</Dropdown>
</>
);
}
}

View File

@@ -1,29 +1,31 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { DragIndicator } from '@material-ui/icons';
import { MdOutlineDragIndicator } from 'react-icons/md';
import { sortableContainer, sortableElement } from 'react-sortable-hoc';
import { toast } from 'react-toastify';
import EventBus from '../../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
const settings = window.language.modals.main.settings.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const widget_name = {
greeting: settings.greeting.title,
time: settings.time.title,
quicklinks: settings.quicklinks.title,
quote: settings.quote.title,
date: settings.time.date.title
greeting: getMessage('modals.main.settings.sections.greeting.title'),
time: getMessage('modals.main.settings.sections.time.title'),
quicklinks: getMessage('modals.main.settings.sections.quicklinks.title'),
quote: getMessage('modals.main.settings.sections.quote.title'),
date: getMessage('modals.main.settings.sections.date.title'),
message: getMessage('modals.main.settings.sections.message.title')
};
const SortableItem = sortableElement(({ value }) => (
<li className='sortableitem'>
<DragIndicator style={{ verticalAlign: 'middle' }} />
<MdOutlineDragIndicator style={{ verticalAlign: 'middle' }} />
{widget_name[value]}
</li>
));
const SortableContainer = sortableContainer(({ children }) => {
return <ul className='sortablecontainer'>{children}</ul>;
});
const SortableContainer = sortableContainer(({ children }) => (
<ul className='sortablecontainer'>{children}</ul>
));
export default class OrderSettings extends PureComponent {
constructor() {
@@ -31,25 +33,14 @@ export default class OrderSettings extends PureComponent {
this.state = {
items: JSON.parse(localStorage.getItem('order'))
};
this.language = window.language.modals.main.settings;
}
// based on https://stackoverflow.com/a/48301905
arrayMove(array, oldIndex, newIndex) {
if (oldIndex === newIndex) {
return array;
}
const result = Array.from(array);
const [removed] = result.splice(oldIndex, 1);
result.splice(newIndex, 0, removed);
const newArray = [...array];
const target = newArray[oldIndex];
const inc = newIndex < oldIndex ? -1 : 1;
for (let i = oldIndex; i !== newIndex; i += inc) {
newArray[i] = newArray[i + inc];
}
newArray[newIndex] = target;
return newArray;
return result;
}
onSortEnd = ({ oldIndex, newIndex }) => {
@@ -59,13 +50,13 @@ export default class OrderSettings extends PureComponent {
}
reset = () => {
localStorage.setItem('order', JSON.stringify(['greeting', 'time', 'quicklinks', 'quote', 'date']));
localStorage.setItem('order', JSON.stringify(['greeting', 'time', 'quicklinks', 'quote', 'date', 'message']));
this.setState({
items: JSON.parse(localStorage.getItem('order'))
});
toast(window.language.toasts.reset);
toast(getMessage('toasts.reset'));
}
enabled = (setting) => {
@@ -79,15 +70,15 @@ export default class OrderSettings extends PureComponent {
componentDidUpdate() {
localStorage.setItem('order', JSON.stringify(this.state.items));
window.stats.postEvent('setting', 'Widget order');
variables.stats.postEvent('setting', 'Widget order');
EventBus.dispatch('refresh', 'widgets');
}
render() {
return (
<>
<h2>{this.language.sections.order.title}</h2>
<span className='modalLink' onClick={this.reset}>{this.language.buttons.reset}</span>
<h2>{getMessage('modals.main.settings.sections.order.title')}</h2>
<span className='modalLink' onClick={this.reset}>{getMessage('modals.main.settings.buttons.reset')}</span>
<SortableContainer onSortEnd={this.onSortEnd} lockAxis='y' lockToContainerEdges disableAutoscroll>
{this.state.items.map((value, index) => {
if (!this.enabled(value)) {

View File

@@ -1,18 +1,20 @@
import Switch from '../Switch';
import variables from 'modules/variables';
import { useState } from 'react';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Slider from '../Slider';
export default function QuickLinks() {
const language = window.language.modals.main.settings.sections.quicklinks;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const [textOnly, setTextOnly] = useState(localStorage.getItem('quicklinksText') === 'true');
return (
<>
<h2>{language.title}</h2>
<Switch name='quicklinksenabled' text={window.language.modals.main.settings.enabled} category='quicklinks' element='.quicklinks-container'/>
<Checkbox name='quicklinksddgProxy' text={window.language.modals.main.settings.sections.background.ddg_image_proxy} category='quicklinks'/>
<Checkbox name='quicklinksnewtab' text={language.open_new} category='quicklinks'/>
<Checkbox name='quicklinkstooltip' text={language.tooltip} category='quicklinks'/>
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomQuicklinks' min='10' max='400' default='100' display='%' category='quicklinks'/>
<Header title={getMessage('modals.main.settings.sections.quicklinks.title')} setting='quicklinksenabled' category='quicklinks' element='.quicklinks-container' zoomSetting='zoomQuicklinks'/>
<Checkbox name='quicklinksText' text={getMessage('modals.main.settings.sections.quicklinks.text_only')} category='quicklinks' onChange={(value) => setTextOnly(value)}/>
<Checkbox name='quicklinksddgProxy' text={getMessage('modals.main.settings.sections.background.ddg_image_proxy')} category='quicklinks' disabled={textOnly}/>
<Checkbox name='quicklinksnewtab' text={getMessage('modals.main.settings.sections.quicklinks.open_new')} category='quicklinks'/>
<Checkbox name='quicklinkstooltip' text={getMessage('modals.main.settings.sections.quicklinks.tooltip')} category='quicklinks' disabled={textOnly}/>
</>
);
}

View File

@@ -1,49 +1,121 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { MdCancel, MdAdd } from 'react-icons/md';
import { TextField } from '@mui/material';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Text from '../Text';
import Switch from '../Switch';
import Slider from '../Slider';
import Dropdown from '../Dropdown';
import { toast } from 'react-toastify';
import EventBus from 'modules/helpers/eventbus';
export default class QuoteSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
quoteType: localStorage.getItem('quoteType') || 'api',
customQuote: this.getCustom()
};
}
marketplaceType = () => {
if (localStorage.getItem('quote_packs')) {
return <option value='quote_pack'>{window.language.modals.main.navbar.marketplace}</option>;
return <option value='quote_pack'>{this.getMessage('modals.main.navbar.marketplace')}</option>;
}
}
render() {
const { quote, background } = window.language.modals.main.settings.sections;
resetCustom = () => {
localStorage.setItem('customQuote', '[{"quote": "", "author": ""}]');
this.setState({
customQuote: [{
quote: '',
author: ''
}]
});
toast(this.getMessage('toasts.reset'));
EventBus.dispatch('refresh', 'background');
}
customQuote(e, text, index, type) {
const result = (text === true) ? e.target.value : e.target.result;
const customQuote = this.state.customQuote;
customQuote[index][type] = result;
this.setState({
customQuote
});
this.forceUpdate();
localStorage.setItem('customQuote', JSON.stringify(customQuote));
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
}
modifyCustomQuote(type, index) {
const customQuote = this.state.customQuote;
if (type === 'add') {
customQuote.push({
quote: '',
author: ''
});
} else {
customQuote.splice(index, 1);
}
this.setState({
customQuote
});
this.forceUpdate();
localStorage.setItem('customQuote', JSON.stringify(customQuote));
}
getCustom() {
let data = JSON.parse(localStorage.getItem('customQuote'));
if (data === null) {
data = [{
quote: localStorage.getItem('customQuote') || '',
author: localStorage.getItem('customQuoteAuthor') || ''
}];
}
return data;
}
render() {
let customSettings;
if (this.state.quoteType === 'custom') {
customSettings = (
<>
<Text title={quote.custom} name='customQuote' category='quote' />
<Text title={quote.custom_author} name='customQuoteAuthor' category='quote'/>
<p>{this.getMessage('modals.main.settings.sections.quote.custom')} <span className='modalLink' onClick={this.resetCustom}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
<div className='data-buttons-row'>
<button onClick={() => this.modifyCustomQuote('add')}>{this.getMessage('modals.main.settings.sections.quote.add')} <MdAdd/></button>
</div>
{this.state.customQuote.map((_url, index) => (
<div style={{ display: 'flex' }} key={index}>
<TextField value={this.state.customQuote[index].quote} placeholder='Quote' onChange={(e) => this.customQuote(e, true, index, 'quote')} varient='outlined' style={{ marginRight: '10px' }} />
<TextField value={this.state.customQuote[index].author} placeholder='Author' onChange={(e) => this.customQuote(e, true, index, 'author')} varient='outlined' />
{this.state.customQuote.length > 1 ? <button className='cleanButton' onClick={() => this.modifyCustomQuote('remove', index)} style={{ marginBottom: '-14px' }}>
<MdCancel/>
</button> : null}
</div>
))}
</>
);
} else {
// api
customSettings = (
<>
<br/><br/>
<Dropdown label={background.interval.title} name='quotechange'>
<option value='refresh'>{window.language.tabname}</option>
<option value='60000'>{background.interval.minute}</option>
<option value='1800000'>{background.interval.half_hour}</option>
<option value='3600000'>{background.interval.hour}</option>
<option value='86400000'>{background.interval.day}</option>
<option value='604800000'>{window.language.widgets.date.week}</option>
<option value='2628000000'>{background.interval.month}</option>
<Dropdown label={this.getMessage('modals.main.settings.sections.background.interval.title')} name='quotechange'>
<option value='refresh'>{this.getMessage('tabname')}</option>
<option value='60000'>{this.getMessage('modals.main.settings.sections.background.interval.minute')}</option>
<option value='1800000'>{this.getMessage('modals.main.settings.sections.background.interval.half_hour')}</option>
<option value='3600000'>{this.getMessage('modals.main.settings.sections.background.interval.hour')}</option>
<option value='86400000'>{this.getMessage('modals.main.settings.sections.background.interval.day')}</option>
<option value='604800000'>{this.getMessage('widgets.date.week')}</option>
<option value='2628000000'>{this.getMessage('modals.main.settings.sections.background.interval.month')}</option>
</Dropdown>
</>
);
@@ -51,22 +123,20 @@ export default class QuoteSettings extends PureComponent {
return (
<>
<h2>{quote.title}</h2>
<Switch name='quote' text={window.language.modals.main.settings.enabled} category='quote' element='.quotediv' />
<Checkbox name='authorLink' text={quote.author_link} element='.other' />
<Dropdown label={window.language.modals.main.settings.sections.background.type.title} name='quoteType' onChange={(value) => this.setState({ quoteType: value })} category='quote'>
<Header title={this.getMessage('modals.main.settings.sections.quote.title')} setting='quote' category='quote' element='.quotediv' zoomSetting='zoomQuote'/>
<Checkbox name='authorLink' text={this.getMessage('modals.main.settings.sections.quote.author_link')} element='.other' />
<Dropdown label={this.getMessage('modals.main.settings.sections.background.type.title')} name='quoteType' onChange={(value) => this.setState({ quoteType: value })} category='quote'>
{this.marketplaceType()}
<option value='api'>{window.language.modals.main.settings.sections.background.type.api}</option>
<option value='custom'>{quote.custom}</option>
<option value='api'>{this.getMessage('modals.main.settings.sections.background.type.api')}</option>
<option value='custom'>{this.getMessage('modals.main.settings.sections.quote.custom')}</option>
</Dropdown>
{customSettings}
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomQuote' min='10' max='400' default='100' display='%' category='quote' />
<h3>{quote.buttons.title}</h3>
<Checkbox name='copyButton' text={quote.buttons.copy} category='quote'/>
<Checkbox name='tweetButton' text={quote.buttons.tweet} category='quote'/>
<Checkbox name='favouriteQuoteEnabled' text={quote.buttons.favourite} category='quote'/>
<h3>{this.getMessage('modals.main.settings.sections.quote.buttons.title')}</h3>
<Checkbox name='copyButton' text={this.getMessage('modals.main.settings.sections.quote.buttons.copy')} category='quote'/>
<Checkbox name='tweetButton' text={this.getMessage('modals.main.settings.sections.quote.buttons.tweet')} category='quote'/>
<Checkbox name='favouriteQuoteEnabled' text={this.getMessage('modals.main.settings.sections.quote.buttons.favourite')} category='quote'/>
</>
);
}
}
}

View File

@@ -1,17 +1,21 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { MenuItem, TextField } from '@mui/material';
import Header from '../Header';
import Dropdown from '../Dropdown';
import Checkbox from '../Checkbox';
import Switch from '../Switch';
import Radio from '../Radio';
import EventBus from '../../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
const searchEngines = require('../../../../widgets/search/search_engines.json');
const autocompleteProviders = require('../../../../widgets/search/autocomplete_providers.json');
const searchEngines = require('components/widgets/search/search_engines.json');
const autocompleteProviders = require('components/widgets/search/autocomplete_providers.json');
export default class SearchSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
@@ -27,7 +31,7 @@ export default class SearchSettings extends PureComponent {
customValue: ''
});
toast(window.language.toasts.reset);
toast(this.getMessage('toasts.reset'));
}
componentDidMount() {
@@ -67,30 +71,26 @@ export default class SearchSettings extends PureComponent {
}
render() {
const language = window.language.modals.main.settings;
const { search } = language.sections;
return (
<>
<h2>{search.title}</h2>
<Switch name='searchBar' text={language.enabled} category='widgets' />
<Header title={this.getMessage('modals.main.settings.sections.search.title')} setting='searchBar' category='widgets'/>
{/* not supported on firefox */}
{(navigator.userAgent.includes('Chrome') && typeof InstallTrigger === 'undefined') ?
<Checkbox name='voiceSearch' text={search.voice_search} category='search'/>
<Checkbox name='voiceSearch' text={this.getMessage('modals.main.settings.sections.search.voice_search')} category='search'/>
: null}
<Dropdown label={search.search_engine} name='searchEngine' onChange={(value) => this.setSearchEngine(value)}>
<Checkbox name='searchDropdown' text={this.getMessage('modals.main.settings.sections.search.dropdown')} category='search' element='.other'/>
<Dropdown label={this.getMessage('modals.main.settings.sections.search.search_engine')} name='searchEngine' onChange={(value) => this.setSearchEngine(value)} manual={true}>
{searchEngines.map((engine) => (
<option key={engine.name} value={engine.settingsName}>{engine.name}</option>
<MenuItem key={engine.name} value={engine.settingsName}>{engine.name}</MenuItem>
))}
<option value='custom'>{search.custom.split(' ')[0]}</option>
<MenuItem value='custom'>{this.getMessage('modals.main.settings.sections.search.custom').split(' ')[0]}</MenuItem>
</Dropdown>
<ul style={{ display: this.state.customDisplay }}>
<br/>
<p style={{ marginTop: '0px' }}>{search.custom} <span className='modalLink' onClick={() => this.resetSearch()}>{language.buttons.reset}</span></p>
<input type='text' value={this.state.customValue} onInput={(e) => this.setState({ customValue: e.target.value })}></input>
<p style={{ marginTop: '0px' }}><span className='modalLink' onClick={() => this.resetSearch()}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
<TextField label={this.getMessage('modals.main.settings.sections.search.custom')} value={this.state.customValue} onInput={(e) => this.setState({ customValue: e.target.value })} varient='outlined' InputLabelProps={{ shrink: true }} />
</ul>
<br/>
<Checkbox name='autocomplete' text={search.autocomplete} category='search' />
<Radio title={search.autocomplete_provider} options={autocompleteProviders} name='autocompleteProvider' category='search'/>
<Checkbox name='autocomplete' text={this.getMessage('modals.main.settings.sections.search.autocomplete')} category='search' />
<Radio title={this.getMessage('modals.main.settings.sections.search.autocomplete_provider')} options={autocompleteProviders} name='autocompleteProvider' category='search'/>
</>
);
}

View File

@@ -1,8 +1,9 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Switch from '../Switch';
import EventBus from '../../../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
export default class Stats extends PureComponent {
constructor() {
@@ -10,7 +11,6 @@ export default class Stats extends PureComponent {
this.state = {
stats: JSON.parse(localStorage.getItem('statsData')) || {}
};
this.language = window.language.modals.main.settings.sections.stats;
}
componentDidMount() {
@@ -32,28 +32,29 @@ export default class Stats extends PureComponent {
}
render() {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
if (localStorage.getItem('stats') === 'false') {
return (
<>
<h2>{window.language.modals.main.settings.reminder.title}</h2>
<p>{this.language.warning}</p>
<Switch name='stats' text={this.language.usage} category='stats'/>
<h2>{getMessage('modals.main.settings.reminder.title')}</h2>
<p>{getMessage('modals.main.settings.sections.stats.warning')}</p>
<Switch name='stats' text={getMessage('modals.main.settings.sections.stats.usage')} category='stats'/>
</>
);
}
return (
<>
<h2>{this.language.title}</h2>
<p>{this.language.sections.tabs_opened}: {this.state.stats['tabs-opened'] || 0}</p>
<p>{this.language.sections.backgrounds_favourited}: {this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}</p>
<p>{this.language.sections.backgrounds_downloaded}: {this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}</p>
<p>{this.language.sections.quotes_favourited}: {this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}</p>
<p>{this.language.sections.quicklinks_added}: {this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}</p>
<p>{this.language.sections.settings_changed}: {this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}</p>
<p>{this.language.sections.addons_installed}: {this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}</p>
<Switch name='stats' text={this.language.usage} category='stats'/>
<p>{this.language.disable}</p>
<h2>{getMessage('modals.main.settings.sections.stats.title')}</h2>
<Switch name='stats' text={getMessage('modals.main.settings.sections.stats.usage')} category='stats'/>
<p>{getMessage('modals.main.settings.sections.stats.sections.tabs_opened')}: {this.state.stats['tabs-opened'] || 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.backgrounds_favourited')}: {this.state.stats.feature ? this.state.stats.feature['background-favourite'] || 0 : 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.backgrounds_downloaded')}: {this.state.stats.feature ? this.state.stats.feature['background-download'] || 0 : 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.quotes_favourited')}: {this.state.stats.feature ? this.state.stats.feature['quoted-favourite'] || 0 : 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.quicklinks_added')}: {this.state.stats.feature ? this.state.stats.feature['quicklink-add'] || 0 : 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.settings_changed')}: {this.state.stats.setting ? Object.keys(this.state.stats.setting).length : 0}</p>
<p>{getMessage('modals.main.settings.sections.stats.sections.addons_installed')}: {this.state.stats.marketplace ? this.state.stats.marketplace['install'] : 0}</p>
</>
);
}

View File

@@ -1,122 +1,70 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Dropdown from '../Dropdown';
import Switch from '../Switch';
import Radio from '../Radio';
import Slider from '../Slider';
export default class TimeSettings extends PureComponent {
constructor() {
super();
this.state = {
timeType: localStorage.getItem('timeType') || 'digital',
dateType: localStorage.getItem('dateType') || 'long'
timeType: localStorage.getItem('timeType') || 'digital'
};
this.language = window.language.modals.main.settings;
}
render() {
const { time } = this.language.sections;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
let timeSettings;
let timeSettings = null;
const digitalOptions = [
{
name: time.digital.twentyfourhour,
name: getMessage('modals.main.settings.sections.time.digital.twentyfourhour'),
value: 'twentyfourhour'
},
{
name: time.digital.twelvehour,
name: getMessage('modals.main.settings.sections.time.digital.twelvehour'),
value: 'twelvehour'
}
];
const digitalSettings = (
<>
<h3>{time.digital.title}</h3>
<Radio title={time.format} name='timeformat' options={digitalOptions} smallTitle={true} category='clock' />
<br/>
<Checkbox name='seconds' text={time.digital.seconds} category='clock' />
<Checkbox name='zero' text={time.digital.zero} category='clock' />
<h3>{getMessage('modals.main.settings.sections.time.digital.title')}</h3>
<Radio title={getMessage('modals.main.settings.sections.time.format')} name='timeformat' options={digitalOptions} smallTitle={true} category='clock' />
<Checkbox name='seconds' text={getMessage('modals.main.settings.sections.time.digital.seconds')} category='clock' />
<Checkbox name='zero' text={getMessage('modals.main.settings.sections.time.digital.zero')} category='clock' />
</>
);
const analogSettings = (
<>
<h3>{time.analogue.title}</h3>
<Checkbox name='secondHand' text={time.analogue.second_hand} category='clock' />
<Checkbox name='minuteHand' text={time.analogue.minute_hand} category='clock' />
<Checkbox name='hourHand' text={time.analogue.hour_hand} category='clock' />
<Checkbox name='hourMarks' text={time.analogue.hour_marks} category='clock' />
<Checkbox name='minuteMarks' text={time.analogue.minute_marks} category='clock' />
<h3>{getMessage('modals.main.settings.sections.time.analogue.title')}</h3>
<Checkbox name='secondHand' text={getMessage('modals.main.settings.sections.time.analogue.second_hand')} category='clock' />
<Checkbox name='minuteHand' text={getMessage('modals.main.settings.sections.time.analogue.minute_hand')} category='clock' />
<Checkbox name='hourHand' text={getMessage('modals.main.settings.sections.time.analogue.hour_hand')} category='clock' />
<Checkbox name='hourMarks' text={getMessage('modals.main.settings.sections.time.analogue.hour_marks')} category='clock' />
<Checkbox name='minuteMarks' text={getMessage('modals.main.settings.sections.time.analogue.minute_marks')} category='clock' />
</>
);
switch (this.state.timeType) {
case 'digital': timeSettings = digitalSettings; break;
case 'analogue': timeSettings = analogSettings; break;
default: timeSettings = null; break;
}
let dateSettings;
const longSettings = (
<>
<Checkbox name='dayofweek' text={time.date.day_of_week} category='date' />
<Checkbox name='datenth' text={time.date.datenth} category='date' />
</>
);
const shortSettings = (
<>
<br/>
<Dropdown label={time.date.short_format} name='dateFormat' category='date'>
<option value='DMY'>DMY</option>
<option value='MDY'>MDY</option>
<option value='YMD'>YMD</option>
</Dropdown>
<br/><br/>
<Dropdown label={time.date.short_separator.title} name='shortFormat' category='date'>
<option value='dash'>{time.date.short_separator.dash}</option>
<option value='dots'>{time.date.short_separator.dots}</option>
<option value='gaps'>{time.date.short_separator.gaps}</option>
<option value='slashes'>{time.date.short_separator.slashes}</option>
</Dropdown>
</>
);
switch (this.state.dateType) {
case 'short': dateSettings = shortSettings; break;
case 'long': dateSettings = longSettings; break;
default: break;
if (this.state.timeType === 'digital') {
timeSettings = digitalSettings;
} else if (this.state.timeType === 'analogue') {
timeSettings = analogSettings;
}
return (
<>
<h2>{time.title}</h2>
<Switch name='time' text={this.language.enabled} category='clock' element='.clock-container' />
<Dropdown label={time.type} name='timeType' onChange={(value) => this.setState({ timeType: value })} category='clock'>
<option value='digital'>{time.digital.title}</option>
<option value='analogue'>{time.analogue.title}</option>
<option value='percentageComplete'>{time.percentage_complete}</option>
<Header title={getMessage('modals.main.settings.sections.time.title')} setting='time' category='clock' element='.clock-container' zoomSetting='zoomClock'/>
<Dropdown label={getMessage('modals.main.settings.sections.time.type')} name='timeType' onChange={(value) => this.setState({ timeType: value })} category='clock'>
<option value='digital'>{getMessage('modals.main.settings.sections.time.digital.title')}</option>
<option value='analogue'>{getMessage('modals.main.settings.sections.time.analogue.title')}</option>
<option value='percentageComplete'>{getMessage('modals.main.settings.sections.time.percentage_complete')}</option>
</Dropdown>
{timeSettings}
{this.state.timeType !== 'analogue' ?
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomClock' min='10' max='400' default='100' display='%' category='clock'/>
: null}
<h3>{time.date.title}</h3>
<Switch name='date' text={this.language.enabled} category='date' element='.date'/>
<Dropdown label={time.type} name='dateType' onChange={(value) => this.setState({ dateType: value })} category='date'>
<option value='long'>{time.date.type.long}</option>
<option value='short'>{time.date.type.short}</option>
</Dropdown>
<br/>
<Checkbox name='datezero' text={time.digital.zero} category='date'/>
<Checkbox name='weeknumber' text={time.date.week_number} category='date'/>
{dateSettings}
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomDate' min='10' max='400' default='100' display='%' category='date'/>
</>
);
}

View File

@@ -1,41 +1,45 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Switch from '../Switch';
import Header from '../Header';
import Radio from '../Radio';
import Checkbox from '../Checkbox';
import Slider from '../Slider';
import { TextField } from '@mui/material';
export default class TimeSettings extends PureComponent {
constructor() {
super();
this.state = {
location: localStorage.getItem('location') || 'London'
location: localStorage.getItem('location') || '',
windSpeed: (localStorage.getItem('windspeed') !== 'true')
};
this.language = window.language.modals.main.settings;
}
componentDidUpdate() {
localStorage.setItem('location', this.state.location);
}
showReminder() {
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
}
changeLocation(e) {
this.setState({
location: e.target.value
});
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
this.showReminder();
}
getAuto() {
navigator.geolocation.getCurrentPosition(async (position) => {
const data = await (await fetch(`${window.constants.PROXY_URL}/weather/autolocation?lat=${position.coords.latitude}&lon=${position.coords.longitude}`)).json();
const data = await (await fetch(`${variables.constants.PROXY_URL}/weather/autolocation?lat=${position.coords.latitude}&lon=${position.coords.longitude}`)).json();
this.setState({
location: data[0].name
});
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
this.showReminder();
}, (error) => {
// firefox requires this 2nd function
console.log(error);
@@ -45,46 +49,41 @@ export default class TimeSettings extends PureComponent {
}
render() {
const language = window.language.modals.main.settings.sections.weather;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
const tempFormat = [
{
name: language.temp_format.celsius + ' (°C)',
name: getMessage('modals.main.settings.sections.weather.temp_format.celsius') + ' (°C)',
value: 'celsius'
},
{
name: language.temp_format.fahrenheit + ' (°F)',
name: getMessage('modals.main.settings.sections.weather.temp_format.fahrenheit') + ' (°F)',
value: 'fahrenheit'
},
{
name: language.temp_format.kelvin + ' (K)',
name: getMessage('modals.main.settings.sections.weather.temp_format.kelvin') + ' (K)',
value: 'kelvin'
}
];
return (
<>
<h2>{language.title}</h2>
<Switch name='weatherEnabled' text={this.language.enabled} category='widgets'/>
<ul>
<p>{language.location} <span className='modalLink' onClick={() => this.getAuto()}>{language.auto}</span></p>
<input type='text' value={this.state.location} onChange={(e) => this.changeLocation(e)}></input>
</ul>
<br/>
<Radio name='tempformat' title={language.temp_format.title} options={tempFormat} category='weather'/>
<Slider title={window.language.modals.main.settings.sections.appearance.accessibility.widget_zoom} name='zoomWeather' min='10' max='400' default='100' display='%' category='weather'/>
<Header title={getMessage('modals.main.settings.sections.weather.title')} setting='weatherEnabled' category='widgets' zoomSetting='zoomWeather' zoomCategory='weather'/>
<TextField label={getMessage('modals.main.settings.sections.weather.location')} value={this.state.location} onChange={(e) => this.changeLocation(e)} placeholder='London' varient='outlined' InputLabelProps={{ shrink: true }} />
<span className='modalLink' onClick={() => this.getAuto()}>{getMessage('modals.main.settings.sections.weather.auto')}</span>
<Radio name='tempformat' title={getMessage('modals.main.settings.sections.weather.temp_format.title')} options={tempFormat} category='weather'/>
<h3>{language.extra_info.title}</h3>
<Checkbox name='showlocation' text={language.extra_info.show_location} category='weather'/>
<Checkbox name='weatherdescription' text={language.extra_info.show_description} category='weather'/>
<Checkbox name='cloudiness' text={language.extra_info.cloudiness} category='weather'/>
<Checkbox name='humidity' text={language.extra_info.humidity} category='weather'/>
<Checkbox name='visibility' text={language.extra_info.visibility} category='weather'/>
<Checkbox name='windspeed' text={language.extra_info.wind_speed} category='weather'/>
<Checkbox name='windDirection' text={language.extra_info.wind_direction} category='weather'/>
<Checkbox name='mintemp' text={language.extra_info.min_temp} category='weather'/>
<Checkbox name='maxtemp' text={language.extra_info.max_temp} category='weather'/>
<Checkbox name='atmosphericpressure' text={language.extra_info.atmospheric_pressure} category='weather'/>
<h3>{getMessage('modals.main.settings.sections.weather.extra_info.title')}</h3>
<Checkbox name='showlocation' text={getMessage('modals.main.settings.sections.weather.extra_info.show_location')} category='weather'/>
<Checkbox name='weatherdescription' text={getMessage('modals.main.settings.sections.weather.extra_info.show_description')} category='weather'/>
<Checkbox name='cloudiness' text={getMessage('modals.main.settings.sections.weather.extra_info.cloudiness')} category='weather'/>
<Checkbox name='humidity' text={getMessage('modals.main.settings.sections.weather.extra_info.humidity')} category='weather'/>
<Checkbox name='visibility' text={getMessage('modals.main.settings.sections.weather.extra_info.visibility')} category='weather'/>
<Checkbox name='windspeed' text={getMessage('modals.main.settings.sections.weather.extra_info.wind_speed')} category='weather' onChange={() => this.setState({ windSpeed: (localStorage.getItem('windspeed') !== 'true') })}/>
<Checkbox name='windDirection' text={getMessage('modals.main.settings.sections.weather.extra_info.wind_direction')} category='weather' disabled={this.state.windSpeed}/>
<Checkbox name='mintemp' text={getMessage('modals.main.settings.sections.weather.extra_info.min_temp')} category='weather'/>
<Checkbox name='maxtemp' text={getMessage('modals.main.settings.sections.weather.extra_info.max_temp')} category='weather'/>
<Checkbox name='atmosphericpressure' text={getMessage('modals.main.settings.sections.weather.extra_info.atmospheric_pressure')} category='weather'/>
</>
);
}

View File

@@ -1,70 +1,35 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { MenuItem } from '@mui/material';
import Header from '../../Header';
import Checkbox from '../../Checkbox';
import Dropdown from '../../Dropdown';
import FileUpload from '../../FileUpload';
import Slider from '../../Slider';
import Switch from '../../Switch';
import Radio from '../../Radio';
import ColourSettings from './Colour';
import CustomSettings from './Custom';
import EventBus from '../../../../../../modules/helpers/eventbus';
import { values } from 'modules/helpers/settings/modals';
export default class BackgroundSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
customBackground: localStorage.getItem('customBackground') || '',
backgroundType: localStorage.getItem('backgroundType') || 'api',
backgroundCategories: [window.language.modals.main.loading]
backgroundFilter: localStorage.getItem('backgroundFilter') || 'none',
backgroundCategories: [this.getMessage('modals.main.loading')],
backgroundAPI: localStorage.getItem('backgroundAPI') || 'mue',
marketplaceEnabled: localStorage.getItem('photo_packs')
};
this.language = window.language.modals.main.settings;
this.controller = new AbortController();
}
resetCustom = () => {
localStorage.setItem('customBackground', '');
this.setState({
customBackground: ''
});
toast(window.language.toasts.reset);
EventBus.dispatch('refresh', 'background');
}
customBackground(e, text) {
const result = (text === true) ? e.target.value : e.target.result;
localStorage.setItem('customBackground', result);
this.setState({
customBackground: result
});
EventBus.dispatch('refresh', 'background');
}
videoCustomSettings = () => {
const customBackground = this.state.customBackground;
if (customBackground.startsWith('data:video/') || customBackground.endsWith('.mp4') || customBackground.endsWith('.webm') || customBackground.endsWith('.ogg')) {
return (
<>
<Checkbox name='backgroundVideoLoop' text={this.language.sections.background.source.loop_video}/>
<Checkbox name='backgroundVideoMute' text={this.language.sections.background.source.mute_video}/>
</>
);
} else {
return null;
}
}
marketplaceType = () => {
if (localStorage.getItem('photo_packs')) {
return <option value='photo_pack'>{window.language.modals.main.navbar.marketplace}</option>;
}
}
async getBackgroundCategories() {
const data = await (await fetch(window.constants.API_URL + '/images/categories', { signal: this.controller.signal })).json();
const data = await (await fetch(variables.constants.API_URL + '/images/categories', { signal: this.controller.signal })).json();
if (this.controller.signal.aborted === true) {
return;
@@ -78,7 +43,7 @@ export default class BackgroundSettings extends PureComponent {
componentDidMount() {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
return this.setState({
backgroundCategories: [window.language.modals.update.offline.title]
backgroundCategories: [this.getMessage('modals.update.offline.title')]
});
}
@@ -91,7 +56,7 @@ export default class BackgroundSettings extends PureComponent {
}
render() {
const { background } = this.language.sections;
const { getMessage } = this;
let backgroundSettings;
@@ -110,94 +75,104 @@ export default class BackgroundSettings extends PureComponent {
}
];
const APISettings = (
<>
<br/>
<Radio title={background.source.api} options={apiOptions} name='backgroundAPI' category='background' element='#backgroundImage'/>
<br/>
<Dropdown label={background.category} name='apiCategory'>
{this.state.backgroundCategories.map((category) => (
<option value={category} key={category}>{category.charAt(0).toUpperCase() + category.slice(1)}</option>
))}
</Dropdown>
<br/><br/>
<Dropdown label={background.source.quality.title} name='apiQuality' element='.other'>
<option value='original'>{background.source.quality.original}</option>
<option value='high'>{background.source.quality.high}</option>
<option value='normal'>{background.source.quality.normal}</option>
<option value='datasaver'>{background.source.quality.datasaver}</option>
</Dropdown>
<br/><br/>
<Dropdown label={background.interval.title} name='backgroundchange'>
<option value='refresh'>{window.language.tabname}</option>
<option value='60000'>{background.interval.minute}</option>
<option value='1800000'>{background.interval.half_hour}</option>
<option value='3600000'>{background.interval.hour}</option>
<option value='86400000'>{background.interval.day}</option>
<option value='604800000'>{window.language.widgets.date.week}</option>
<option value='2628000000'>{background.interval.month}</option>
</Dropdown>
</>
const interval = (
<Dropdown label={getMessage('modals.main.settings.sections.background.interval.title')} name='backgroundchange'>
<option value='refresh'>{getMessage('tabname')}</option>
<option value='60000'>{getMessage('modals.main.settings.sections.background.interval.minute')}</option>
<option value='1800000'>{getMessage('modals.main.settings.sections.background.interval.half_hour')}</option>
<option value='3600000'>{getMessage('modals.main.settings.sections.background.interval.hour')}</option>
<option value='86400000'>{getMessage('modals.main.settings.sections.background.interval.day')}</option>
<option value='604800000'>{getMessage('widgets.date.week')}</option>
<option value='2628000000'>{getMessage('modals.main.settings.sections.background.interval.month')}</option>
</Dropdown>
);
const customSettings = (
const APISettings = (
<>
<ul>
<p>{background.source.custom_background} <span className='modalLink' onClick={this.resetCustom}>{this.language.buttons.reset}</span></p>
<input type='text' value={this.state.customBackground} onChange={(e) => this.customBackground(e, true)}></input>
<span className='modalLink' onClick={() => document.getElementById('bg-input').click()}>{background.source.upload}</span>
<FileUpload id='bg-input' accept='image/jpeg, image/png, image/webp, image/webm, image/gif, video/mp4, video/webm, video/ogg' loadFunction={(e) => this.customBackground(e)} />
</ul>
{this.videoCustomSettings()}
<Radio title={getMessage('modals.main.settings.sections.background.source.api')} options={apiOptions} name='backgroundAPI' category='background' element='#backgroundImage' onChange={(e) => this.setState({ backgroundAPI: e })}/>
{this.state.backgroundCategories[0] === getMessage('modals.main.loading') ?
<>
<Dropdown label={getMessage('modals.main.settings.sections.background.category')} name='apiCategory'>
<MenuItem value='loading' key='loading'>{getMessage('modals.main.loading')}</MenuItem>
<MenuItem value='loading' key='loading'>{getMessage('modals.main.loading')}</MenuItem>
</Dropdown>
</> :
<Dropdown label={getMessage('modals.main.settings.sections.background.category')} name='apiCategory' >
{this.state.backgroundCategories.map((category) => (
<MenuItem value={category} key={category}>{category.charAt(0).toUpperCase() + category.slice(1)}</MenuItem>
))}
</Dropdown>
}
<Dropdown label={getMessage('modals.main.settings.sections.background.source.quality.title')} name='apiQuality' element='.other'>
<option value='original'>{getMessage('modals.main.settings.sections.background.source.quality.original')}</option>
<option value='high'>{getMessage('modals.main.settings.sections.background.source.quality.high')}</option>
<option value='normal'>{getMessage('modals.main.settings.sections.background.source.quality.normal')}</option>
<option value='datasaver'>{getMessage('modals.main.settings.sections.background.source.quality.datasaver')}</option>
</Dropdown>
{interval}
</>
);
switch (this.state.backgroundType) {
case 'custom': backgroundSettings = customSettings; break;
case 'custom': backgroundSettings = <CustomSettings interval={interval}/>; break;
case 'colour': backgroundSettings = <ColourSettings/>; break;
case 'random_colour': backgroundSettings = <></>; break;
case 'random_gradient': backgroundSettings = <></>; break;
default: backgroundSettings = APISettings; break;
}
if (localStorage.getItem('photo_packs') && this.state.backgroundType !== 'custom' && this.state.backgroundType !== 'colour' && this.state.backgroundType !== 'api') {
backgroundSettings = null;
}
const usingImage = this.state.backgroundType !== 'colour' && this.state.backgroundType !== 'random_colour' && this.state.backgroundType !== 'random_gradient';
return (
<>
<h2>{background.title}</h2>
<Switch name='background' text={this.language.enabled} category='background' element='#backgroundImage' />
<Checkbox name='ddgProxy' text={background.ddg_image_proxy} element='.other' />
<Checkbox name='bgtransition' text={background.transition} element='.other' />
<Checkbox name='photoInformation' text={background.photo_information} element='.other' />
<Header title={getMessage('modals.main.settings.sections.background.title')} setting='background' category='background' element='#backgroundImage'/>
<Checkbox name='ddgProxy' text={getMessage('modals.main.settings.sections.background.ddg_image_proxy')} element='.other' disabled={!usingImage} />
<Checkbox name='bgtransition' text={getMessage('modals.main.settings.sections.background.transition')} element='.other' disabled={!usingImage} />
<Checkbox name='photoInformation' text={getMessage('modals.main.settings.sections.background.photo_information')} element='.other' disabled={this.state.backgroundType !== 'api' && this.state.backgroundType !== 'marketplace'} />
<Checkbox name='photoMap' text={getMessage('modals.main.settings.sections.background.show_map')} element='.other' disabled={this.state.backgroundAPI !== 'unsplash'}/>
<h3>{background.source.title}</h3>
<Dropdown label={background.type.title} name='backgroundType' onChange={(value) => this.setState({ backgroundType: value })} category='background'>
{this.marketplaceType()}
<option value='api'>{background.type.api}</option>
<option value='custom'>{background.type.custom_image}</option>
<option value='colour'>{background.type.custom_colour}</option>
<h3>{getMessage('modals.main.settings.sections.background.source.title')}</h3>
<Dropdown label={getMessage('modals.main.settings.sections.background.type.title')} name='backgroundType' onChange={(value) => this.setState({ backgroundType: value })} category='background'>
{this.state.marketplaceEnabled ? <option value='photo_pack'>{this.getMessage('modals.main.navbar.marketplace')}</option> : null}
<option value='api'>{getMessage('modals.main.settings.sections.background.type.api')}</option>
<option value='custom'>{getMessage('modals.main.settings.sections.background.type.custom_image')}</option>
<option value='colour'>{getMessage('modals.main.settings.sections.background.type.custom_colour')}</option>
<option value='random_colour'>{getMessage('modals.main.settings.sections.background.type.random_colour')}</option>
<option value='random_gradient'>{getMessage('modals.main.settings.sections.background.type.random_gradient')}</option>
</Dropdown>
<br/>
{backgroundSettings}
<h3>{background.buttons.title}</h3>
<Checkbox name='view' text={background.buttons.view} category='navbar' />
<Checkbox name='favouriteEnabled' text={background.buttons.favourite} category='navbar' />
<Checkbox name='downloadbtn' text={background.buttons.download} element='.other' />
<h3>{background.effects.title}</h3>
<Slider title={background.effects.blur} name='blur' min='0' max='100' default='0' display='%' category='background' element='#backgroundImage' />
<Slider title={background.effects.brightness} name='brightness' min='0' max='100' default='90' display='%' category='background' element='#backgroundImage' />
<br/><br/>
<Dropdown label={background.effects.filters.title} name='backgroundFilter' category='background' element='#backgroundImage'>
<option value='grayscale'>{background.effects.filters.grayscale}</option>
<option value='sepia'>{background.effects.filters.sepia}</option>
<option value='invert'>{background.effects.filters.invert}</option>
<option value='saturate'>{background.effects.filters.saturate}</option>
<option value='contrast'>{background.effects.filters.contrast}</option>
</Dropdown>
<Slider title={background.effects.filters.amount} name='backgroundFilterAmount' min='0' max='100' default='0' display='%' category='background' element='#backgroundImage' />
{this.state.backgroundType === 'api' && APISettings && this.state.backgroundAPI === 'mue' ?
<>
<h3>{getMessage('modals.main.settings.sections.background.buttons.title')}</h3>
<Checkbox name='downloadbtn' text={getMessage('modals.main.settings.sections.background.buttons.download')} element='.other' />
</>
: null}
{this.state.backgroundType === 'api' || this.state.backgroundType === 'custom' || this.state.marketplaceEnabled ?
<>
<h3>{getMessage('modals.main.settings.sections.background.effects.title')}</h3>
<Slider title={getMessage('modals.main.settings.sections.background.effects.blur')} name='blur' min='0' max='100' default='0' display='%' marks={values('background')} category='background' element='#backgroundImage' />
<Slider title={getMessage('modals.main.settings.sections.background.effects.brightness')} name='brightness' min='0' max='100' default='90' display='%' marks={values('background')} category='background' element='#backgroundImage' />
<br/>
<Dropdown label={getMessage('modals.main.settings.sections.background.effects.filters.title')} name='backgroundFilter' onChange={(value) => this.setState({ backgroundFilter: value })} category='background' element='#backgroundImage'>
<option value='none'>{getMessage('modals.main.settings.sections.appearance.navbar.refresh_options.none')}</option>
<option value='grayscale'>{getMessage('modals.main.settings.sections.background.effects.filters.grayscale')}</option>
<option value='sepia'>{getMessage('modals.main.settings.sections.background.effects.filters.sepia')}</option>
<option value='invert'>{getMessage('modals.main.settings.sections.background.effects.filters.invert')}</option>
<option value='saturate'>{getMessage('modals.main.settings.sections.background.effects.filters.saturate')}</option>
<option value='contrast'>{getMessage('modals.main.settings.sections.background.effects.filters.contrast')}</option>
</Dropdown>
{this.state.backgroundFilter !== 'none' ?
<Slider title={getMessage('modals.main.settings.sections.background.effects.filters.amount')} name='backgroundFilterAmount' min='0' max='100' default='0' display='%' marks={values('background')} category='background' element='#backgroundImage' />
: null}
</>
: null}
</>
);
}

View File

@@ -1,9 +1,10 @@
import variables from 'modules/variables';
import { PureComponent, Fragment } from 'react';
import { ColorPicker } from 'react-color-gradient-picker';
import { toast } from 'react-toastify';
import hexToRgb from '../../../../../../modules/helpers/background/hexToRgb';
import rgbToHex from '../../../../../../modules/helpers/background/rgbToHex';
import hexToRgb from 'modules/helpers/background/hexToRgb';
import rgbToHex from 'modules/helpers/background/rgbToHex';
import 'react-color-gradient-picker/dist/index.css';
import '../../../scss/settings/react-color-picker-gradient-picker-custom-styles.scss';
@@ -11,13 +12,14 @@ import '../../../scss/settings/react-color-picker-gradient-picker-custom-styles.
export default class ColourSettings extends PureComponent {
DefaultGradientSettings = { angle: '180', gradient: [{ colour: '#ffb032', stop: 0 }], type: 'linear' };
GradientPickerInitalState = undefined;
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
gradientSettings: this.DefaultGradientSettings
};
this.language = window.language.modals.main.settings;
}
resetColour() {
@@ -25,7 +27,7 @@ export default class ColourSettings extends PureComponent {
this.setState({
gradientSettings: this.DefaultGradientSettings
});
toast(window.language.toasts.reset);
toast(this.getMessage('toasts.reset'));
}
initialiseColourPickerState(gradientSettings) {
@@ -67,7 +69,7 @@ export default class ColourSettings extends PureComponent {
}
componentDidUpdate() {
localStorage.setItem('customBackgroundColour', document.getElementById('customBackgroundHex').value);
localStorage.setItem('customBackgroundColour', this.currentGradientSettings());
}
onGradientChange = (event, index) => {
@@ -83,11 +85,7 @@ export default class ColourSettings extends PureComponent {
return newState;
});
const reminderInfo = document.querySelector('.reminder-info');
if (reminderInfo.style.display !== 'block') {
reminderInfo.style.display = 'block';
localStorage.setItem('showReminder', true);
}
this.showReminder();
}
addColour = () => {
@@ -102,18 +100,18 @@ export default class ColourSettings extends PureComponent {
return newState;
});
window.stats.postEvent('setting', 'Changed backgroundtype from colour to gradient');
variables.stats.postEvent('setting', 'Changed backgroundtype from colour to gradient');
}
currentGradientSettings = () => {
if (typeof this.state.gradientSettings === 'object' && this.state.gradientSettings.gradient.every(g => g.colour !== this.language.sections.background.source.disabled)) {
if (typeof this.state.gradientSettings === 'object' && this.state.gradientSettings.gradient.every(g => g.colour !== this.getMessage('modals.main.settings.sections.background.source.disabled'))) {
const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
return JSON.stringify({
...this.state.gradientSettings,
gradient: [...this.state.gradientSettings.gradient.map(g => { return { ...g, stop: clampNumber(+g.stop, 0, 100) } })].sort((a, b) => (a.stop > b.stop) ? 1 : -1)
});
}
return this.language.sections.background.source.disabled;
return this.getMessage('modals.main.settings.sections.background.source.disabled');
}
onColourPickerChange = (attrs, name) => {
@@ -133,16 +131,18 @@ export default class ColourSettings extends PureComponent {
}
});
this.showReminder();
};
showReminder() {
const reminderInfo = document.querySelector('.reminder-info');
if (reminderInfo.style.display !== 'block') {
reminderInfo.style.display = 'block';
localStorage.setItem('showReminder', true);
}
};
}
render() {
const { background } = this.language.sections;
let colourSettings = null;
if (typeof this.state.gradientSettings === 'object') {
const gradientHasMoreThanOneColour = this.state.gradientSettings.gradient.length > 1;
@@ -175,15 +175,14 @@ export default class ColourSettings extends PureComponent {
colourSettings = (
<>
{gradientInputs}
{!gradientHasMoreThanOneColour ? (<><br/><br/><button type='button' className='add' onClick={this.addColour}>{background.source.add_colour}</button></>) : null}
{!gradientHasMoreThanOneColour ? (<><br/><br/><button type='button' className='add' onClick={this.addColour}>{this.getMessage('modals.main.settings.sections.background.source.add_colour')}</button></>) : null}
</>
);
}
return (
<>
<p>{background.source.custom_colour} <span className='modalLink' onClick={() => this.resetColour()}>{this.language.buttons.reset}</span></p>
<input id='customBackgroundHex' type='hidden' value={this.currentGradientSettings()} />
<p>{this.getMessage('modals.main.settings.sections.background.source.custom_colour')} <span className='modalLink' onClick={() => this.resetColour()}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
{colourSettings}
</>
);

View File

@@ -0,0 +1,141 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { toast } from 'react-toastify';
import { MdCancel, MdAddLink, MdAddPhotoAlternate, MdPersonalVideo } from 'react-icons/md';
import EventBus from 'modules/helpers/eventbus';
import Checkbox from '../../Checkbox';
import FileUpload from '../../FileUpload';
import Modal from 'react-modal';
import CustomURLModal from './CustomURLModal';
export default class CustomSettings extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
customBackground: this.getCustom(),
customURLModal: false
};
}
resetCustom = () => {
localStorage.setItem('customBackground', '[]');
this.setState({
customBackground: []
});
toast(this.getMessage('toasts.reset'));
EventBus.dispatch('refresh', 'background');
}
customBackground(e, text, index) {
const result = (text === true) ? e.target.value : e.target.result;
const customBackground = this.state.customBackground;
customBackground[index] = result;
this.setState({
customBackground
});
this.forceUpdate();
localStorage.setItem('customBackground', JSON.stringify(customBackground));
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
}
modifyCustomBackground(type, index) {
const customBackground = this.state.customBackground;
if (type === 'add') {
customBackground.push('');
} else {
customBackground.splice(index, 1);
}
this.setState({
customBackground
});
this.forceUpdate();
localStorage.setItem('customBackground', JSON.stringify(customBackground));
document.querySelector('.reminder-info').style.display = 'block';
localStorage.setItem('showReminder', true);
}
videoCheck(url) {
return url.startsWith('data:video/') || url.endsWith('.mp4') || url.endsWith('.webm') || url.endsWith('.ogg');
}
videoCustomSettings = () => {
const hasVideo = this.state.customBackground.filter(bg => this.videoCheck(bg));
if (hasVideo.length > 0) {
return (
<>
<Checkbox name='backgroundVideoLoop' text={this.getMessage('modals.main.settings.sections.background.source.loop_video')}/>
<Checkbox name='backgroundVideoMute' text={this.getMessage('modals.main.settings.sections.background.source.mute_video')}/>
</>
);
} else {
return null;
}
}
getCustom() {
let data;
try {
data = JSON.parse(localStorage.getItem('customBackground'));
} catch (e) {
data = [localStorage.getItem('customBackground')];
}
return data;
}
uploadCustomBackground() {
document.getElementById('bg-input').setAttribute('index', this.state.customBackground.length);
document.getElementById('bg-input').click();
// to fix loadFunction
this.setState({
currentBackgroundIndex: this.state.customBackground.length
});
}
addCustomURL(e) {
this.setState({
customURLModal: false,
currentBackgroundIndex: this.state.customBackground.length
});
this.customBackground({ target: { value: e }}, true, this.state.customBackground.length);
}
render() {
return (
<ul>
<p>{this.getMessage('modals.main.settings.sections.background.source.custom_background')} <span className='modalLink' onClick={this.resetCustom}>{this.getMessage('modals.main.settings.buttons.reset')}</span></p>
<div className='data-buttons-row'>
<button onClick={() => this.uploadCustomBackground()}>{this.getMessage('modals.main.settings.sections.background.source.add_background')} <MdAddPhotoAlternate/></button>
<button onClick={() => this.setState({ customURLModal: true })}>{this.getMessage('modals.main.settings.sections.background.source.add_url')} <MdAddLink/></button>
</div>
<div className='images-row'>
{this.state.customBackground.map((url, index) => (
<div style={{ backgroundImage: `url(${!this.videoCheck(url) ? this.state.customBackground[index] : ''})` }} key={index}>
{this.videoCheck(url) ? <MdPersonalVideo className='customvideoicon'/> : null}
{this.state.customBackground.length > 0 ? <button className='cleanButton' onClick={() => this.modifyCustomBackground('remove', index)}>
<MdCancel/>
</button> : null}
</div>
))}
</div>
<FileUpload id='bg-input' accept='image/jpeg, image/png, image/webp, image/webm, image/gif, video/mp4, video/webm, video/ogg' loadFunction={(e) => this.customBackground(e, false, this.state.currentBackgroundIndex)} />
{this.props.interval}
{this.videoCustomSettings()}
<Modal closeTimeoutMS={100} onRequestClose={() => this.setState({ customURLModal: false })} isOpen={this.state.customURLModal} className='Modal resetmodal mainModal' overlayClassName='Overlay resetoverlay' ariaHideApp={false}>
<CustomURLModal modalClose={(e) => this.addCustomURL(e)} modalCloseOnly={() => this.setState({ customURLModal: false })} />
</Modal>
</ul>
);
}
}

View File

@@ -0,0 +1,21 @@
import variables from 'modules/variables';
import { useState } from 'react';
import { MdAdd } from 'react-icons/md';
import { TextField } from '@mui/material';
export default function CustomURLModal({ modalClose, modalCloseOnly }) {
const [url, setURL] = useState();
return (
<>
<span className='closeModal' onClick={modalCloseOnly}>&times;</span>
<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.source.add_url')}</h1>
<TextField value={url} onChange={(e) => setURL(e.target.value)} varient='outlined'/>
<div className='resetfooter'>
<button className='round import' style={{ marginLeft: '5px' }} onClick={() => modalClose(url)}>
<MdAdd/>
</button>
</div>
</>
);
}

View File

@@ -1,3 +1,4 @@
import variables from 'modules/variables';
import Tabs from './backend/Tabs';
import Added from '../marketplace/sections/Added';
@@ -5,13 +6,13 @@ import Sideload from '../marketplace/sections/Sideload';
import Create from '../marketplace/sections/Create';
export default function Addons() {
const addons = window.language.modals.main.addons;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<Tabs>
<div label={addons.added} name='added'><Added/></div>
<div label={addons.sideload} name='sideload'><Sideload/></div>
<div label={addons.create.title} name='create'><Create/></div>
<div label={getMessage('modals.main.addons.added')} name='added'><Added/></div>
<div label={getMessage('modals.main.addons.sideload.title')} name='sideload'><Sideload/></div>
<div label={getMessage('modals.main.addons.create.title')} name='create'><Create/></div>
</Tabs>
);
}

View File

@@ -1,15 +1,16 @@
import variables from 'modules/variables';
import Tabs from './backend/Tabs';
import MarketplaceTab from '../marketplace/sections/Marketplace';
export default function Marketplace() {
const marketplace = window.language.modals.main.marketplace;
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<Tabs>
<div label={marketplace.photo_packs} name='photo_packs'><MarketplaceTab type='photo_packs'/></div>
<div label={marketplace.quote_packs} name='quote_packs'><MarketplaceTab type='quote_packs'/></div>
<div label={marketplace.preset_settings} name='preset_settings'><MarketplaceTab type='preset_settings'/></div>
<div label={getMessage('modals.main.marketplace.photo_packs')} name='photo_packs'><MarketplaceTab type='photo_packs'/></div>
<div label={getMessage('modals.main.marketplace.quote_packs')} name='quote_packs'><MarketplaceTab type='quote_packs'/></div>
<div label={getMessage('modals.main.marketplace.preset_settings')} name='preset_settings'><MarketplaceTab type='preset_settings'/></div>
</Tabs>
);
}

View File

@@ -1,49 +1,52 @@
import variables from 'modules/variables';
import Tabs from './backend/Tabs';
import About from '../settings/sections/About';
import Language from '../settings/sections/Language';
import Search from '../settings/sections/Search';
import Navbar from '../settings/sections/Navbar';
import Greeting from '../settings/sections/Greeting';
import Time from '../settings/sections/Time';
import Quote from '../settings/sections/Quote';
import Appearance from '../settings/sections/Appearance';
import Background from '../settings/sections/background/Background';
import Advanced from '../settings/sections/Advanced';
import Changelog from '../settings/sections/Changelog';
import Order from '../settings/sections/Order';
import Experimental from '../settings/sections/Experimental';
import QuickLinks from '../settings/sections/QuickLinks';
import Quote from '../settings/sections/Quote';
import Date from '../settings/sections/Date';
import Message from '../settings/sections/Message';
import Background from '../settings/sections/background/Background';
import Search from '../settings/sections/Search';
import Weather from '../settings/sections/Weather';
import Order from '../settings/sections/Order';
import Appearance from '../settings/sections/Appearance';
import Language from '../settings/sections/Language';
import Advanced from '../settings/sections/Advanced';
//import Keybinds from '../settings/sections/Keybinds';
import Stats from '../settings/sections/Stats';
import Experimental from '../settings/sections/Experimental';
import Changelog from '../settings/sections/Changelog';
import About from '../settings/sections/About';
export default function Settings() {
const { reminder, sections } = window.language.modals.main.settings;
const display = (localStorage.getItem('showReminder') === 'true') ? 'block' : 'none';
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
return (
<>
<Tabs>
<div label={sections.time.title} name='time'><Time/></div>
<div label={sections.quote.title} name='quote'><Quote/></div>
<div label={sections.greeting.title} name='greeting'><Greeting/></div>
<div label={sections.background.title} name='background'><Background/></div>
<div label={sections.search.title} name='search'><Search/></div>
<div label={sections.quicklinks.title} name='quicklinks'><QuickLinks/></div>
<div label={sections.weather.title} name='weather'><Weather/></div>
<div label={sections.appearance.title} name='appearance'><Appearance/></div>
<div label={sections.order.title} name='order'><Order/></div>
<div label={sections.language.title} name='language'><Language/></div>
<div label={sections.advanced.title} name='advanced'><Advanced/></div>
<div label={sections.stats.title} name='stats'><Stats/></div>
<div label={sections.experimental.title} name='experimental'><Experimental/></div>
<div label={sections.changelog} name='changelog'><Changelog/></div>
<div label={sections.about.title} name='about'><About/></div>
<div label={getMessage('modals.main.settings.sections.appearance.navbar.title')} name='navbar'><Navbar/></div>
<div label={getMessage('modals.main.settings.sections.greeting.title')} name='greeting'><Greeting/></div>
<div label={getMessage('modals.main.settings.sections.time.title')} name='time'><Time/></div>
<div label={getMessage('modals.main.settings.sections.quicklinks.title')} name='quicklinks'><QuickLinks/></div>
<div label={getMessage('modals.main.settings.sections.quote.title')} name='quote'><Quote/></div>
<div label={getMessage('modals.main.settings.sections.date.title')} name='date'><Date/></div>
<div label={getMessage('modals.main.settings.sections.message.title')} name='message'><Message/></div>
<div label={getMessage('modals.main.settings.sections.background.title')} name='background'><Background/></div>
<div label={getMessage('modals.main.settings.sections.search.title')} name='search'><Search/></div>
<div label={getMessage('modals.main.settings.sections.weather.title')} name='weather'><Weather/></div>
<div label={getMessage('modals.main.settings.sections.order.title')} name='order'><Order/></div>
<div label={getMessage('modals.main.settings.sections.appearance.title')} name='appearance'><Appearance/></div>
<div label={getMessage('modals.main.settings.sections.language.title')} name='language'><Language/></div>
<div label={getMessage('modals.main.settings.sections.advanced.title')} name='advanced'><Advanced/></div>
{/*<div label={getMessage('modals.main.settings.sections.keybinds.title')} name='keybinds'><Keybinds/></div>*/}
<div label={getMessage('modals.main.settings.sections.stats.title')} name='stats'><Stats/></div>
<div label={getMessage('modals.main.settings.sections.experimental.title')} name='experimental'><Experimental/></div>
<div label={getMessage('modals.main.settings.sections.changelog.title')} name='changelog'><Changelog/></div>
<div label={getMessage('modals.main.settings.sections.about.title')} name='about'><About/></div>
</Tabs>
<div className='reminder-info' style={{ display: display }}>
<h1>{reminder.title}</h1>
<p>{reminder.message}</p>
<button className='pinNote' onClick={() => window.location.reload()}>{window.language.modals.main.error_boundary.refresh}</button>
</div>
</>
);
}

View File

@@ -1,82 +1,89 @@
import variables from 'modules/variables';
import { memo } from 'react';
import {
SettingsRounded as Settings,
Widgets as Addons,
ShoppingBasket as Marketplace,
AccessAlarm as Time,
EmojiPeopleOutlined as Greeting,
FormatQuoteOutlined as Quote,
PhotoOutlined as Background,
Search,
FormatPaintOutlined as Appearance,
Translate as Language,
NewReleasesOutlined as Changelog,
InfoOutlined as About,
BugReportOutlined as Experimental,
List as Order,
CloudOutlined as Weather,
SettingsOutlined as Advanced,
Link as QuickLinks,
AssessmentOutlined as Stats,
Code as Sideload,
AddCircleOutline as Added,
CreateNewFolderOutlined as Create
} from '@material-ui/icons';
MdSettings as Settings,
MdWidgets as Addons,
MdShoppingBasket as Marketplace,
MdMenu as Navbar,
MdEmojiPeople as Greeting,
MdAccessAlarm as Time,
MdOutlineFormatQuote as Quote,
MdLink as QuickLinks,
MdDateRange as Date,
MdOutlineTextsms as Message,
MdOutlinePhoto as Background,
MdSearch,
MdCloudQueue as Weather,
MdList as Order,
MdFormatPaint as Appearance,
MdTranslate as Language,
MdOutlineSettings as Advanced,
MdBugReport as Experimental,
//KeyboardAltOutlined as Keybinds,
MdOutlineAssessment as Stats,
MdOutlineNewReleases as Changelog,
MdInfoOutline as About,
MdEvent as Reminder,
MdCode as Sideload,
MdAddCircleOutline as Added,
MdAddCircleOutline as Create
} from 'react-icons/md';
function Tab({ label, currentTab, onClick, navbarTab }) {
const getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
function Tab(props) {
let className = 'tab-list-item';
if (props.currentTab === props.label) {
if (currentTab === label) {
className += ' tab-list-active';
}
if (props.navbar === true) {
if (navbarTab === true) {
className = 'navbar-item';
if (props.currentTab === props.label) {
if (currentTab === label) {
className += ' navbar-item-active';
}
}
const settings = window.language.modals.main.settings.sections;
const { navbar, marketplace, addons } = window.language.modals.main;
let icon, divider;
switch (props.label) {
// Navbar
case navbar.settings: icon = <Settings/>; break;
case navbar.addons: icon = <Addons/>; break;
case navbar.marketplace: icon = <Marketplace/>; break;
switch (label) {
case getMessage('modals.main.navbar.settings'): icon = <Settings/>; break;
case getMessage('modals.main.navbar.addons'): icon = <Addons/>; break;
case getMessage('modals.main.navbar.marketplace'): icon = <Marketplace/>; break;
// Settings
case settings.time.title: icon = <Time/>; break;
case settings.greeting.title: icon = <Greeting/>; break;
case settings.quote.title: icon = <Quote/>; break;
case settings.background.title: icon = <Background/>; break;
case settings.search.title: icon = <Search/>; break;
case settings.weather.title: icon = <Weather/>; break;
case settings.quicklinks.title: icon = <QuickLinks/>; break;
case settings.appearance.title: icon = <Appearance/>; break;
case settings.order.title: icon = <Order/>; break;
case settings.language.title: icon = <Language/>; divider = true; break;
case settings.advanced.title: icon = <Advanced/>; break;
case settings.stats.title: icon = <Stats/>; break;
case settings.experimental.title: icon = <Experimental/>; divider = true; break;
case settings.changelog: icon = <Changelog/>; break;
case settings.about.title: icon = <About/>; break;
case getMessage('modals.main.settings.sections.appearance.navbar.title'): icon = <Navbar/>; break;
case getMessage('modals.main.settings.sections.greeting.title'): icon = <Greeting/>; break;
case getMessage('modals.main.settings.sections.time.title'): icon = <Time/>; break;
case getMessage('modals.main.settings.sections.quicklinks.title'): icon = <QuickLinks/>; break;
case getMessage('modals.main.settings.sections.quote.title'): icon = <Quote/>; break;
case getMessage('modals.main.settings.sections.date.title'): icon = <Date/>; break;
case getMessage('modals.main.settings.sections.message.title'): icon = <Message/>; break;
case getMessage('modals.main.settings.sections.background.title'): icon = <Background/>; break;
case getMessage('modals.main.settings.sections.search.title'): icon = <MdSearch/>; break;
case getMessage('modals.main.settings.sections.weather.title'): icon = <Weather/>; divider = true; break;
case getMessage('modals.main.settings.sections.order.title'): icon = <Order/>; break;
// Addons
case addons.added: icon = <Added/>; break;
case addons.sideload: icon = <Sideload/>; break;
case addons.create.title: icon = <Create/>; break;
case getMessage('modals.main.settings.sections.appearance.title'): icon = <Appearance/>; break;
case getMessage('modals.main.settings.sections.language.title'): icon = <Language/>; divider = true; break;
case getMessage('modals.main.settings.sections.advanced.title'): icon = <Advanced/>; break;
//case getMessage('modals.main.settings.sections.keybinds.title'): icon = <Keybinds/>; break;
case getMessage('modals.main.settings.sections.stats.title'): icon = <Stats/>; break;
case getMessage('modals.main.settings.sections.experimental.title'): icon = <Experimental/>; divider = true; break;
case getMessage('modals.main.settings.sections.changelog.title'): icon = <Changelog/>; break;
case getMessage('modals.main.settings.sections.about.title'): icon = <About/>; break;
// Marketplace
case marketplace.photo_packs: icon = <Background/>; break;
case marketplace.quote_packs: icon = <Quote/>; break;
case marketplace.preset_settings: icon = <Advanced/>; break;
case getMessage('modals.main.addons.added'): icon = <Added/>; break;
case getMessage('modals.main.addons.sideload.title'): icon = <Sideload/>; break;
case getMessage('modals.main.addons.create.title'): icon = <Create/>; break;
case getMessage('modals.main.marketplace.photo_packs'): icon = <Background/>; break;
case getMessage('modals.main.marketplace.quote_packs'): icon = <Quote/>; break;
case getMessage('modals.main.marketplace.preset_settings'): icon = <Advanced/>; break;
default: break;
}
if (props.label === settings.experimental.title) {
if (label === getMessage('modals.main.settings.sections.experimental.title')) {
if (localStorage.getItem('experimental') === 'false') {
return <hr/>;
}
@@ -84,8 +91,8 @@ function Tab(props) {
return (
<>
<li className={className} onClick={() => props.onClick(props.label)}>
{icon} <span>{props.label}</span>
<li className={className} onClick={() => onClick(label)}>
{icon} <span>{label}</span>
</li>
{(divider === true) ? <hr/> : null}
</>

View File

@@ -1,3 +1,4 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import Tab from './Tab';
@@ -15,7 +16,7 @@ export default class Tabs extends PureComponent {
onClick = (tab, name) => {
if (name !== this.state.currentName) {
window.stats.postEvent('tab', `Opened ${name}`);
variables.stats.postEvent('tab', `Opened ${name}`);
}
this.setState({
@@ -27,7 +28,7 @@ export default class Tabs extends PureComponent {
render() {
let className = 'sidebar';
let tabClass = 'tab-content';
let optionsText = (<h1>{window.language.modals.main.title}</h1>);
let optionsText = (<h1>{variables.language.getMessage(variables.languagecode, 'modals.main.title')}</h1>);
if (this.props.navbar) {
className = 'modalNavbar';
@@ -45,7 +46,7 @@ export default class Tabs extends PureComponent {
key={index}
label={tab.props.label}
onClick={(nextTab) => this.onClick(nextTab, tab.props.name)}
navbar={this.props.navbar || false}
navbarTab={this.props.navbar || false}
/>
))}
</ul>

View File

@@ -1,15 +1,15 @@
export default function ProgressBar(props) {
export default function ProgressBar({ count, currentTab, switchTab }) {
return (
<div className='progressbar'>
{props.count.map((num) => {
{count.map((num) => {
let className = 'step';
const index = props.count.indexOf(num);
if (index === props.currentTab) {
const index = count.indexOf(num);
if (index === currentTab) {
className = 'step active';
}
return <div className={className} key={index} onClick={() => props.switchTab(index)}></div>;
return <div className={className} key={index} onClick={() => switchTab(index)}></div>;
})}
</div>
);

View File

@@ -1,6 +1,7 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import EventBus from '../../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
import WelcomeSections from './WelcomeSections';
import ProgressBar from './ProgressBar';
@@ -8,15 +9,16 @@ import ProgressBar from './ProgressBar';
import './welcome.scss';
export default class WelcomeModal extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
image: './././icons/undraw_celebration.svg',
currentTab: 0,
finalTab: 4,
buttonText: window.language.modals.welcome.buttons.next
buttonText: this.getMessage('modals.welcome.buttons.next')
};
this.language = window.language.modals.welcome;
this.images = [
'./././icons/undraw_celebration.svg',
'./././icons/undraw_around_the_world_modified.svg',
@@ -35,18 +37,18 @@ export default class WelcomeModal extends PureComponent {
return this.setState({
currentTab: this.state.currentTab - 1,
image: this.images[this.state.currentTab - 1],
buttonText: this.language.buttons.next
buttonText: this.getMessage('modals.welcome.buttons.next')
});
}
if (this.state.buttonText === this.language.buttons.close) {
if (this.state.buttonText === this.getMessage('modals.main.addons.create.finish.title')) {
return this.props.modalClose();
}
this.setState({
currentTab: this.state.currentTab + 1,
image: this.images[this.state.currentTab + 1],
buttonText: (this.state.currentTab !== this.state.finalTab) ? this.language.buttons.next : this.language.buttons.close
buttonText: (this.state.currentTab !== this.state.finalTab) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
});
}
@@ -55,7 +57,7 @@ export default class WelcomeModal extends PureComponent {
this.setState({
currentTab: tab,
image: this.images[tab],
buttonText: (tab !== this.state.finalTab + 1) ? this.language.buttons.next : this.language.buttons.close
buttonText: (tab !== this.state.finalTab + 1) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
});
localStorage.setItem('bgtransition', true);
@@ -68,7 +70,7 @@ export default class WelcomeModal extends PureComponent {
this.setState({
currentTab: Number(welcomeTab),
image: this.images[Number(welcomeTab)],
buttonText: (Number(welcomeTab) !== this.state.finalTab + 1) ? this.language.buttons.next : this.language.buttons.close
buttonText: (Number(welcomeTab) !== this.state.finalTab + 1) ? this.getMessage('modals.welcome.buttons.next') : this.getMessage('modals.main.addons.create.finish.title')
});
}
@@ -89,7 +91,7 @@ export default class WelcomeModal extends PureComponent {
return (
<div className='welcomeContent'>
<section>
<img className='showcaseimg' alt='celebration' draggable={false} src={this.state.image} />
<img className='showcaseimg' alt='sidebar icon' draggable={false} src={this.state.image} />
<ProgressBar count={this.images} currentTab={this.state.currentTab} switchTab={(tab) => this.switchTab(tab)}/>
</section>
<section>
@@ -97,7 +99,8 @@ export default class WelcomeModal extends PureComponent {
<WelcomeSections currentTab={this.state.currentTab} switchTab={(tab) => this.switchTab(tab)}/>
</div>
<div className='buttons'>
{(this.state.currentTab !== 0) ? <button className='close' style={{ marginRight: '20px' }} onClick={() => this.changeTab(true)}>{this.language.buttons.previous}</button> : null}
{(this.state.currentTab === 0) ? <button className='close' style={{ marginRight: '20px' }} onClick={() => this.props.modalSkip()}>{this.getMessage('modals.welcome.buttons.preview')}</button> : null}
{(this.state.currentTab !== 0) ? <button className='close' style={{ marginRight: '20px' }} onClick={() => this.changeTab(true)}>{this.getMessage('modals.welcome.buttons.previous')}</button> : null}
<button className='close' onClick={() => this.changeTab()}>{this.state.buttonText}</button>
</div>
</section>

View File

@@ -1,17 +1,20 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { CloudUpload, AutoAwesome, LightMode, DarkMode } from '@material-ui/icons';
import { MdCloudUpload, MdAutoAwesome, MdLightMode, MdDarkMode } from 'react-icons/md';
import Radio from '../main/settings/Radio';
import Checkbox from '../main/settings/Checkbox';
import FileUpload from '../main/settings/FileUpload';
import { loadSettings } from '../../../modules/helpers/settings';
import { importSettings } from '../../../modules/helpers/settings/modals';
import { loadSettings } from 'modules/helpers/settings';
import { importSettings } from 'modules/helpers/settings/modals';
const languages = require('../../../modules/languages.json');
const default_settings = require('../../../modules/default_settings.json');
const languages = require('modules/languages.json');
const default_settings = require('modules/default_settings.json');
export default class WelcomeSections extends PureComponent {
getMessage = (text) => variables.language.getMessage(variables.languagecode, text);
constructor() {
super();
this.state = {
@@ -25,7 +28,7 @@ export default class WelcomeSections extends PureComponent {
importedSettings: []
};
this.changeWelcomeImg = this.changeWelcomeImg.bind(this);
this.welcomeImages = ['./welcome-images/example1.webp', './welcome-images/example2.webp', './welcome-images/example3.webp', './welcome-images/example4.webp'];
this.welcomeImages = 4;
}
changeTheme(type) {
@@ -47,7 +50,7 @@ export default class WelcomeSections extends PureComponent {
importSettings(e) {
importSettings(e);
let settings = [];
const settings = [];
const data = JSON.parse(e.target.result);
Object.keys(data).forEach((setting) => {
// language and theme already shown, the others are only used internally
@@ -79,138 +82,133 @@ export default class WelcomeSections extends PureComponent {
let welcomeImage = this.state.welcomeImage;
this.setState({
welcomeImage: ++welcomeImage % this.welcomeImages.length
welcomeImage: ++welcomeImage % this.welcomeImages
});
this.timeout = setTimeout(this.changeWelcomeImg, 3 * 1000);
this.timeout = setTimeout(this.changeWelcomeImg, 3000);
}
componentDidMount() {
this.timeout = setTimeout(this.changeWelcomeImg, 3 * 1000);
this.timeout = setTimeout(this.changeWelcomeImg, 3000);
}
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
}
// cancel welcome image timer if not on welcome tab
componentDidUpdate() {
if (this.props.currentTab !== 0) {
if (this.props.currentTab !== 0) {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
} else {
if (!this.timeout) {
this.timeout = setTimeout(this.changeWelcomeImg, 3 * 1000);
}
} else if (!this.timeout) {
this.timeout = setTimeout(this.changeWelcomeImg, 3000);
}
}
render() {
const language = window.language.modals.welcome;
let tabContent;
render() {
const intro = (
<>
<h1>{language.sections.intro.title}</h1>
<p>{language.sections.intro.description}</p>
<h1>{this.getMessage('modals.welcome.sections.intro.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.intro.description')}</p>
<h3 className='quicktip'>#shareyourmue</h3>
<div className='examples'>
<img src={this.welcomeImages[this.state.welcomeImage]} alt='Example Mue setup' draggable={false}/>
<img src={`./welcome-images/example${[this.state.welcomeImage + 1]}.webp`} alt='Example Mue setup' draggable={false}/>
</div>
</>
);
const chooseLanguage = (
<>
<h1>{language.sections.language.title}</h1>
<p>{language.sections.language.description} <a href={window.constants.TRANSLATIONS_URL} className='resetLink' target='_blank' rel='noopener noreferrer'>GitHub</a>!</p>
<h1>{this.getMessage('modals.welcome.sections.language.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.language.description')} <a href={variables.constants.TRANSLATIONS_URL} className='resetLink' target='_blank' rel='noopener noreferrer'>GitHub</a>!</p>
<Radio name='language' options={languages} category='welcomeLanguage'/>
</>
);
const { appearance, advanced, background, quicklinks, stats } = window.language.modals.main.settings.sections;
const languageSettings = window.language.modals.main.settings.sections.language;
const theme = (
<>
<h1>{language.sections.theme.title}</h1>
<p>{language.sections.theme.description}</p>
<h1>{this.getMessage('modals.welcome.sections.theme.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.theme.description')}</p>
<div className='themesToggleArea'>
<div className={this.state.autoClass} onClick={() => this.changeTheme('auto')}>
<AutoAwesome/>
<span>{appearance.theme.auto}</span>
<MdAutoAwesome/>
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.auto')}</span>
</div>
<div className='options'>
<div className={this.state.lightClass} onClick={() => this.changeTheme('light')}>
<LightMode/>
<span>{appearance.theme.light}</span>
<MdLightMode/>
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.light')}</span>
</div>
<div className={this.state.darkClass} onClick={() => this.changeTheme('dark')}>
<DarkMode/>
<span>{appearance.theme.dark}</span>
<MdDarkMode/>
<span>{this.getMessage('modals.main.settings.sections.appearance.theme.dark')}</span>
</div>
</div>
<h3 className='quicktip'>{language.tip}</h3>
<p>{language.sections.theme.tip}</p>
<h3 className='quicktip'>{this.getMessage('modals.welcome.tip')}</h3>
<p>{this.getMessage('modals.welcome.sections.theme.tip')}</p>
</div>
</>
);
const settings = (
<>
<h1>{language.sections.settings.title}</h1>
<p>{language.sections.settings.description}</p>
<h1>{this.getMessage('modals.welcome.sections.settings.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.settings.description')}</p>
<button className='upload' onClick={() => document.getElementById('file-input').click()}>
<CloudUpload/>
<MdCloudUpload/>
<br/>
<span>{window.language.modals.main.settings.buttons.import}</span>
<span>{this.getMessage('modals.main.settings.buttons.import')}</span>
</button>
<FileUpload id='file-input' accept='application/json' type='settings' loadFunction={(e) => this.importSettings(e)}/>
<h3 className='quicktip'>{language.tip}</h3>
<p>{language.sections.settings.tip}</p>
<h3 className='quicktip'>{this.getMessage('modals.welcome.tip')}</h3>
<p>{this.getMessage('modals.welcome.sections.settings.tip')}</p>
</>
);
const privacy = (
<>
<h1>{language.sections.privacy.title}</h1>
<p>{language.sections.privacy.description}</p>
<Checkbox name='offlineMode' text={advanced.offline_mode} element='.other' />
<p>{language.sections.privacy.offline_mode_description}</p>
<Checkbox name='quicklinksddgProxy' text={background.ddg_image_proxy + ' (' + quicklinks.title + ')'}/>
<Checkbox name='ddgProxy' text={background.ddg_image_proxy + ' (' + background.title + ')'}/>
<p>{language.sections.privacy.ddg_proxy_description}</p>
<Checkbox name='stats' text={stats.usage}/>
<p>{language.sections.privacy.stats_description}</p>
<h3 className='quicktip'>{language.sections.privacy.links.title}</h3>
<a className='privacy' href={window.constants.PRIVACY_URL} target='_blank' rel='noopener noreferrer'>{language.sections.privacy.links.privacy_policy}</a>
<h1>{this.getMessage('modals.welcome.sections.privacy.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.privacy.description')}</p>
<Checkbox name='offlineMode' text={this.getMessage('modals.main.settings.sections.advanced.offline_mode')} element='.other' />
<p>{this.getMessage('modals.welcome.sections.privacy.offline_mode_description')}</p>
<Checkbox name='quicklinksddgProxy' text={this.getMessage('modals.main.settings.sections.background.ddg_image_proxy') + ' (' + this.getMessage('modals.main.settings.sections.quicklinks.title') + ')'}/>
<Checkbox name='ddgProxy' text={this.getMessage('modals.main.settings.sections.background.ddg_image_proxy') + ' (' +this.getMessage('modals.main.settings.sections.background.title') + ')'}/>
<p>{this.getMessage('modals.welcome.sections.privacy.ddg_proxy_description')}</p>
<h3 className='quicktip'>{this.getMessage('modals.welcome.sections.privacy.links.title')}</h3>
<a className='privacy' href={variables.constants.PRIVACY_URL} target='_blank' rel='noopener noreferrer'>{this.getMessage('modals.welcome.sections.privacy.links.privacy_policy')}</a>
<br/><br/>
<a className='privacy' href={'https://github.com/' + window.constants.ORG_NAME} target='_blank' rel='noopener noreferrer'>{language.sections.privacy.links.source_code}</a>
<a className='privacy' href={'https://github.com/' + variables.constants.ORG_NAME} target='_blank' rel='noopener noreferrer'>{this.getMessage('modals.welcome.sections.privacy.links.source_code')}</a>
</>
);
const final = (
<>
<h1>{language.sections.final.title}</h1>
<p>{language.sections.final.description}</p>
<h3 className='quicktip'>{language.sections.final.changes}</h3>
<p>{language.sections.final.changes_description}</p>
<h1>{this.getMessage('modals.welcome.sections.final.title')}</h1>
<p>{this.getMessage('modals.welcome.sections.final.description')}</p>
<h3 className='quicktip'>{this.getMessage('modals.welcome.sections.final.changes')}</h3>
<p>{this.getMessage('modals.welcome.sections.final.changes_description')}</p>
<div className='themesToggleArea'>
<div className='toggle' onClick={() => this.props.switchTab(1)}><span>{languageSettings.title}: {languages.find((i) => i.value === localStorage.getItem('language')).name}</span></div>
<div className='toggle' onClick={() => this.props.switchTab(3)}><span>{appearance.theme.title}: {this.getSetting('theme')}</span></div>
{(this.state.importedSettings.length !== 0) ? <div className='toggle' onClick={() => this.props.switchTab(2)}>{language.sections.final.imported} {this.state.importedSettings.length} {language.sections.final.settings}</div> : null}
<div className='toggle' onClick={() => this.props.switchTab(1)}><span>{this.getMessage('modals.main.settings.sections.language.title')}: {languages.find((i) => i.value === localStorage.getItem('language')).name}</span></div>
<div className='toggle' onClick={() => this.props.switchTab(3)}><span>{this.getMessage('modals.main.settings.sections.appearance.theme.title')}: {this.getSetting('theme')}</span></div>
{(this.state.importedSettings.length !== 0) ? <div className='toggle' onClick={() => this.props.switchTab(2)}>{this.getMessage('modals.main.settings.sections.final.imported', { amount: this.state.importedSettings.length })} {this.state.importedSettings.length}</div> : null}
</div>
</>
);
switch (this.props.currentTab) {
case 1: tabContent = chooseLanguage; break;
case 2: tabContent = settings; break;
case 3: tabContent = theme; break;
case 4: tabContent = privacy; break;
case 5: tabContent = final; break;
case 1: return chooseLanguage;
case 2: return settings;
case 3: return theme;
case 4: return privacy;
case 5: return final;
// 0
default: tabContent = intro;
default: return intro;
}
return tabContent;
}
}

View File

@@ -67,7 +67,7 @@
background: #8395a7;
height: 4px;
margin: 10px;
transition: .2s ease;
transition: 0.2s ease;
cursor: pointer;
border-radius: 15px;
}
@@ -77,27 +77,38 @@
}
}
.themesToggleArea {
.active {
background: var(--tab-active) !important;
background: var(--tab-active);
}
.toggle {
background: var(--sidebar);
text-align: center;
border-radius: 40px;
border-radius: 20px;
padding: 20px;
margin: 10px;
border: 3px solid var(--tab-active);
display: flex;
flex-direction: column;
align-items: center;
align-content: center;
justify-content: center;
cursor: pointer;
&:hover {
background: var(--tab-active);
cursor: pointer;
}
span {
font-size: 1rem;
}
svg {
font-size: 2.5em;
}
}
.auto {
@@ -123,6 +134,31 @@
}
}
.upload {
width: 100%;
height: 100%;
border-radius: 20px;
border: none;
outline: none;
padding: 50px;
background: var(--sidebar);
color: var(--modal-text);
cursor: pointer;
border: 3px solid var(--tab-active);
&:hover {
background: var(--tab-active);
}
svg {
font-size: 4em;
}
span {
font-size: 2em;
}
}
a.privacy {
text-decoration: none;
color: var(--modal-text);
@@ -153,18 +189,22 @@ a.privacy {
height: auto;
}
@media only screen and (max-width: 1440px) {
.buttons {
position: relative !important;
bottom: 0rem !important;
@media (max-width: 1820px) and (min-width: 1200px) {
.welcomemodal {
width: 85%;
height: 90%;
}
.examples img {
width: 15rem !important;
section {
height: 90vh !important;
}
}
@media only screen and (max-width: 1600px) {
@media (max-width: 1300px) {
.welcomemodal {
overflow-x: hidden !important;
}
.examples img {
width: 20rem !important;
}
@@ -172,5 +212,32 @@ a.privacy {
.buttons {
position: relative !important;
bottom: 1rem !important;
right: -1rem !important;
}
section {
height: 100vh !important;
}
}
@media (max-width: 1190px) {
.welcomemodal {
width: 90%;
height: 90%;
}
}
@media (max-width: 800px) {
.welcomemodal {
width: 100%;
height: 100%;
}
.examples img {
width: 15rem !important;
}
section {
height: 140vh !important;
}
}

View File

@@ -6,8 +6,9 @@ import Quote from './quote/Quote';
import Search from './search/Search';
import QuickLinks from './quicklinks/QuickLinks';
import Date from './time/Date';
import Message from './message/Message';
import EventBus from '../../modules/helpers/eventbus';
import EventBus from 'modules/helpers/eventbus';
const Weather = lazy(() => import('./weather/Weather'));
const renderLoader = () => <></>;
@@ -17,7 +18,8 @@ export default class Widgets extends PureComponent {
constructor() {
super();
this.state = {
order: JSON.parse(localStorage.getItem('order'))
order: JSON.parse(localStorage.getItem('order')),
welcome: localStorage.getItem('showWelcome')
};
// widgets we can re-order
this.widgets = {
@@ -25,7 +27,8 @@ export default class Widgets extends PureComponent {
greeting: this.enabled('greeting') ? <Greeting/> : null,
quote: this.enabled('quote') ? <Quote/> : null,
date: this.enabled('date') ? <Date/> : null,
quicklinks: this.enabled('quicklinksenabled') && this.online ? <QuickLinks/> : null
quicklinks: this.enabled('quicklinksenabled') && this.online ? <QuickLinks/> : null,
message: this.enabled('message') ? <Message/> : null
};
}
@@ -40,12 +43,29 @@ export default class Widgets extends PureComponent {
order: JSON.parse(localStorage.getItem('order'))
});
}
if (data === 'widgetsWelcome') {
this.setState({
welcome: localStorage.getItem('showWelcome')
});
localStorage.setItem('showWelcome', true);
window.onbeforeunload = () => {
localStorage.clear();
}
}
if (data === 'widgetsWelcomeDone') {
this.setState({
welcome: localStorage.getItem('showWelcome')
});
window.onbeforeunload = null;
}
});
}
render() {
// don't show when welcome is there
if (localStorage.getItem('showWelcome') !== 'false') {
if (this.state.welcome !== 'false') {
return <div id='widgets'></div>;
}
@@ -58,7 +78,7 @@ export default class Widgets extends PureComponent {
});
} else {
// prevent error
elements = [<Greeting/>, <Clock/>, <QuickLinks/>, <Quote/>, <Date/>];
elements = [<Greeting/>, <Clock/>, <QuickLinks/>, <Quote/>, <Date/>, <Message/>];
}
return (

View File

@@ -1,11 +1,12 @@
// todo: rewrite this mess
import variables from 'modules/variables';
import { PureComponent } from 'react';
import PhotoInformation from './PhotoInformation';
import EventBus from '../../../modules/helpers/eventbus';
import Interval from '../../../modules/helpers/interval';
import { videoCheck, offlineBackground, gradientStyleBuilder } from '../../../modules/helpers/background/widget';
import EventBus from 'modules/helpers/eventbus';
import Interval from 'modules/helpers/interval';
import { videoCheck, offlineBackground, getGradient, randomColourStyleBuilder } from 'modules/helpers/background/widget';
import './scss/index.scss';
@@ -23,22 +24,22 @@ export default class Background extends PureComponent {
photoURL: ''
}
};
this.language = window.language.widgets.background;
}
setBackground() {
const backgroundImage = document.getElementById('backgroundImage');
if (this.state.url !== '') {
const url = (localStorage.getItem('ddgProxy') === 'true' && this.state.photoInfo.offline !== true && !this.state.url.startsWith('data:')) ? window.constants.DDG_IMAGE_PROXY + this.state.url : this.state.url;
let url = this.state.url;
if (localStorage.getItem('ddgProxy') === 'true' && this.state.photoInfo.offline !== true && !this.state.url.startsWith('data:')) {
url = variables.constants.DDG_IMAGE_PROXY + this.state.url;
}
const photoInformation = document.querySelector('.photoInformation');
// just set the background
if (localStorage.getItem('bgtransition') === 'false') {
if (photoInformation) {
photoInformation.style.display = 'block';
}
backgroundImage.style.background = null;
photoInformation?.[photoInformation.style.display = 'block'];
return backgroundImage.style.background = `url(${url})`;
}
@@ -47,9 +48,7 @@ export default class Background extends PureComponent {
backgroundImage.style.background = null;
// same with photo information if not using custom background
if (photoInformation) {
photoInformation.classList.add('backgroundPreload');
}
photoInformation?.classList.add('backgroundPreload');
// preloader for background transition, required so it loads in nice
const preloader = document.createElement('img');
@@ -82,44 +81,53 @@ export default class Background extends PureComponent {
offline = true;
}
const setFavourited = (favourited) => {
const setFavourited = ({ type, url, credit, location, camera }) => {
console.log(type)
if (type === 'random_colour' || type === 'random_gradient') {
return this.setState({
type: 'colour',
style: `background:${url}`
});
}
this.setState({
url: favourited.url,
url,
photoInfo: {
credit: favourited.credit,
location: favourited.location,
camera: favourited.camera
credit,
location,
camera
}
});
}
switch (localStorage.getItem('backgroundType')) {
const favourited = JSON.parse(localStorage.getItem('favourite'));
if (favourited) {
return setFavourited(favourited);
}
const type = localStorage.getItem('backgroundType');
switch (type) {
case 'api':
if (offline) {
return this.setState(offlineBackground());
}
const favourited = JSON.parse(localStorage.getItem('favourite'));
if (favourited) {
return setFavourited(favourited);
}
// API background
const backgroundAPI = localStorage.getItem('backgroundAPI');
const apiCategory = localStorage.getItem('apiCategory');
const apiQuality = localStorage.getItem('apiQuality');
const photoMap = (localStorage.getItem('photoMap') === 'true');
let requestURL, data;
switch (backgroundAPI) {
case 'unsplash':
requestURL = `${window.constants.PROXY_URL}/images/unsplash?quality=${apiQuality}`;
requestURL = `${variables.constants.PROXY_URL}/images/unsplash?quality=${apiQuality}&map=${photoMap}`;
break;
case 'pexels':
requestURL = `${window.constants.PROXY_URL}/images/pexels?quality=${apiQuality}`;
requestURL = `${variables.constants.PROXY_URL}/images/pexels?quality=${apiQuality}`;
break;
// Defaults to Mue
default:
requestURL = `${window.constants.API_URL}/images/random?category=${apiCategory}&quality=${apiQuality}`;
requestURL = `${variables.constants.API_URL}/images/random?category=${apiCategory}&quality=${apiQuality}`;
break;
}
@@ -130,15 +138,9 @@ export default class Background extends PureComponent {
return this.setState(offlineBackground());
}
let credit = data.photographer;
let photoURL, photographerURL;
if (backgroundAPI === 'unsplash') {
credit = data.photographer + ` ${this.language.unsplash}`;
photoURL = data.photo_page;
photographerURL = data.photographer_page;
} else if (backgroundAPI === 'pexels') {
credit = data.photographer + ` ${this.language.pexels}`;
if (backgroundAPI === 'unsplash' || backgroundAPI === 'pexels') {
photoURL = data.photo_page;
photographerURL = data.photographer_page;
}
@@ -149,59 +151,72 @@ export default class Background extends PureComponent {
currentAPI: backgroundAPI,
photoInfo: {
hidden: false,
credit: credit,
credit: data.photographer,
location: data.location,
camera: data.camera,
url: data.file,
photographerURL: photographerURL,
photoURL: photoURL
photographerURL,
photoURL,
latitude: data.latitude || null,
longitude: data.longitude || null,
// location map token from mapbox
maptoken: data.maptoken || null
}
};
this.setState(object);
localStorage.setItem('currentBackground', JSON.stringify(object));
break;
break;
case 'colour':
const customBackgroundColour = localStorage.getItem('customBackgroundColour') || {'angle':'180','gradient':[{'colour':'#ffb032','stop':0}],'type':'linear'};
let gradientSettings = '';
try {
gradientSettings = JSON.parse(customBackgroundColour);
} catch (e) {
const hexColorRegex = /#[0-9a-fA-F]{6}/s;
if (hexColorRegex.exec(customBackgroundColour)) {
// Colour use to be simply a hex colour or a NULL value before it was a JSON object. This automatically upgrades the hex colour value to the new standard. (NULL would not trigger an exception)
gradientSettings = { 'type': 'linear', 'angle': '180', 'gradient': [{ 'colour': customBackgroundColour, 'stop': 0 }] };
localStorage.setItem('customBackgroundColour', JSON.stringify(gradientSettings));
}
const gradient = getGradient();
if (gradient) {
this.setState(gradient);
}
break;
if (typeof gradientSettings === 'object' && gradientSettings !== null) {
return this.setState(gradientStyleBuilder(gradientSettings));
}
break;
case 'random_colour':
case 'random_gradient':
this.setState(randomColourStyleBuilder(type));
break;
case 'custom':
const customBackground = localStorage.getItem('customBackground');
let customBackground = [];
const customSaved = localStorage.getItem('customBackground');
try {
customBackground = JSON.parse(customSaved);
} catch (e) {
if (customSaved !== '') {
// move to new format
customBackground = [customSaved];
}
localStorage.setItem('customBackground', JSON.stringify(customBackground));
}
// pick random
customBackground = customBackground[Math.floor(Math.random() * customBackground.length)];
// allow users to use offline images
if (offline && !customBackground.startsWith('data:')) {
return this.setState(offlineBackground());
}
if (customBackground !== '' && customBackground !== 'undefined') {
this.setState({
if (customBackground !== '' && customBackground !== 'undefined' && customBackground !== [''] && customBackground !== undefined) {
const object = {
url: customBackground,
type: 'custom',
video: videoCheck(customBackground),
photoInfo: {
hidden: true
}
});
};
this.setState(object);
localStorage.setItem('currentBackground', JSON.stringify(object));
}
break;
break;
case 'photo_pack':
if (offline) {
@@ -226,7 +241,7 @@ export default class Background extends PureComponent {
}
});
}
break;
break;
default:
break;
}
@@ -292,24 +307,23 @@ export default class Background extends PureComponent {
if (backgroundType !== this.state.type || (this.state.type === 'api' && localStorage.getItem('backgroundAPI') !== this.state.currentAPI) || (this.state.type === 'custom' && localStorage.getItem('customBackground') !== this.state.url)) {
return refresh();
}
} else {
if (backgroundType !== this.state.type) {
return refresh();
}
} else if (backgroundType !== this.state.type) {
return refresh();
}
// background effects so we don't get another image again
const backgroundFilter = localStorage.getItem('backgroundFilter');
const backgroundFilterSetting = localStorage.getItem('backgroundFilter');
const backgroundFilter = backgroundFilterSetting && backgroundFilterSetting !== 'none';
if (this.state.video === true) {
document.getElementById('backgroundVideo').style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
document.getElementById('backgroundVideo').style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
} else {
element.style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
element.style.webkitFilter = `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilterSetting + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}`;
}
}
// uninstall photo pack reverts your background to what you had previously
if (data === 'marketplacebackgrounduninstall' || data === 'backgroundwelcome') {
if (data === 'marketplacebackgrounduninstall' || data === 'backgroundwelcome' || data === 'backgroundrefresh') {
refresh();
}
});
@@ -320,7 +334,9 @@ export default class Background extends PureComponent {
const interval = localStorage.getItem('backgroundchange');
if (interval && interval !== 'refresh') {
if (localStorage.getItem('backgroundType') === 'api') {
const type = localStorage.getItem('backgroundType');
if (type === 'api' || type === 'custom') {
Interval(() => {
try {
document.getElementById('backgroundImage').classList.remove('fade-in');
@@ -334,6 +350,9 @@ export default class Background extends PureComponent {
try {
// todo: refactor this mess
const current = JSON.parse(localStorage.getItem('currentBackground'));
if (current.type !== type) {
this.getBackground();
}
const offline = localStorage.getItem('offlineMode');
if (current.url.startsWith('http') && offline === 'false') {
this.setState(current);
@@ -385,7 +404,7 @@ export default class Background extends PureComponent {
return (
<>
<div style={{ WebkitFilter: `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter ? backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)' : ''}` }} id='backgroundImage'/>
<div style={{ WebkitFilter: `blur(${localStorage.getItem('blur')}px) brightness(${localStorage.getItem('brightness')}%) ${backgroundFilter && backgroundFilter !== 'none' ? (backgroundFilter + '(' + localStorage.getItem('backgroundFilterAmount') + '%)') : ''}` }} id='backgroundImage'/>
{(this.state.photoInfo.credit !== '') ?
<PhotoInformation info={this.state.photoInfo} api={this.state.currentAPI} url={this.state.url}/>
: null}

View File

@@ -1,12 +1,14 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Star, StarBorder } from '@material-ui/icons';
import { MdStar, MdStarBorder } from 'react-icons/md';
//import Hotkeys from 'react-hot-keys';
import Tooltip from '../../helpers/tooltip/Tooltip';
import Tooltip from 'components/helpers/tooltip/Tooltip';
export default class Favourite extends PureComponent {
buttons = {
favourited: <Star onClick={() => this.favourite()} className='topicons' />,
unfavourited: <StarBorder onClick={() => this.favourite()} className='topicons' />
favourited: <MdStar onClick={() => this.favourite()} className='topicons' />,
unfavourited: <MdStarBorder onClick={() => this.favourite()} className='topicons' />
}
constructor() {
@@ -22,39 +24,65 @@ export default class Favourite extends PureComponent {
this.setState({
favourited: this.buttons.unfavourited
});
window.stats.postEvent('feature', 'Background favourite');
variables.stats.postEvent('feature', 'Background favourite');
} else {
const url = document.getElementById('backgroundImage').style.backgroundImage.replace('url("', '').replace('")', '');
const type = localStorage.getItem('backgroundType');
switch (type) {
case 'colour':
return;
case 'random_colour':
case 'random_gradient':
localStorage.setItem('favourite', JSON.stringify({
type: localStorage.getItem('backgroundType'),
url: document.getElementById('backgroundImage').style.background
}));
break;
default:
const url = document.getElementById('backgroundImage').style.backgroundImage.replace('url("', '').replace('")', '').replace(variables.constants.DDG_IMAGE_PROXY, '');
if (!url) {
return;
if (!url) {
return;
}
if (type === 'custom') {
localStorage.setItem('favourite', JSON.stringify({
type,
url
}));
} else {
// photo information now hides information if it isn't sent, unless if photoinformation hover is hidden
const location = document.getElementById('infoLocation');
const camera = document.getElementById('infoCamera');
localStorage.setItem('favourite', JSON.stringify({
type,
url,
credit: document.getElementById('credit').textContent || '',
location: location ? location.innerText : 'N/A',
camera: camera ? camera.innerText : 'N/A',
resolution: document.getElementById('infoResolution').textContent || '',
}));
}
}
// photo information now hides information if it isn't sent, unless if photoinformation hover is hidden
const location = document.getElementById('infoLocation');
const camera = document.getElementById('infoCamera');
localStorage.setItem('favourite', JSON.stringify({
url: url,
credit: document.getElementById('credit').textContent,
location: location ? location.innerText : 'N/A',
camera: camera ? camera.innerText : 'N/A',
resolution: document.getElementById('infoResolution').textContent
}));
this.setState({
favourited: this.buttons.favourited
});
window.stats.postEvent('feature', 'Background unfavourite');
variables.stats.postEvent('feature', 'Background unfavourite');
}
}
render() {
const backgroundType = localStorage.getItem('backgroundType');
if (backgroundType === 'colour' || backgroundType === 'custom') {
if (backgroundType === 'colour') {
return null;
}
return <Tooltip title={window.language.modals.main.settings.sections.background.buttons.favourite}>{this.state.favourited}</Tooltip>;
return (
<Tooltip title={variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.buttons.favourite')}>
{this.state.favourited}
{/*variables.keybinds.favouriteBackground && variables.keybinds.favouriteBackground !== '' ? <Hotkeys keyName={variables.keybinds.favouriteBackground} onKeyDown={() => this.favourite()} /> : null*/}
</Tooltip>
);
}
}

View File

@@ -1,7 +1,9 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { Fullscreen } from '@material-ui/icons';
import { MdCropFree } from 'react-icons/md';
//import Hotkeys from 'react-hot-keys';
import Tooltip from '../../helpers/tooltip/Tooltip';
import Tooltip from 'components/helpers/tooltip/Tooltip';
export default class Maximise extends PureComponent {
constructor() {
@@ -14,7 +16,7 @@ export default class Maximise extends PureComponent {
setAttribute(blur, brightness, filter) {
// don't attempt to modify the background if it isn't an image
const backgroundType = localStorage.getItem('backgroundType');
if (backgroundType === 'colour') {
if (backgroundType === 'colour' || backgroundType === 'random_colour' || backgroundType === 'random_gradient') {
return;
}
@@ -42,21 +44,22 @@ export default class Maximise extends PureComponent {
});
this.setAttribute(0, 100);
window.stats.postEvent('feature', 'Background maximise');
variables.stats.postEvent('feature', 'Background maximise');
} else {
this.setState({
hidden: false
});
this.setAttribute(localStorage.getItem('blur'), localStorage.getItem('brightness'), true);
window.stats.postEvent('feature', 'Background unmaximise');
variables.stats.postEvent('feature', 'Background unmaximise');
}
}
render() {
return (
<Tooltip title={window.language.modals.main.settings.sections.background.buttons.view}>
<Fullscreen onClick={this.maximise} className='topicons' />
<Tooltip title={variables.language.getMessage(variables.languagecode, 'modals.main.settings.sections.background.buttons.view')}>
<MdCropFree onClick={this.maximise} className='topicons' />
{/*variables.keybinds.maximiseBackground && variables.keybinds.maximiseBackground !== '' ? <Hotkeys keyName={variables.keybinds.maximiseBackground} onKeyDown={this.maximise} /> : null*/}
</Tooltip>
);
}

View File

@@ -1,5 +1,14 @@
import variables from 'modules/variables';
import { useState, Fragment } from 'react';
import { Info, LocationOn, PhotoCamera, Crop as Resolution, Person as Photographer, GetApp as Download } from '@material-ui/icons';
import {
MdInfo,
MdLocationOn,
MdPhotoCamera,
MdCrop as Resolution,
MdPerson as Photographer,
MdGetApp as Download
} from 'react-icons/md';
//import Hotkeys from 'react-hot-keys';
const toDataURL = async (url) => {
const res = await fetch(url);
@@ -17,43 +26,46 @@ const downloadImage = async (info) => {
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.stats.postEvent('feature', 'Background download');
variables.stats.postEvent('feature', 'Background download');
};
export default function PhotoInformation(props) {
export default function PhotoInformation({ info, url, api }) {
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const [usePhotoMap, setPhotoMap] = useState(false);
const language = window.language.widgets.background;
if (props.info.hidden === true || !props.info.credit) {
if (info.hidden === true || !info.credit) {
return null;
}
// remove unsplash and pexels text
const photographer = props.info.credit.split(` ${language.unsplash}`)[0].split(` ${language.pexels}`);
const unsplash = variables.language.getMessage(variables.languagecode, 'widgets.background.unsplash');
const pexels = variables.language.getMessage(variables.languagecode, 'widgets.background.pexels');
const photographer = info.credit.split(` ${unsplash}`)[0].split(` ${pexels}`);
let credit = props.info.credit;
let photo = language.credit;
let credit = info.credit;
let photo = variables.language.getMessage(variables.languagecode, 'widgets.background.credit');
// unsplash and pexels credit
if (props.info.photographerURL && props.info.photographerURL !== '' && !props.info.offline && props.api) {
if (props.api === 'unsplash') {
photo = <a href={props.info.photoURL + '?utm_source=mue'} target='_blank' rel='noopener noreferrer'>{language.credit}</a>;
credit = <><a href={props.info.photographerURL} target='_blank' rel='noopener noreferrer'>{photographer}</a> <a href='https://unsplash.com?utm_source=mue' target='_blank' rel='noopener noreferrer'>{language.unsplash}</a></>;
if (info.photographerURL && info.photographerURL !== '' && !info.offline && api) {
if (api === 'unsplash') {
photo = <a href={info.photoURL + '?utm_source=mue'} target='_blank' rel='noopener noreferrer'>{photo}</a>;
credit = <><a href={info.photographerURL} target='_blank' rel='noopener noreferrer'>{info.credit}</a> <a href='https://unsplash.com?utm_source=mue' target='_blank' rel='noopener noreferrer'>{unsplash}</a></>;
} else {
photo = <a href={props.info.photoURL} target='_blank' rel='noopener noreferrer'>{language.credit}</a>;
credit = <><a href={props.info.photographerURL} target='_blank' rel='noopener noreferrer'>{photographer}</a> <a href='https://pexels.com' target='_blank' rel='noopener noreferrer'>{language.pexels}</a></>;
photo = <a href={info.photoURL} target='_blank' rel='noopener noreferrer'>{photo}</a>;
credit = <><a href={info.photographerURL} target='_blank' rel='noopener noreferrer'>{info.credit}</a> <a href='https://pexels.com' target='_blank' rel='noopener noreferrer'>{pexels}</a></>;
}
}
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 = (localStorage.getItem('ddgProxy') === 'true' && !props.info.offline && !props.url.startsWith('data:')) ? window.constants.DDG_IMAGE_PROXY + props.url : props.url;
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') {
@@ -61,42 +73,92 @@ export default function PhotoInformation(props) {
<div className='photoInformation'>
<h1>{photo} <span id='credit'>{credit}</span></h1>
<div style={{ display: 'none' }}>
<span id='infoLocation'>{props.info.location || 'N/A'}</span>
<span id='infoCamera'>{props.info.camera || 'N/A'}</span>
<span id='infoLocation'>{info.location || 'N/A'}</span>
<span id='infoCamera'>{info.camera || 'N/A'}</span>
<span id='infoResolution'>{width}x{height}</span>
</div>
</div>
);
}
const downloadEnabled = (localStorage.getItem('downloadbtn') === 'true') && !info.offline && !info.photographerURL && api;
const downloadBackground = () => {
if (downloadEnabled) {
downloadImage(info);
}
};
const showBackgroundInformation = () => {
const element = document.querySelector('.infoCard');
if (element) {
if (element.style.display === 'none' || element.style.display === '') {
element.style.display = 'block';
} else {
element.style.display = 'none';
}
}
};
const photoMap = () => {
if (localStorage.getItem('photoMap') !== 'true' || !info.latitude || !info.longitude || usePhotoMap === false) {
return null;
}
const zoom = 12;
const tile = `${variables.constants.MAPBOX_URL}/styles/v1/mapbox/streets-v11/static/pin-s+555555(${info.longitude},${info.latitude})/${info.longitude},${info.latitude},${zoom},0/300x100?access_token=${info.maptoken}`;
return (
<Fragment key='photomap'>
<a href={`${variables.constants.OPENSTREETMAP_URL}/?mlat=${info.latitude}&mlon=${info.longitude}`} target='_blank' rel='noopener noreferrer'>
<img className='locationMap' src={tile} alt='location' draggable={false}/>
</a>
<br/>
<span className='mapCopyright'>
<a href='https://www.mapbox.com/about/maps/' target='_blank' rel='noopener noreferrer'> © Mapbox</a>, <a href='https://www.openstreetmap.org/about/' target='_blank' rel='noopener noreferrer'>© OpenStreetMap</a>. <a href='https://www.mapbox.com/map-feedback/' target='_blank' rel='noopener noreferrer'>Improve this map</a>.
</span>
</Fragment>
);
}
// only request map image if the user looks at the photo information
// this is to reduce requests to the api
try {
document.getElementsByClassName('photoInformation')[0].onmouseover = () => {
setPhotoMap(true);
}
} catch (e) {}
return (
<div className='photoInformation'>
<h1>{photo} <span id='credit'>{credit}</span></h1>
<Info className='photoInformationHover'/>
<MdInfo className='photoInformationHover'/>
<div className='infoCard'>
<Info className='infoIcon'/>
<h1>{language.information}</h1>
<MdInfo className='infoIcon'/>
<h1>{variables.language.getMessage(variables.languagecode, 'widgets.background.information')}</h1>
<hr/>
{photoMap()}
{/* fix console error by using fragment and key */}
{props.info.location && props.info.location !== 'N/A' ? <Fragment key='location'>
<LocationOn/>
<span id='infoLocation'>{props.info.location}</span>
{info.location && info.location !== 'N/A' ? <Fragment key='location'>
<MdLocationOn/>
<span id='infoLocation'>{info.location}</span>
</Fragment> : null}
{props.info.camera && props.info.camera !== 'N/A' ? <Fragment key='camera'>
<PhotoCamera/>
<span id='infoCamera'>{props.info.camera}</span>
{info.camera && info.camera !== 'N/A' ? <Fragment key='camera'>
<MdPhotoCamera/>
<span id='infoCamera'>{info.camera}</span>
</Fragment> : null}
<Resolution/>
<span id='infoResolution'>{width}x{height}</span>
<Photographer/>
<span>{photographer}</span>
{(localStorage.getItem('downloadbtn') === 'true') && !props.info.offline && !props.info.photographerURL ?
{downloadEnabled ?
<>
<Download/>
<span className='download' onClick={() => downloadImage(props.info)}>{language.download}</span>
<span className='download' onClick={() => downloadImage(info)}>{variables.language.getMessage(variables.languagecode, 'widgets.background.download')}</span>
</>
: null}
</div>
{/*variables.keybinds.downloadBackground && variables.keybinds.downloadBackground !== '' ? <Hotkeys keyName={variables.keybinds.downloadBackground} onKeyDown={() => downloadBackground()} /> : null*/}
{/*variables.keybinds.showBackgroundInformation && variables.keybinds.showBackgroundInformation !== '' ? <Hotkeys keyName={variables.keybinds.showBackgroundInformation} onKeyDown={() => showBackgroundInformation()} /> : null*/}
</div>
);
}

View File

@@ -55,13 +55,30 @@
padding: 2px;
}
.locationMap {
height: 100px;
object-fit: cover;
width: 100%;
background-position: center center;
background-repeat: no-repeat;
}
.mapboxLogo {
height: 20px;
width: auto;
}
span,
svg {
font-size: 2em;
}
span {
user-select: text;
}
h1,
.MuiSvgIcon-root {
svg {
user-select: none;
cursor: initial;
}
@@ -82,7 +99,7 @@
border: none;
}
&:hover,
&:hover,
span {
display: block !important;
}
@@ -95,4 +112,8 @@
opacity: 0.8;
}
}
.mapCopyright {
font-size: 0.9em;
}
}

View File

@@ -1,7 +1,8 @@
import { PureComponent } from 'react';
import variables from 'modules/variables';
import { PureComponent, createRef } from 'react';
import { nth, convertTimezone } from '../../../modules/helpers/date';
import EventBus from '../../../modules/helpers/eventbus';
import { nth, convertTimezone } from 'modules/helpers/date';
import EventBus from 'modules/helpers/eventbus';
import './greeting.scss';
@@ -12,7 +13,7 @@ export default class Greeting extends PureComponent {
greeting: ''
};
this.timer = undefined;
this.language = window.language.widgets.greeting;
this.greeting = createRef();
}
doEvents(time, message) {
@@ -26,13 +27,13 @@ export default class Greeting extends PureComponent {
// If it's December 25th, set the greeting string to "Merry Christmas"
if (month === 11 && date === 25) {
message = this.language.christmas;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.christmas');
// If the date is January 1st, set the greeting string to "Happy new year"
} else if (month === 0 && date === 1) {
message = this.language.newyear;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.newyear');
// If it's October 31st, set the greeting string to "Happy Halloween"
} else if (month === 9 && date === 31) {
message = this.language.halloween;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.halloween');
}
return message;
@@ -55,13 +56,13 @@ export default class Greeting extends PureComponent {
const hour = now.getHours();
// Set the default greeting string to "Good evening"
let message = this.language.evening;
let message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.evening');
// If it's before 12am, set the greeting string to "Good morning"
if (hour < 12) {
message = this.language.morning;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.morning');
// If it's before 6pm, set the greeting string to "Good afternoon"
} else if (hour < 18) {
message = this.language.afternoon;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.afternoon');
}
// Events and custom
@@ -94,10 +95,10 @@ export default class Greeting extends PureComponent {
if (birth.getDate() === now.getDate() && birth.getMonth() === now.getMonth()) {
if (localStorage.getItem('birthdayage') === 'true') {
const text = this.language.birthday.split(' ');
const text = variables.language.getMessage(variables.languagecode, 'widgets.greeting.birthday').split(' ');
message = `${text[0]} ${nth(this.calculateAge(birth))} ${text[1]}`;
} else {
message = this.language.birthday;
message = variables.language.getMessage(variables.languagecode, 'widgets.greeting.birthday');
}
}
}
@@ -114,23 +115,21 @@ export default class Greeting extends PureComponent {
componentDidMount() {
EventBus.on('refresh', (data) => {
if (data === 'greeting' || data === 'timezone') {
const element = document.querySelector('.greeting');
if (localStorage.getItem('greeting') === 'false') {
return element.style.display = 'none';
return this.greeting.current.style.display = 'none';
}
this.timer = null;
this.getGreeting(0);
element.style.display = 'block';
element.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
this.greeting.current.style.display = 'block';
this.greeting.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
}
});
// this comment can apply to all widget zoom features apart from the general one in the Accessibility section
// in a nutshell: 1.6 is the current font size and we do "localstorage || 100" so we don't have to try that 4.0 -> 5.0 thing again
document.querySelector('.greeting').style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
this.greeting.current.style.fontSize = `${1.6 * Number((localStorage.getItem('zoomGreeting') || 100) / 100)}em`;
this.getGreeting(0);
}
@@ -140,8 +139,10 @@ export default class Greeting extends PureComponent {
}
render() {
return <h1 className='greeting'>
{this.state.greeting}
</h1>;
return (
<h1 className='greeting' ref={this.greeting}>
{this.state.greeting}
</h1>
);
}
}

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