diff --git a/src/static/views/assets/icons/scheme-dark.svg b/src/static/views/assets/icons/scheme-dark.svg index 0a6b3b48..f458ba3f 100644 --- a/src/static/views/assets/icons/scheme-dark.svg +++ b/src/static/views/assets/icons/scheme-dark.svg @@ -1,3 +1 @@ - - - + \ No newline at end of file diff --git a/src/static/views/assets/icons/scheme-light.svg b/src/static/views/assets/icons/scheme-light.svg index a29b905c..a3ae38ba 100644 --- a/src/static/views/assets/icons/scheme-light.svg +++ b/src/static/views/assets/icons/scheme-light.svg @@ -1,3 +1 @@ - - - + \ No newline at end of file diff --git a/src/static/views/assets/styles/global.css b/src/static/views/assets/styles/global.css index 7446ee28..212a125c 100644 --- a/src/static/views/assets/styles/global.css +++ b/src/static/views/assets/styles/global.css @@ -14,10 +14,6 @@ body { color: var(--primary); } -svg { - color: var(--primary-glass); -} - a { color: var(--primary); text-decoration-line: none; @@ -34,7 +30,6 @@ a { .title { display: flex; height: 50px; - flex-direction: row; align-items: center; font-size: 20px; font-weight: 500; @@ -51,7 +46,6 @@ a { flex-direction: column; align-items: flex-start; font-size: 14px; - font-weight: 200; gap: 10px; line-height: 17px; } @@ -86,3 +80,8 @@ a { align-items: center; gap: 10px; } + +.vertical_line { + height: 30px; + border-left: 0.5px solid var(--primary-glass); +} diff --git a/src/static/views/components/header/index.css b/src/static/views/components/header/index.css index 51a9ba9e..8b84323c 100644 --- a/src/static/views/components/header/index.css +++ b/src/static/views/components/header/index.css @@ -10,7 +10,6 @@ display: flex; width: 800px; height: 60px; - flex-direction: row; align-items: center; justify-content: space-between; gap: 25px; @@ -19,16 +18,16 @@ .header_menu { display: flex; - flex-direction: row; + align-items: center; gap: 25px; } .header_menu_item { display: flex; height: 25px; - flex-direction: row; align-items: center; justify-content: center; + color: var(--primary-glass); cursor: pointer; font-size: 14px; font-weight: 400; @@ -36,6 +35,10 @@ line-height: 17px; } +.header_menu_item:hover { + color: var(--primary); +} + .logo img { height: 30px; margin-right: 5px; @@ -53,3 +56,24 @@ li { background-repeat: no-repeat; cursor: pointer; } + +.scheme_switcher_radio_group_item { + display: flex; + width: 80px; + height: 30px; + align-items: center; + justify-content: center; + border-radius: 20px; + cursor: pointer; + gap: 10px; + padding-inline: 15px; +} + +.scheme_switcher_radio_group_item.active, +.scheme_switcher_radio_group_item.active:hover { + background-color: var(--accent); +} + +.scheme_switcher_radio_group_item:hover { + background-color: var(--accent-glass); +} diff --git a/src/static/views/components/header/index.ejs b/src/static/views/components/header/index.ejs index 1c8959d0..4f502abf 100644 --- a/src/static/views/components/header/index.ejs +++ b/src/static/views/components/header/index.ejs @@ -7,33 +7,69 @@ diff --git a/src/static/views/components/header/index.js b/src/static/views/components/header/index.js index 945e6840..0fe77c53 100644 --- a/src/static/views/components/header/index.js +++ b/src/static/views/components/header/index.js @@ -1 +1,24 @@ -document.getElementById('scheme_switcher').addEventListener('click', () => window.switchScheme()); +const initSchemeSwitcher = () => { + // eslint-disable-next-line no-undef + const { scheme, setScheme } = initScheme(); + // eslint-disable-next-line no-undef + const { closeDropdown } = initDropdown('scheme_switcher_dropdown'); + + const radioGroupItems = document.getElementsByClassName('scheme_switcher_radio_group_item'); + + for (let item of radioGroupItems) { + const value = item.getAttribute('data-value'); + + if (scheme === value) { + item.classList.add('active'); + } + + item.addEventListener('click', () => { + setScheme(value); + switchActiveItem('scheme_switcher_radio_group_item', item); + closeDropdown(); + }); + } +}; + +initSchemeSwitcher(); diff --git a/src/static/views/features/dropdown/index.css b/src/static/views/features/dropdown/index.css new file mode 100644 index 00000000..752fe651 --- /dev/null +++ b/src/static/views/features/dropdown/index.css @@ -0,0 +1,23 @@ +.dropdown { + display: flex; + justify-content: center; +} + +.dropdown_content { + position: absolute; + display: none; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 5px; + border-radius: 20px; + backdrop-filter: blur(20px); + background-color: var(--background-card); + box-shadow: var(--shadow); + gap: 10px; + transform: translateY(25%); +} + +.dropdown_content.active { + display: flex; +} diff --git a/src/static/views/features/dropdown/index.ejs b/src/static/views/features/dropdown/index.ejs new file mode 100644 index 00000000..270cdf4f --- /dev/null +++ b/src/static/views/features/dropdown/index.ejs @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/static/views/features/dropdown/index.js b/src/static/views/features/dropdown/index.js new file mode 100644 index 00000000..fee13b04 --- /dev/null +++ b/src/static/views/features/dropdown/index.js @@ -0,0 +1,35 @@ +const onClickOutside = (element, handler) => { + const onClickOutsideListener = (event) => { + if (!element.contains(event.target)) { + handler(); + } + }; + + document.addEventListener('click', onClickOutsideListener); +}; + +// eslint-disable-next-line no-unused-vars +const initDropdown = (dropdownId) => { + const dropdown = document.getElementById(dropdownId); + const dropdownTrigger = document.getElementById(`${dropdownId}_trigger`); + const dropdownContent = document.getElementById(`${dropdownId}_content`); + + const closeDropdown = () => { + dropdownContent.classList.remove('active'); + }; + + const openDropdown = () => { + dropdownContent.classList.add('active'); + }; + + const onClickDropdownListener = (event) => { + event.stopPropagation(); + dropdownContent.classList.toggle('active'); + }; + + dropdownTrigger.addEventListener('click', onClickDropdownListener); + + document.addEventListener('click', () => onClickOutside(dropdown, closeDropdown)); + + return { openDropdown, closeDropdown }; +}; diff --git a/src/static/views/features/scheme/dark.css b/src/static/views/features/scheme/dark.css deleted file mode 100644 index 218e53e7..00000000 --- a/src/static/views/features/scheme/dark.css +++ /dev/null @@ -1,13 +0,0 @@ -:root { - color-scheme: dark; - - --accent: #6972ff; - --accent-glass: rgb(105 114 255 / 50%); - --primary: #fff; - --primary-glass: rgba(255 255 255 / 70%); - --shadow: 0px 4px 10px rgba(0 0 0 / 25%); - --background-body: #363942; - --background-container: rgba(0 0 0 / 15%); - --background-card: rgba(255 255 255 / 5%); - --image-scheme: url('/assets/icons/scheme-dark.svg'); -} diff --git a/src/static/views/features/scheme/index.css b/src/static/views/features/scheme/index.css new file mode 100644 index 00000000..88e0834d --- /dev/null +++ b/src/static/views/features/scheme/index.css @@ -0,0 +1,27 @@ +:root { + color-scheme: dark; + + --accent: rgb(105 114 255); + --accent-glass: rgb(105 114 255 / 50%); + --primary: rgba(230 230 230); + --primary-glass: rgba(230 230 230 / 70%); + --shadow: 0px 4px 10px rgba(0 0 0 / 25%); + --background-body: #2f3239; + --background-container: rgba(0 0 0 / 15%); + --background-card: rgba(255 255 255 / 5%); + --image-scheme: url('/assets/icons/scheme-dark.svg'); +} + +:root.light_scheme { + color-scheme: light; + + --accent: rgb(149 155 255); + --accent-glass: rgb(149 155 255 / 50%); + --primary: #343434; + --primary-glass: rgba(52 52 52 / 80%); + --shadow: 0px 4px 10px rgba(0 0 0 / 15%); + --background-body: #d9dbed; + --background-container: rgba(255 255 255 / 75%); + --background-card: rgba(255 255 255 / 30%); + --image-scheme: url('/assets/icons/scheme-light.svg'); +} diff --git a/src/static/views/features/scheme/index.ejs b/src/static/views/features/scheme/index.ejs index 272e3eaf..2beba21a 100644 --- a/src/static/views/features/scheme/index.ejs +++ b/src/static/views/features/scheme/index.ejs @@ -1,3 +1,2 @@ - - - + + \ No newline at end of file diff --git a/src/static/views/features/scheme/index.js b/src/static/views/features/scheme/index.js index 7e1a60de..35c7fe1b 100644 --- a/src/static/views/features/scheme/index.js +++ b/src/static/views/features/scheme/index.js @@ -1,31 +1,45 @@ -const lightStyles = document.querySelector( - 'link[rel=stylesheet][media*=prefers-color-scheme][media*=light]' -); -const darkStyles = document.querySelector( - 'link[rel=stylesheet][media*=prefers-color-scheme][media*=dark]' -); - -function getSavedScheme() { +const mediaDark = window.matchMedia('(prefers-color-scheme: dark)'); + +const getSavedScheme = () => { return localStorage.getItem('color-scheme'); -} +}; -function setScheme(scheme) { - const lightMedia = scheme === 'light' ? 'all' : 'not all'; - const darkMedia = scheme === 'dark' ? 'all' : 'not all'; +const getSystemScheme = () => { + const isDark = mediaDark.matches; + const systemScheme = isDark ? 'dark' : 'light'; + return systemScheme; +}; - lightStyles.media = lightMedia; - darkStyles.media = darkMedia; +const getCurrentScheme = () => getSavedScheme() ?? 'system'; - localStorage.setItem('color-scheme', scheme); -} +const setSchemeStyles = (scheme) => { + const isDark = scheme === 'dark'; + if (isDark) { + document.documentElement.classList.remove('light_scheme'); + } else { + document.documentElement.classList.add('light_scheme'); + } +}; -// eslint-disable-next-line no-unused-vars -function switchScheme() { - setScheme(getSavedScheme() === 'light' ? 'dark' : 'light'); -} +const setScheme = (newScheme) => { + let scheme = newScheme; + + const setSystemScheme = () => setScheme('system'); -function initScheme() { - setScheme(getSavedScheme() ?? 'dark'); -} + if (newScheme === 'system') { + scheme = getSystemScheme(); + mediaDark.addEventListener('change', setSystemScheme); + } else { + mediaDark.removeEventListener('change', setSystemScheme); + } -initScheme(); + localStorage.setItem('color-scheme', newScheme); + setSchemeStyles(scheme); +}; + +// eslint-disable-next-line no-unused-vars +const initScheme = () => { + const scheme = getCurrentScheme(); + setScheme(scheme); + return { scheme, setScheme }; +}; diff --git a/src/static/views/features/scheme/light.css b/src/static/views/features/scheme/light.css deleted file mode 100644 index c9af2e4b..00000000 --- a/src/static/views/features/scheme/light.css +++ /dev/null @@ -1,13 +0,0 @@ -:root { - color-scheme: light; - - --accent: rgb(149 155 255); - --accent-glass: rgb(149 155 255 / 50%); - --primary: #343434; - --primary-glass: rgba(52 52 52 / 70%); - --shadow: 0px 4px 10px rgba(0 0 0 / 15%); - --background-body: #e4e5ef; - --background-container: rgba(255 255 255 / 75%); - --background-card: rgba(255 255 255 / 75%); - --image-scheme: url('/assets/icons/scheme-light.svg'); -} diff --git a/src/static/views/features/tab/index.css b/src/static/views/features/tab/index.css index 1e826e36..abc53dcb 100644 --- a/src/static/views/features/tab/index.css +++ b/src/static/views/features/tab/index.css @@ -1,17 +1,15 @@ -.tab_items { +.tab_triggers { display: flex; - flex-direction: row; align-items: center; padding: 3px; border-radius: 20px; background: var(--background-container); font-size: 14px; - font-weight: 300; gap: 4px; line-height: 17px; } -.tab_item { +.tab_trigger { display: flex; width: 120px; height: 30px; @@ -21,10 +19,18 @@ cursor: pointer; } -.tab_item:not(.tab_item_active):hover { +.tab_trigger:not(.tab_trigger.active):hover { background-color: var(--accent-glass); } +.tab_trigger.active { + background: var(--accent); +} + .tab_content { display: none; } + +.tab_content.active { + display: unset; +} diff --git a/src/static/views/features/tab/index.js b/src/static/views/features/tab/index.js index 8f95f2db..cfd81c7b 100644 --- a/src/static/views/features/tab/index.js +++ b/src/static/views/features/tab/index.js @@ -1,12 +1,11 @@ -function switchTab(activeTabId) { - document.querySelector('body').className = activeTabId; -} +const initTabGroup = (tabGroupClassName, tabIds) => { + for (let tabId of tabIds) { + const tabTrigger = document.getElementById(`${tabId}_trigger`); + const tabContent = document.getElementById(`${tabId}_content`); -function initTab() { - const tabItems = document.getElementsByClassName('tab_item'); - for (let i = 0; i < tabItems.length; i += 1) { - tabItems[i].addEventListener('click', () => switchTab(tabItems[i].id)); + tabTrigger.addEventListener('click', () => { + switchActiveItem(`${tabGroupClassName} tab_trigger`, tabTrigger); + switchActiveItem(`${tabGroupClassName} tab_content`, tabContent); + }); } -} - -initTab(); +}; diff --git a/src/static/views/pages/404/index.css b/src/static/views/pages/404/index.css deleted file mode 100644 index d66ddfc9..00000000 --- a/src/static/views/pages/404/index.css +++ /dev/null @@ -1,10 +0,0 @@ -/* stylelint-disable */ -.tab_item-REST #tab_item-REST, -.tab_item-GraphQL #tab_item-GraphQL { - background: var(--accent); -} - -.tab_item-REST #tab_content-REST, -.tab_item-GraphQL #tab_content-GraphQL { - display: unset; -} diff --git a/src/static/views/pages/404/index.ejs b/src/static/views/pages/404/index.ejs index 306686d1..cc327ea2 100644 --- a/src/static/views/pages/404/index.ejs +++ b/src/static/views/pages/404/index.ejs @@ -8,16 +8,19 @@ 404 - 🎉 Mock Config Server - <% const api = { rest: "REST", graphql: "GraphQL" } %> + <% const apiView = graphqlRequestSuggestions.length ? api.graphql : api.rest %> <% const rootPath = (path) => `../../${path}` %> <%- include(rootPath('features/scheme/index')) -%> <%- include(rootPath('features/tab/index')) -%> + <%- include(rootPath('features/dropdown/index')) -%> + <%- include(rootPath('utils/helpers/index')) -%> + - + <%- include(rootPath('components/header/index')) -%>
@@ -36,15 +39,15 @@
-
+
<% Object.values(api).forEach((variant)=> { %> -
+
<%=variant%>
<% }) %>
-
+
<% if (restRequestSuggestions.length) { %> We searched a bit, maybe this will help you: @@ -61,7 +64,7 @@
-
+
<% if (graphqlRequestSuggestions.length) { %> We searched a bit, maybe this will help you: diff --git a/src/static/views/pages/404/index.js b/src/static/views/pages/404/index.js new file mode 100644 index 00000000..381eacec --- /dev/null +++ b/src/static/views/pages/404/index.js @@ -0,0 +1 @@ +initTabGroup('tab_api', ['tab_api_REST', 'tab_api_GraphQL']); diff --git a/src/static/views/utils/helpers/index.ejs b/src/static/views/utils/helpers/index.ejs new file mode 100644 index 00000000..56267274 --- /dev/null +++ b/src/static/views/utils/helpers/index.ejs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/views/utils/helpers/switchActiveItem.js b/src/static/views/utils/helpers/switchActiveItem.js new file mode 100644 index 00000000..bf670b42 --- /dev/null +++ b/src/static/views/utils/helpers/switchActiveItem.js @@ -0,0 +1,7 @@ +const switchActiveItem = (groupClassName, activatedElement) => { + const activeItems = document.getElementsByClassName(`${groupClassName} active`); + for (let activeItem of activeItems) { + activeItem.classList.remove('active'); + } + activatedElement.classList.add('active'); +};