diff --git a/app.config.ts b/app.config.ts deleted file mode 100644 index 11f7f7c..0000000 --- a/app.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default defineAppConfig({ - title: "Gorb", - buildTimeString: new Date().toISOString(), - gitHash: process.env.GIT_SHORT_REV || "N/A" -}) diff --git a/app.vue b/app.vue index a0a0ed6..cb5ec34 100644 --- a/app.vue +++ b/app.vue @@ -33,6 +33,7 @@ body { font-family: Arial, Helvetica, sans-serif; box-sizing: border-box; color: var(--text-color); + background: var(--optional-body-background); background-color: var(--chat-background-color); margin: 0; } diff --git a/components/Button.vue b/components/Button.vue index fb44cf2..66706de 100644 --- a/components/Button.vue +++ b/components/Button.vue @@ -21,7 +21,7 @@ const props = defineProps<{ background-color: var(--primary-color); color: var(--text-color); - padding: 0.7dvh 1.2dvw; + padding: 0.4em 0.75em; font-size: 1.1em; transition: background-color 0.2s; diff --git a/components/Channel.vue b/components/Channel.vue index 0f48323..98f210e 100644 --- a/components/Channel.vue +++ b/components/Channel.vue @@ -23,14 +23,14 @@ const isCurrentChannel = props.uuid == props.currentUuid; .channel-list-link { text-decoration: none; color: inherit; - padding-left: .5dvw; - padding-right: .5dvw; + padding-left: .25em; + padding-right: .25em; } .channel-list-link-container { text-align: left; display: flex; - height: 4dvh; + height: 1.5em; white-space: nowrap; align-items: center; } diff --git a/components/CropPopup.vue b/components/CropPopup.vue new file mode 100644 index 0000000..12c3a0b --- /dev/null +++ b/components/CropPopup.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/components/MemberEntry.vue b/components/MemberEntry.vue index 3eed3c5..ed4cd48 100644 --- a/components/MemberEntry.vue +++ b/components/MemberEntry.vue @@ -2,8 +2,8 @@
- {{ props.member.user.display_name ?? props.member.user.username }} - + {{ props.member.user.display_name || props.member.user.username }} +
@@ -32,9 +32,4 @@ const hidePopup = () => { .member-item { position: relative; /* Set the position to relative for absolute positioning of the popup */ } - -.profile-popup { - position: absolute; /* Use absolute positioning */ - left: -100px; /* Adjust this value to position the popup to the left */ -} diff --git a/components/Message.vue b/components/Message.vue index e8a91b5..eb073ac 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -60,7 +60,16 @@ const sanitized = ref(); onMounted(async () => { const parsed = await parse(props.text, { gfm: true }); - sanitized.value = DOMPurify.sanitize(parsed, { ALLOWED_TAGS: ["strong", "em", "br", "blockquote", "code", "ul", "ol", "li", "a", "h1", "h2", "h3", "h4", "h5", "h6"] }); + sanitized.value = DOMPurify.sanitize(parsed, { + ALLOWED_TAGS: [ + "strong", "em", "br", "blockquote", + "code", "ul", "ol", "li", "a", "h1", + "h2", "h3", "h4", "h5", "h6" + ], + ALLOW_DATA_ATTR: false, + ALLOW_SELF_CLOSE_IN_ATTR: false, + ALLOWED_ATTR: [] + }); console.log("adding listeners") await nextTick(); messageElement.value?.addEventListener("mouseenter", (e: Event) => { @@ -99,6 +108,7 @@ function getDayDifference(date1: Date, date2: Date) { align-items: center; column-gap: 1dvw; width: 100%; + overflow-wrap: anywhere; } .message:hover { @@ -178,12 +188,12 @@ function getDayDifference(date1: Date, date2: Date) { diff --git a/components/MessageArea.vue b/components/MessageArea.vue index 18b9ac5..59e5e06 100644 --- a/components/MessageArea.vue +++ b/components/MessageArea.vue @@ -9,11 +9,28 @@
- - +
+ + + +
+ +
+
+
+
+ +
+ + + + +
@@ -106,11 +123,38 @@ function pushMessage(message: MessageResponse) { messages.value.push(message); } +function handleTextboxKeyDown(event: KeyboardEvent) { + if (event.key === "Enter" && event.shiftKey && messageTextboxInput.value) { + // this enters a newline, due to not preventing default + } else if (event.key === "Enter") { + event.preventDefault() + sendMessage(event) + } + + adjustTextboxHeight() +} + +function handleTextboxInput() { + if (messageTextboxInput.value) { + messageInput.value = messageTextboxInput.value.innerText; + } + + adjustTextboxHeight() +} + +// this technically uses pixel units, but it's still set using dynamic units +function adjustTextboxHeight() { + if (messageTextboxInput.value && messageTextboxDisplay.value) { + messageTextboxInput.value.style.height = "auto" + messageTextboxInput.value.style.height = `${messageTextboxInput.value.scrollHeight}px` + } +} + const messages = ref([]); - -const messageInput = ref(); - +const messageInput = ref(""); const messagesElement = ref(); +const messageTextboxInput = ref(); +const messageTextboxDisplay = ref(); if (messagesRes) messages.value = messagesRes; @@ -158,14 +202,21 @@ if (accessToken && apiBase) { function sendMessage(e: Event) { e.preventDefault(); - const message = { - message: messageInput.value - } - console.log("message:", message); - if (message.message) { + if (messageInput.value && messageInput.value.trim() !== "") { + const message = { + message: messageInput.value.trim().replace(/\n/g, "
") // trim, and replace \n with
+ } + + console.log("message:", message); ws.send(JSON.stringify(message)); - messageInput.value = ""; - console.log("MESSAGE SENT!!!"); + + // reset input field + messageInput.value = "" + if (messageTextboxInput.value) { + messageTextboxInput.value.innerText = "" + } + + adjustTextboxHeight() } } @@ -241,38 +292,64 @@ router.beforeEach((to, from, next) => { \ No newline at end of file +.theme-preview-container { + margin: .5em; + width: 5em; + height: 5em; +} + +.theme-preview { + width: 5em; + height: 5em; + border-radius: 100%; + border: .1em solid var(--primary-color); + + display: inline-block; + text-align: center; + align-content: center; + cursor: pointer; +} + +.theme-title { + font-size: .8em; + line-height: 5em; /* same height as the parent to centre it vertically */ +} + diff --git a/components/Settings/UserSettings/Account.vue b/components/Settings/UserSettings/Account.vue index 85589e7..b2ac87a 100644 --- a/components/Settings/UserSettings/Account.vue +++ b/components/Settings/UserSettings/Account.vue @@ -43,6 +43,14 @@ async function changeEmail() { body: formData }) + const apiBase = useCookie("api_base").value; + + if (apiBase) { + const stats = await useApi().fetchInstanceStats(apiBase); + if (stats.email_verification_required) { + return window.location.reload(); + } + } alert('success!!') } catch (error: any) { if (error?.response?.status !== 200) { @@ -70,13 +78,6 @@ async function deleteAccount() { \ No newline at end of file diff --git a/components/Settings/UserSettings/Profile.vue b/components/Settings/UserSettings/Profile.vue index ed7da0a..04d1e30 100644 --- a/components/Settings/UserSettings/Profile.vue +++ b/components/Settings/UserSettings/Profile.vue @@ -20,15 +20,25 @@ - + + + \ No newline at end of file diff --git a/components/UserPopup.vue b/components/UserPopup.vue index 3a65cf0..a3a15cb 100644 --- a/components/UserPopup.vue +++ b/components/UserPopup.vue @@ -59,12 +59,14 @@ const props = defineProps<{ width: 96px; height: 96px; border: 5px solid #4b3018; + background-color: var(--secondary-color); border-radius: 100%; position: absolute; left: 16px; top: 16px; } + #display-name { margin-top: 60px; margin-bottom: 0; diff --git a/composables/api.ts b/composables/api.ts index 603f71f..d2ca7a0 100644 --- a/composables/api.ts +++ b/composables/api.ts @@ -1,4 +1,4 @@ -import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse } from "~/types/interfaces"; +import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse, StatsResponse } from "~/types/interfaces"; export const useApi = () => { async function fetchGuilds(): Promise { @@ -41,6 +41,15 @@ export const useApi = () => { return await fetchWithApi(`/channels/${channelId}/messages/${messageId}`); } + async function fetchInstanceStats(apiBase: string): Promise { + return await $fetch(`${apiBase}/stats`, { method: "GET" }); + } + + async function sendVerificationEmail(): Promise { + const email = useAuth().user.value?.email; + await fetchWithApi("/auth/verify-email", { method: "POST", body: { email } }); + } + return { fetchGuilds, fetchGuild, @@ -51,6 +60,8 @@ export const useApi = () => { fetchUsers, fetchUser, fetchMessages, - fetchMessage + fetchMessage, + fetchInstanceStats, + sendVerificationEmail } } diff --git a/composables/auth.ts b/composables/auth.ts index b23a67b..ebe27de 100644 --- a/composables/auth.ts +++ b/composables/auth.ts @@ -7,6 +7,7 @@ export const useAuth = () => { async function clearAuth() { accessToken.value = null; user.value = null; + await navigateTo("/login"); } async function register(username: string, email: string, password: string) { diff --git a/layouts/auth.vue b/layouts/auth.vue index b7d5c5e..0c4ad41 100644 --- a/layouts/auth.vue +++ b/layouts/auth.vue @@ -20,30 +20,7 @@
- Instance URL is set to {{ instanceUrl }} -
-
- You're logged in! -
-
- -
- -
-
- -
-
-
- -
-
- -
-
- -
+ Instance URL is set to {{ instanceUrl }}
@@ -51,7 +28,6 @@ \ No newline at end of file diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index 699b9a3..4873094 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -83,34 +83,36 @@ function handleMemberClick(member: GuildMemberResponse) { \ No newline at end of file diff --git a/pages/verify-email.vue b/pages/verify-email.vue index cae02ea..f160a1d 100644 --- a/pages/verify-email.vue +++ b/pages/verify-email.vue @@ -15,6 +15,12 @@ const token = useRoute().query.token; try { const res = await fetchWithApi("/auth/verify-email", { query: { token } }); console.log("hi"); + const query = useRoute().query; + if (query.redirect_to) { + await navigateTo(`/?redirect_to=${query.redirect_to}`); + } else { + await navigateTo("/"); + } } catch (error) { console.error("Error verifying email:", error); errorMessage.value = error; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c815868..bd6c885 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@tauri-apps/plugin-http': specifier: ~2.5.0 version: 2.5.0 + cropperjs: + specifier: ^2.0.0 + version: 2.0.0 dompurify: specifier: ^3.2.6 version: 3.2.6 @@ -211,6 +214,39 @@ packages: resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} + '@cropper/element-canvas@2.0.0': + resolution: {integrity: sha512-GPtGJgSm92crJhhhwUsaMw3rz2KfJWWSz7kRAlufFEV/EHTP5+6r6/Z1BCGRna830i+Avqbm435XLOtA7PVJwA==} + + '@cropper/element-crosshair@2.0.0': + resolution: {integrity: sha512-KfPfyrdeFvUC31Ws7ATtcalWWSaMtrC6bMoCipZhqbUOE7wZoL4ecDSL6BUOZxPa74awZUqfzirCDjHvheBfyw==} + + '@cropper/element-grid@2.0.0': + resolution: {integrity: sha512-i78SQ0IJTLFveKX6P7svkfMYVdgHrQ8ZmmEw8keFy9n1ZVbK+SK0UHK5FNMRNI/gtVhKJOGEnK/zeyjUdj4Iyw==} + + '@cropper/element-handle@2.0.0': + resolution: {integrity: sha512-ZJvW+0MkK9E8xYymGdoruaQn2kwjSHFpNSWinjyq6csuVQiCPxlX5ovAEDldmZ9MWePPtWEi3vLKQOo2Yb0T8g==} + + '@cropper/element-image@2.0.0': + resolution: {integrity: sha512-9BxiTS/aHRmrjopaFQb9mQQXmx4ruhYHGkDZMVz24AXpMFjUY6OpqrWse/WjzD9tfhMFvEdu17b3VAekcAgpeg==} + + '@cropper/element-selection@2.0.0': + resolution: {integrity: sha512-ensNnbIfJsJ8bhbJTH/RXtk2URFvTOO4TvfRk461n2FPEC588D7rwBmUJxQg74IiTi4y1JbCI+6j+4LyzYBLCQ==} + + '@cropper/element-shade@2.0.0': + resolution: {integrity: sha512-jv/2bbNZnhU4W+T4G0c8ADocLIZvQFTXgCf2RFDNhI5UVxurzWBnDdb8Mx8LnVplnkTqO+xUmHZYve0CwgWo+Q==} + + '@cropper/element-viewer@2.0.0': + resolution: {integrity: sha512-zY+3VRN5TvpM8twlphYtXw0tzJL2VgzeK7ufhL1BixVqOdRxwP13TprYIhqwGt9EW/SyJZUiaIu396T89kRX8A==} + + '@cropper/element@2.0.0': + resolution: {integrity: sha512-lsthn0nQq73GExUE7Mg/ss6Q3RXADGDv055hxoLFwvl/wGHgy6ZkYlfLZ/VmgBHC6jDK5IgPBFnqrPqlXWSGBA==} + + '@cropper/elements@2.0.0': + resolution: {integrity: sha512-PQkPo1nUjxLFUQuHYu+6atfHxpX9B41Xribao6wpvmvmNIFML6LQdNqqWYb6LyM7ujsu71CZdBiMT5oetjJVoQ==} + + '@cropper/utils@2.0.0': + resolution: {integrity: sha512-cprLYr+7kK3faGgoOsTW9gIn5sefDr2KwOmgyjzIXk+8PLpW8FgFKEg5FoWfRD5zMAmkCBuX6rGKDK3VdUEGrg==} + '@dabh/diagnostics@2.0.3': resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} @@ -1997,6 +2033,9 @@ packages: resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} engines: {node: '>=18.0'} + cropperjs@2.0.0: + resolution: {integrity: sha512-TO2j0Qre01kPHbow4FuTrbdEB4jTmGRySxW49jyEIqlJZuEBfrvCTT0vC3eRB2WBXudDfKi1Onako6DKWKxeAQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -5083,6 +5122,72 @@ snapshots: '@colors/colors@1.6.0': {} + '@cropper/element-canvas@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-crosshair@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-grid@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-handle@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-image@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/element-canvas': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-selection@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/element-canvas': 2.0.0 + '@cropper/element-image': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-shade@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/element-canvas': 2.0.0 + '@cropper/element-selection': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element-viewer@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/element-canvas': 2.0.0 + '@cropper/element-image': 2.0.0 + '@cropper/element-selection': 2.0.0 + '@cropper/utils': 2.0.0 + + '@cropper/element@2.0.0': + dependencies: + '@cropper/utils': 2.0.0 + + '@cropper/elements@2.0.0': + dependencies: + '@cropper/element': 2.0.0 + '@cropper/element-canvas': 2.0.0 + '@cropper/element-crosshair': 2.0.0 + '@cropper/element-grid': 2.0.0 + '@cropper/element-handle': 2.0.0 + '@cropper/element-image': 2.0.0 + '@cropper/element-selection': 2.0.0 + '@cropper/element-shade': 2.0.0 + '@cropper/element-viewer': 2.0.0 + + '@cropper/utils@2.0.0': {} + '@dabh/diagnostics@2.0.3': dependencies: colorspace: 1.1.4 @@ -7079,6 +7184,11 @@ snapshots: croner@9.0.0: {} + cropperjs@2.0.0: + dependencies: + '@cropper/elements': 2.0.0 + '@cropper/utils': 2.0.0 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 diff --git a/public/themes/ash.css b/public/themes/ash.css new file mode 100644 index 0000000..66923af --- /dev/null +++ b/public/themes/ash.css @@ -0,0 +1,20 @@ +:root { + --text-color: #f0e5e0; + --secondary-text-color: #e8e0db; + + --chat-background-color: #2f2e2d; + --chat-highlighted-background-color: #3f3b38; + --sidebar-background-color: #3e3a37; + --sidebar-highlighted-background-color: #46423b; + --topbar-background-color: #3a3733; + --chatbox-background-color: #3a3733; + + --padding-color: #e0e0e0; + + --primary-color: #f07028; + --primary-highlighted-color: #f28f4b; + --secondary-color: #683820; + --secondary-highlighted-color: #885830; + --accent-color: #a04b24; + --accent-highlighted-color: #b86038; +} \ No newline at end of file diff --git a/public/themes/ash.json b/public/themes/ash.json new file mode 100644 index 0000000..d5d2a59 --- /dev/null +++ b/public/themes/ash.json @@ -0,0 +1,6 @@ +{ + "displayName": "Ash", + "previewGradient": "45deg, #2f2e2d, #46423b", + "complementaryColor": "white", + "themeUrl": "ash.css" +} \ No newline at end of file diff --git a/public/themes/dark.css b/public/themes/dark.css index 8245724..af94112 100644 --- a/public/themes/dark.css +++ b/public/themes/dark.css @@ -7,6 +7,7 @@ --sidebar-background-color: #2e2a27; --sidebar-highlighted-background-color: #36322b; --topbar-background-color: #2a2723; + --chatbox-background-color: #1a1713; --padding-color: #484848; diff --git a/public/themes/dark.json b/public/themes/dark.json new file mode 100644 index 0000000..4731d43 --- /dev/null +++ b/public/themes/dark.json @@ -0,0 +1,6 @@ +{ + "displayName": "Dark", + "previewGradient": "45deg, #1f1e1d, #36322b", + "complementaryColor": "white", + "themeUrl": "dark.css" +} \ No newline at end of file diff --git a/public/themes/default-themes.json b/public/themes/default-themes.json deleted file mode 100644 index fb9478d..0000000 --- a/public/themes/default-themes.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - "dark.css", - "light.css" -] \ No newline at end of file diff --git a/public/themes/description.css b/public/themes/description.css new file mode 100644 index 0000000..4b07f11 --- /dev/null +++ b/public/themes/description.css @@ -0,0 +1,29 @@ +/* this is not a real theme, but rather a template for themes */ +:root { + --text-color: #161518; + --secondary-text-color: #2b2930; + + --chat-background-color: #80808000; + --chat-highlighted-background-color: #ffffff20; + --sidebar-background-color: #80808000; + --sidebar-highlighted-background-color: #ffffff20; + --topbar-background-color: #80808000; + --chatbox-background-color: #80808000; + + --padding-color: #80808000; + + --primary-color: #21b1ff80; + --primary-highlighted-color: #18a0df80; + --secondary-color: #ffd80080; + --secondary-highlighted-color: #dfb80080; + --accent-color: #ff218c80; + --accent-highlighted-color: #df1b6f80; + + --optional-body-background: ; /* background element for the body */ + --optional-chat-background: ; /* background element for the chat box */ + --optional-topbar-background: ; /* background element for the topbar */ + --optional-sidebar-background: ; /* background element for left server sidebar */ + --optional-channel-list-background: ; /* background element for channel list and settings list */ + --optional-member-list-background: ; /* background element for member list */ + --optional-message-box-background: ; /* background element for message box */ +} \ No newline at end of file diff --git a/public/themes/light.css b/public/themes/light.css index cb51d8c..b9b7b86 100644 --- a/public/themes/light.css +++ b/public/themes/light.css @@ -7,6 +7,7 @@ --sidebar-background-color: #dbd8d4; --sidebar-highlighted-background-color: #d4d0ca; --topbar-background-color: #dfdbd6; + --chatbox-background-color: #dfdbd6; --padding-color: #484848; diff --git a/public/themes/light.json b/public/themes/light.json new file mode 100644 index 0000000..b95c78b --- /dev/null +++ b/public/themes/light.json @@ -0,0 +1,6 @@ +{ + "displayName": "Light", + "previewGradient": "45deg, #f0ebe8, #d4d0ca", + "complementaryColor": "black", + "themeUrl": "light.css" +} \ No newline at end of file diff --git a/public/themes/rainbow-capitalism.css b/public/themes/rainbow-capitalism.css new file mode 100644 index 0000000..32f7449 --- /dev/null +++ b/public/themes/rainbow-capitalism.css @@ -0,0 +1,28 @@ +:root { + --text-color: #161518; + --secondary-text-color: #2b2930; + + --chat-background-color: #80808000; + --chat-highlighted-background-color: #ffffff20; + --sidebar-background-color: #80808000; + --sidebar-highlighted-background-color: #ffffff20; + --topbar-background-color: #80808000; + --chatbox-background-color: #80808040; + + --padding-color: #80808000; + + --primary-color: #21b1ff80; + --primary-highlighted-color: #18a0df80; + --secondary-color: #ffd80080; + --secondary-highlighted-color: #dfb80080; + --accent-color: #ff218c80; + --accent-highlighted-color: #df1b6f80; + + /* --optional-body-background: background */ + --optional-body-background: linear-gradient(45deg, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #f35b2280, #f9962180, #f5c11e80, #f1eb1b80, #f1eb1b80, #f1eb1b80, #63c72080, #0c9b4980, #21878d80, #3954a580, #61379b80, #93288e80); + --optional-topbar-background: linear-gradient(-12.5deg, cyan, pink, white, pink, cyan); + --optional-sidebar-background: linear-gradient(90deg, #55cdfcd0, #f7a8b8d0, #ffffffd0, #f7a8b8d0, #55cdfcd0); + --optional-channel-list-background: linear-gradient(82deg, #d52c00b0, #e29688b0, #ffffffb0, #d27fa4b0, #a20062b0); + --optional-member-list-background: linear-gradient(3deg, #ff0080, #c8259d, #8c4799, #442e9f, #0032a0); + --optional-message-box-background: linear-gradient(3deg, #ff0080, #c8259d, #8c4799, #442e9f, #0032a0); +} \ No newline at end of file diff --git a/public/themes/rainbow-capitalism.json b/public/themes/rainbow-capitalism.json new file mode 100644 index 0000000..e110ea2 --- /dev/null +++ b/public/themes/rainbow-capitalism.json @@ -0,0 +1,6 @@ +{ + "displayName": "Woke", + "previewGradient": "45deg, #ed2224, #ed2224, #f35b22, #f99621, #f5c11e, #f1eb1b 27%, #f1eb1b, #f1eb1b 33%, #63c720, #0c9b49, #21878d, #3954a5, #61379b, #93288e, #93288e", + "complementaryColor": "white", + "themeUrl": "rainbow-capitalism.css" +} \ No newline at end of file