From 9a64fc7794cc9ba4d53c88f9d645a39cdc34291c Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Tue, 28 May 2024 16:51:37 +0300 Subject: [PATCH 1/6] fix(song): remove 0 play count --- app/views/components/song/song.templ | 4 +++- app/views/pages/playlist.templ | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/views/components/song/song.templ b/app/views/components/song/song.templ index 3de6e7f..ebe1174 100644 --- a/app/views/components/song/song.templ +++ b/app/views/components/song/song.templ @@ -58,7 +58,9 @@ templ Song(s entities.Song, additionalData []string, additionalOptions []templ.C

By { s.Artist }

for _, info := range additionalData { -

{ info }

+ if info != "" { +

{ info }

+ } }
diff --git a/app/views/pages/playlist.templ b/app/views/pages/playlist.templ index 621c787..5bbb223 100644 --- a/app/views/pages/playlist.templ +++ b/app/views/pages/playlist.templ @@ -258,10 +258,13 @@ css songThumb(url string) { } func playedTimes(times int) string { - if times == 1 { + switch { + case times == 1: return "Played once" - } else { + case times > 1: return fmt.Sprintf("Played %d times", times) + default: + return "" } } From 18b108bd97d72efb4c63e73dda7b2c38e9f6b303 Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Wed, 29 May 2024 01:29:05 +0300 Subject: [PATCH 2/6] fix(player): shuffle's behavior --- app/static/js/player.js | 128 +++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 22 deletions(-) diff --git a/app/static/js/player.js b/app/static/js/player.js index 54e9d2a..9601ae4 100644 --- a/app/static/js/player.js +++ b/app/static/js/player.js @@ -41,6 +41,7 @@ const playPauseToggleExapndedEl = document.getElementById("play-expand"), * @property {number} play_times * @property {string} added_at * @property {number} votes + * @property {number} order */ /** @@ -55,6 +56,7 @@ const playPauseToggleExapndedEl = document.getElementById("play-expand"), * @typedef {object} PlayerState * @property {LoopMode} loopMode * @property {boolean} shuffled + * @property {string} shuffledPlaylist * @property {Playlist} playlist * @property {number} currentSongIdx */ @@ -74,6 +76,7 @@ const LOOP_MODES = Object.freeze({ const playerState = { loopMode: LOOP_MODES.OFF, shuffled: false, + shuffledPlaylist: "", currentSongIdx: 0, playlist: { title: "Queue", @@ -227,13 +230,84 @@ function stopper(audioEl) { * @returns {Function} */ function shuffler(state) { - return () => { + // using Fisher–Yates shuffling algorithm https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + const __shuffleArray = (a) => { + let currIdx = a.length; + while (currIdx != 0) { + let randIdx = Math.floor(Math.random() * currIdx); + currIdx--; + [a[currIdx], a[randIdx]] = [a[randIdx], a[currIdx]]; + } + }; + + /** + * @param {string} songYtId + */ + const __shuffle = (songYtId) => { + if (isSingleSong()) { + return; + } + state.shuffledPlaylist = state.playlist.public_id; + const extraSongs = []; + state.playlist.songs.forEach((s) => { + for (let i = 0; i < s.votes - 1; i++) { + extraSongs.push(s); + } + }); + state.playlist.songs.push(...extraSongs); + __shuffleArray(state.playlist.songs); + let sIdx = 0; + if (!!audioPlayerEl.src) { + sIdx = state.playlist.songs.findIndex((s) => s.yt_id === songYtId); + if (sIdx !== -1) { + [state.playlist.songs[sIdx], state.playlist.songs[0]] = [ + state.playlist.songs[0], + state.playlist.songs[sIdx], + ]; + } + } + state.currentSongIdx = 0; + }; + + const __toggleShuffle = () => { state.shuffled = !state.shuffled; + if (state.shuffled) { + shuffle( + audioPlayerEl.src.substring( + audioPlayerEl.src.lastIndexOf("/") + 1, + audioPlayerEl.src.length - 4, + ), + ); + } else { + const tmp = state.playlist.songs.sort((si, sj) => si.order - sj.order); + state.playlist.songs = []; + for (let i = 0; i < tmp.length - 1; i++) { + if (tmp[i].yt_id === tmp[i + 1].yt_id) { + continue; + } + state.playlist.songs.push(tmp[i]); + } + if (tmp[tmp.length - 1].yt_id !== tmp[tmp.length - 2]) { + state.playlist.songs.push(tmp[tmp.length - 1]); + } + if (!!audioPlayerEl.src) { + state.currentSongIdx = state.playlist.songs.findIndex( + (s) => + s.yt_id === + audioPlayerEl.src.substring( + audioPlayerEl.src.lastIndexOf("/") + 1, + audioPlayerEl.src.length - 4, + ), + ); + } + } setPlayerButtonIcon( shuffleEl, state.shuffled ? Player.icons.shuffle : Player.icons.shuffleOff, ); }; + + return [__shuffle, __toggleShuffle]; } /** @@ -269,7 +343,10 @@ function playlister(state) { return; } // chack votes to whether repeat the song or not. - if (state.playlist.songs[state.currentSongIdx].votes > 1) { + if ( + state.playlist.songs[state.currentSongIdx].votes > 1 && + !state.shuffled + ) { const songToPlay = state.playlist.songs[state.currentSongIdx]; songToPlay.votes--; songToPlay.plays++; @@ -280,7 +357,6 @@ function playlister(state) { if ( !checkLoop(LOOP_MODES.ALL) && - !state.shuffled && state.currentSongIdx + 1 >= state.playlist.songs.length ) { stopMuzikk(); @@ -288,15 +364,15 @@ function playlister(state) { for (const s of state.playlist.songs) { if (!!s.plays) { s.votes = s.plays; + s.plays = 0; } } return; } - state.currentSongIdx = state.shuffled - ? Math.floor(Math.random() * state.playlist.songs.length) - : checkLoop(LOOP_MODES.ALL) && - state.currentSongIdx + 1 >= state.playlist.songs.length + state.currentSongIdx = + checkLoop(LOOP_MODES.ALL) && + state.currentSongIdx + 1 >= state.playlist.songs.length ? 0 : state.currentSongIdx + 1; const songToPlay = state.playlist.songs[state.currentSongIdx]; @@ -312,7 +388,10 @@ function playlister(state) { return; } // chack votes to whether repeat the song or not. - if (state.playlist.songs[state.currentSongIdx].votes > 1) { + if ( + state.playlist.songs[state.currentSongIdx].votes > 1 && + !state.shuffled + ) { const songToPlay = state.playlist.songs[state.currentSongIdx]; songToPlay.votes--; songToPlay.plays++; @@ -320,23 +399,19 @@ function playlister(state) { __setSongInPlaylistStyle(songToPlay.yt_id, state.playlist); return; } - if ( - !checkLoop(LOOP_MODES.ALL) && - !state.shuffled && - state.currentSongIdx - 1 < 0 - ) { + if (!checkLoop(LOOP_MODES.ALL) && state.currentSongIdx - 1 < 0) { stopMuzikk(); // reset songs' votes for (const s of state.playlist.songs) { if (!!s.plays) { s.votes = s.plays; + s.plays = 0; } } return; } - state.currentSongIdx = state.shuffled - ? Math.floor(Math.random() * state.playlist.songs.length) - : checkLoop(LOOP_MODES.ALL) && state.currentSongIdx - 1 < 0 + state.currentSongIdx = + checkLoop(LOOP_MODES.ALL) && state.currentSongIdx - 1 < 0 ? state.playlist.songs.length - 1 : state.currentSongIdx - 1; const songToPlay = state.playlist.songs[state.currentSongIdx]; @@ -565,20 +640,29 @@ function playSingleSong(song) { * @param {Playlist} playlist */ function playSongFromPlaylist(songYtId, playlist) { + if ( + playerState.shuffled && + playerState.shuffledPlaylist !== playlist.public_id + ) { + playerState.playlist = playlist; + shuffle(songYtId); + } const songIdx = playlist.songs.findIndex((s) => s.yt_id === songYtId); if (songIdx < 0) { alert("Invalid song!"); return; } - playerState.playlist = playlist; - playerState.playlist.songs = playlist.songs.map((s) => { - return { ...s, plays: 0 }; - }); + if (!playerState.shuffled) { + playerState.playlist = playlist; + playerState.playlist.songs = playlist.songs.map((s, idx) => { + return { ...s, plays: 0, order: idx }; + }); + } playerState.currentSongIdx = songIdx; if (playerState.playlist.songs[songIdx].votes === 0) { playerState.currentSongIdx++; } - const songToPlay = playlist.songs[songIdx]; + const songToPlay = playlist.songs[playerState.currentSongIdx]; highlightSongInPlaylist(songToPlay.yt_id, playlist); playSong(songToPlay); } @@ -634,7 +718,7 @@ function setMediaSessionMetadata(song) { const [toggleLoop, handleLoop, checkLoop] = looper(); const [playMuzikk, pauseMuzikk, togglePP] = playPauser(audioPlayerEl); const stopMuzikk = stopper(audioPlayerEl); -const toggleShuffle = shuffler(playerState); +const [shuffle, toggleShuffle] = shuffler(playerState); const [ nextMuzikk, previousMuzikk, From 8bcdeeec673df65011017430cc37106f33d39909 Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Wed, 29 May 2024 13:33:26 +0300 Subject: [PATCH 3/6] chore(errors): add some client error message --- app/handlers/apis/email_login.go | 16 ++++++------ app/handlers/pages/pages.go | 42 ++++++++++++++++++++++--------- app/static/images/error-img.webp | Bin 0 -> 38954 bytes 3 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 app/static/images/error-img.webp diff --git a/app/handlers/apis/email_login.go b/app/handlers/apis/email_login.go index 24cec19..028e8fe 100644 --- a/app/handlers/apis/email_login.go +++ b/app/handlers/apis/email_login.go @@ -37,7 +37,7 @@ func (e *emailLoginApi) HandleEmailLogin(w http.ResponseWriter, r *http.Request) log.Errorf("[EMAIL LOGIN API]: Failed to login user: %+v, error: %s\n", reqBody, err.Error()) // w.WriteHeader(http.StatusInternalServerError) status. - GenericError(fmt.Sprintf("No account associated with the email \"%s\" was found", reqBody.Email)). + BugsBunnyError(fmt.Sprintf("No account associated with the email \"%s\" was found", reqBody.Email)). Render(context.Background(), w) return } @@ -66,7 +66,7 @@ func (e *emailLoginApi) HandleEmailSignup(w http.ResponseWriter, r *http.Request log.Errorf("[EMAIL LOGIN API]: Failed to sign up a new user: %+v, error: %s\n", reqBody, err.Error()) // w.WriteHeader(http.StatusConflict) status. - GenericError(fmt.Sprintf("An account associated with the email \"%s\" already exists", reqBody.Email)). + BugsBunnyError(fmt.Sprintf("An account associated with the email \"%s\" already exists", reqBody.Email)). Render(context.Background(), w) return } @@ -95,14 +95,14 @@ func (e *emailLoginApi) HandleEmailOTPVerification(w http.ResponseWriter, r *htt if err != nil { // w.Write([]byte("Invalid verification token")) status. - GenericError("Invalid verification token"). + BugsBunnyError("Invalid verification token"). Render(context.Background(), w) return } if verificationToken.Expires.After(time.Now().UTC()) { // w.Write([]byte("Expired verification token")) status. - GenericError("Expired verification token"). + BugsBunnyError("Expired verification token"). Render(context.Background(), w) return } @@ -113,7 +113,7 @@ func (e *emailLoginApi) HandleEmailOTPVerification(w http.ResponseWriter, r *htt log.Error(err) // w.WriteHeader(http.StatusBadRequest) status. - GenericError("Invalid verification token"). + BugsBunnyError("Invalid verification token"). Render(context.Background(), w) return } @@ -121,13 +121,13 @@ func (e *emailLoginApi) HandleEmailOTPVerification(w http.ResponseWriter, r *htt sessionToken, err := e.service.VerifyOtp(verificationToken.Value, reqBody) if errors.Is(err, login.ErrExpiredVerificationCode) { status. - GenericError("Expired verification code!"). + BugsBunnyError("Expired verification code!"). Render(context.Background(), w) return } if errors.Is(err, login.ErrInvalidVerificationCode) { status. - GenericError("Invalid verification code!"). + BugsBunnyError("Invalid verification code!"). Render(context.Background(), w) return } @@ -135,7 +135,7 @@ func (e *emailLoginApi) HandleEmailOTPVerification(w http.ResponseWriter, r *htt log.Error(err) // w.WriteHeader(http.StatusInternalServerError) status. - GenericError("Something went wrong..."). + BugsBunnyError("Something went wrong..."). Render(context.Background(), w) return } diff --git a/app/handlers/pages/pages.go b/app/handlers/pages/pages.go index 2d7cbf5..84f9a7a 100644 --- a/app/handlers/pages/pages.go +++ b/app/handlers/pages/pages.go @@ -13,6 +13,7 @@ import ( "dankmuzikk/services/playlists" "dankmuzikk/services/youtube/download" "dankmuzikk/services/youtube/search" + "dankmuzikk/views/components/status" "dankmuzikk/views/layouts" "dankmuzikk/views/pages" "errors" @@ -21,10 +22,6 @@ import ( _ "github.com/a-h/templ" ) -const ( - notFoundMessage = "🤷‍♂️ I have no idea about what you requested!" -) - type pagesHandler struct { profileRepo db.GetterRepo[models.Profile] playlistsService *playlists.Service @@ -89,7 +86,9 @@ func (p *pagesHandler) HandleLoginPage(w http.ResponseWriter, r *http.Request) { func (p *pagesHandler) HandlePlaylistsPage(w http.ResponseWriter, r *http.Request) { profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint) if !profileIdCorrect { - w.Write([]byte(notFoundMessage)) + status. + BugsBunnyError("I'm not sure what you're trying to do :)"). + Render(context.Background(), w) return } @@ -110,27 +109,46 @@ func (p *pagesHandler) HandlePlaylistsPage(w http.ResponseWriter, r *http.Reques func (p *pagesHandler) HandleSinglePlaylistPage(w http.ResponseWriter, r *http.Request) { profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint) if !profileIdCorrect { - w.Write([]byte(notFoundMessage)) + status. + BugsBunnyError("I'm not sure what you're trying to do :)"). + Render(context.Background(), w) return } playlistPubId := r.PathValue("playlist_id") if playlistPubId == "" { - w.Write([]byte(notFoundMessage)) + status. + BugsBunnyError("You need to provide a playlist id!"). + Render(context.Background(), w) return } playlist, permission, err := p.playlistsService.Get(playlistPubId, profileId) + htmxReq := handlers.IsNoLayoutPage(r) switch { case errors.Is(err, playlists.ErrUnauthorizedToSeePlaylist): log.Errorln(err) - w.Write([]byte(notFoundMessage)) + if htmxReq { + status. + BugsBunnyError("You can't see this playlist!
(don't snoop around other people's stuff or else!)"). + Render(context.Background(), w) + } else { + layouts.Default("Error", + status. + BugsBunnyError("You can't see this playlist!
(don't snoop around other people's stuff or else!)")). + Render(r.Context(), w) + } return case err != nil: - if playlist.Title == "" { - log.Errorln(err) - w.Write([]byte(notFoundMessage)) - return + if htmxReq { + status. + BugsBunnyError("You can't see this playlist!
(it might be John Cena)"). + Render(context.Background(), w) + } else { + layouts.Default("Error", + status. + BugsBunnyError("You can't see this playlist!
(it might be John Cena)")). + Render(r.Context(), w) } } ctx := context.WithValue(r.Context(), handlers.PlaylistPermission, permission) diff --git a/app/static/images/error-img.webp b/app/static/images/error-img.webp new file mode 100644 index 0000000000000000000000000000000000000000..df93809716fff2bf95ee7e675f3ada2937d43c78 GIT binary patch literal 38954 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 W-~bID;7_6$dE9nCfj&=w0000w8sd)t literal 0 HcmV?d00001 From d73b323cd4d25c0519fbae1140ad50edbf2c9353 Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Wed, 29 May 2024 13:34:24 +0300 Subject: [PATCH 4/6] chore(background): remove background --- app/static/css/themes/black.css | 3 +-- app/static/css/themes/default.css | 3 +-- app/static/css/themes/white.css | 3 +-- .../components/status/bugs_bunny_error.templ | 18 ++++++++++++++++++ .../components/themeswitch/themeswitch.templ | 9 ++++----- app/views/layouts/default.templ | 11 +---------- app/views/layouts/raw.templ | 11 +---------- 7 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 app/views/components/status/bugs_bunny_error.templ diff --git a/app/static/css/themes/black.css b/app/static/css/themes/black.css index 4aec6f0..c0599c9 100644 --- a/app/static/css/themes/black.css +++ b/app/static/css/themes/black.css @@ -16,6 +16,5 @@ } body { - background-image: url("/static/images/dankground-dark.svg"); - background-color: var(--primary-color); + background-color: #131313; } diff --git a/app/static/css/themes/default.css b/app/static/css/themes/default.css index 309b2d0..a9aee15 100644 --- a/app/static/css/themes/default.css +++ b/app/static/css/themes/default.css @@ -16,6 +16,5 @@ } body { - background-image: url("/static/images/dankground.svg"); - background-color: var(--primary-color); + background-color: #5aa340; } diff --git a/app/static/css/themes/white.css b/app/static/css/themes/white.css index 327ae93..45305ba 100644 --- a/app/static/css/themes/white.css +++ b/app/static/css/themes/white.css @@ -16,6 +16,5 @@ } body { - background-image: url("/static/images/dankground-light.svg"); - background-color: var(--primary-color); + background-color: #ededed; } diff --git a/app/views/components/status/bugs_bunny_error.templ b/app/views/components/status/bugs_bunny_error.templ new file mode 100644 index 0000000..bd82a75 --- /dev/null +++ b/app/views/components/status/bugs_bunny_error.templ @@ -0,0 +1,18 @@ +package status + +import "strings" + +templ BugsBunnyError(msg string) { +
+ Error image +

+ for _, tok := range strings.Split(msg, " ") { + if tok == "\n" || tok == "
" { +
+ } else { + { tok + " " } + } + } +

+
+} diff --git a/app/views/components/themeswitch/themeswitch.templ b/app/views/components/themeswitch/themeswitch.templ index 609e0d7..9dcc4aa 100644 --- a/app/views/components/themeswitch/themeswitch.templ +++ b/app/views/components/themeswitch/themeswitch.templ @@ -64,7 +64,7 @@ script changeTheme(themeName string) { accent20: "#00000033", accent30: "#0000004c", accent69: "#000000b0", - bg: "/static/images/dankground.svg", + bg: "#5aa340", }, black: { primary: "#000000", @@ -79,7 +79,7 @@ script changeTheme(themeName string) { accent20: "#d3fcbf33", accent30: "#d3fcbf4C", accent69: "#d3fcbfB0", - bg: "/static/images/dankground-dark.svg", + bg: "#131313", }, white: { primary: "#ffffff", @@ -94,7 +94,7 @@ script changeTheme(themeName string) { accent20: "#d5ffc133", accent30: "#d5ffc14c", accent69: "#d5ffc1b0", - bg: "/static/images/dankground-light.svg", + bg: "#ededed", }, }; @@ -116,7 +116,6 @@ script changeTheme(themeName string) { style.setProperty('--accent-color-20', theme.accent20); style.setProperty('--accent-color-30', theme.accent30); style.setProperty('--accent-color-69', theme.accent69); - document.body.style.backgroundImage = `url('${theme.bg}')`; - document.body.style.backgroundColor = theme.primary; + document.body.style.backgroundColor = theme.bg; document.getElementById("popover-theme-switcher").style.display = "none"; } diff --git a/app/views/layouts/default.templ b/app/views/layouts/default.templ index 87daee5..5aceb7e 100644 --- a/app/views/layouts/default.templ +++ b/app/views/layouts/default.templ @@ -47,16 +47,7 @@ templ Default(title string, children ...templ.Component) { @header.Header()
diff --git a/app/views/layouts/raw.templ b/app/views/layouts/raw.templ index a6317fc..8533a94 100644 --- a/app/views/layouts/raw.templ +++ b/app/views/layouts/raw.templ @@ -44,16 +44,7 @@ templ Raw(title string, children ...templ.Component) {
for _, child := range children { From 54447204648406b202eda0c53826a040826e870f Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Wed, 29 May 2024 13:35:55 +0300 Subject: [PATCH 5/6] chore(background): remove background --- README.md | 3 +-- app/views/pages/about.templ | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b06294f..4be8841 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ IDK, it would be really nice of you to contribute, check the poorly written [CON - [ ] View/Edit queue - [ ] Expandable player - [x] Mobile - - [ ] Desktop + - [ ] Desktop - [ ] Share songs - [ ] Player's menu - [ ] Import **public** playlists from YouTube @@ -86,7 +86,6 @@ docker compose up -f docker-compose-dev.yml ## Acknowledgements - **This project is not affiliated with YouTube or Google, or anyone to that matter in any sort of ways.** -- The background was taken from [dankpods.net](https://dankpods.net) - Frank’s original image was taken from [dingusland.biz](https://dingusland.biz) - Colorscheme is inspired from [Dankpods](https://www.youtube.com/@DankPods) - youtube-scrape was used to search videos without using the actual YouTube API (small quota): MIT licenses by [Herman Fassett](https://github.com/HermanFassett) diff --git a/app/views/pages/about.templ b/app/views/pages/about.templ index 6f66ffa..c97537d 100644 --- a/app/views/pages/about.templ +++ b/app/views/pages/about.templ @@ -68,7 +68,6 @@ templ aboutContent() {
  • This project is not affiliated with YouTube or Google, or anyone to that matter in any sort of ways.

  • -
  • The background was taken from dankpods.net
  • Frank’s original image was taken from dingusland.biz
  • Colorscheme is inspired from @Dankpods
  • youtube-scrape was used to search videos without using the actual YouTube API (small quota): MIT licenses by Herman Fassett.
  • From 7559b4af60f9ec35b08151962bd16c91fae10440 Mon Sep 17 00:00:00 2001 From: Baraa Al-Masri Date: Wed, 29 May 2024 13:46:59 +0300 Subject: [PATCH 6/6] chore(background): remove files and update default color --- app/static/css/themes/default.css | 2 +- app/static/css/themes/white.css | 2 +- app/static/images/dankground-dark.svg | 10 ---------- app/static/images/dankground-light.svg | 10 ---------- app/static/images/dankground.svg | 16 ---------------- .../components/themeswitch/themeswitch.templ | 2 +- 6 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 app/static/images/dankground-dark.svg delete mode 100644 app/static/images/dankground-light.svg delete mode 100644 app/static/images/dankground.svg diff --git a/app/static/css/themes/default.css b/app/static/css/themes/default.css index a9aee15..7588bd6 100644 --- a/app/static/css/themes/default.css +++ b/app/static/css/themes/default.css @@ -16,5 +16,5 @@ } body { - background-color: #5aa340; + background-color: #305922; } diff --git a/app/static/css/themes/white.css b/app/static/css/themes/white.css index 45305ba..233cfae 100644 --- a/app/static/css/themes/white.css +++ b/app/static/css/themes/white.css @@ -16,5 +16,5 @@ } body { - background-color: #ededed; + background-color: #dedede; } diff --git a/app/static/images/dankground-dark.svg b/app/static/images/dankground-dark.svg deleted file mode 100644 index d2b587b..0000000 --- a/app/static/images/dankground-dark.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/app/static/images/dankground-light.svg b/app/static/images/dankground-light.svg deleted file mode 100644 index fc6b5c6..0000000 --- a/app/static/images/dankground-light.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/app/static/images/dankground.svg b/app/static/images/dankground.svg deleted file mode 100644 index 5cf167a..0000000 --- a/app/static/images/dankground.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/views/components/themeswitch/themeswitch.templ b/app/views/components/themeswitch/themeswitch.templ index 9dcc4aa..1c930f2 100644 --- a/app/views/components/themeswitch/themeswitch.templ +++ b/app/views/components/themeswitch/themeswitch.templ @@ -64,7 +64,7 @@ script changeTheme(themeName string) { accent20: "#00000033", accent30: "#0000004c", accent69: "#000000b0", - bg: "#5aa340", + bg: "#305922", }, black: { primary: "#000000",