@@ -42,12 +42,13 @@ export default {
|
|||||||
{ text: 'Promotion', link: '/components/promotion' },
|
{ text: 'Promotion', link: '/components/promotion' },
|
||||||
{ text: 'Markdown', link: '/components/markdown' },
|
{ text: 'Markdown', link: '/components/markdown' },
|
||||||
{ text: 'Copy Code', link: '/components/copy-code' },
|
{ text: 'Copy Code', link: '/components/copy-code' },
|
||||||
|
{ text: 'Notifications', link: '/components/notifications' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
footer: {
|
footer: {
|
||||||
message:
|
message:
|
||||||
'Released under the <a href="https://github.com/modrinth/omoprhia/blob/main/LICENSE">GPLv3 License</a>.',
|
'Released under the <a href="https://github.com/modrinth/omoprhia/blob/main/LICENSE">AGPLv3 License</a>.',
|
||||||
copyright: 'Copyright © 2023-present <a href="https://modrinth.com">Rinth, Inc.</a>',
|
copyright: 'Copyright © 2023-present <a href="https://modrinth.com">Rinth, Inc.</a>',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
46
docs/components/notifications.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Notifications
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const notifsContainer = ref(null);
|
||||||
|
|
||||||
|
function addNotification(type) {
|
||||||
|
console.log(notifsContainer);
|
||||||
|
notifsContainer.value.addNotification({
|
||||||
|
title: 'Test Notification',
|
||||||
|
text: 'This is a test! Random number: ' + Math.random(),
|
||||||
|
type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<DemoContainer>
|
||||||
|
<Notifications ref="notifsContainer" />
|
||||||
|
<Button color="primary" @click="addNotification('success')">Success</Button>
|
||||||
|
<Button color="highlight" @click="addNotification('warn')">Warning</Button>
|
||||||
|
<Button color="danger" @click="addNotification('error')">Error</Button>
|
||||||
|
<Button @click="addNotification('info')">Info</Button>
|
||||||
|
</DemoContainer>
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const notifsContainer = ref(null);
|
||||||
|
|
||||||
|
function addNotification(type) {
|
||||||
|
console.log(notifsContainer);
|
||||||
|
notifsContainer.value.addNotification({
|
||||||
|
title: 'Test Notification',
|
||||||
|
text: 'This is a test! Random number: ' + Math.random(),
|
||||||
|
type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Notifications ref="notifsContainer" />
|
||||||
|
<Button color="primary" @click="addNotification('success')">Success</Button>
|
||||||
|
<Button color="highlight" @click="addNotification('warn')">Warning</Button>
|
||||||
|
<Button color="danger" @click="addNotification('error')">Error</Button>
|
||||||
|
<Button @click="addNotification('info')">Info</Button>
|
||||||
|
```
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
||||||
|
Before Width: | Height: | Size: 274 B |
4
lib/assets/icons/folder-open.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2"></path>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 389 B |
6
lib/assets/icons/folder-search.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M11 20H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H20a2 2 0 0 1 2 2v4"></path>
|
||||||
|
<circle cx="17" cy="17" r="3"></circle>
|
||||||
|
<path d="m21 21-1.5-1.5"></path>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
lib/assets/icons/hammer.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 12-8.5 8.5c-.83.83-2.17.83-3 0 0 0 0 0 0 0a2.12 2.12 0 0 1 0-3L12 9"></path><path d="M17.64 15 22 10.64"></path><path d="m20.91 11.7-1.25-1.25c-.6-.6-.93-1.4-.93-2.25v-.86L16.01 4.6a5.56 5.56 0 0 0-3.94-1.64H9l.92.82A6.18 6.18 0 0 1 12 8.4v1.56l2 2h2.47l2.26 1.91"></path></svg>
|
||||||
|
After Width: | Height: | Size: 473 B |
1
lib/assets/icons/log-in.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-log-in"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" x2="3" y1="12" y2="12"></line></svg>
|
||||||
|
After Width: | Height: | Size: 366 B |
1
lib/assets/icons/stop-circle.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-stop-circle"><circle cx="12" cy="12" r="10"></circle><rect width="6" height="6" x="9" y="9"></rect></svg>
|
||||||
|
After Width: | Height: | Size: 307 B |
1
lib/assets/icons/terminal-square.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-terminal-square"><path d="m7 11 2-2-2-2"></path><path d="M11 13h4"></path><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect></svg>
|
||||||
|
After Width: | Height: | Size: 344 B |
6
lib/assets/icons/x-circle.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<line x1="15" y1="9" x2="9" y2="15"></line>
|
||||||
|
<line x1="9" y1="9" x2="15" y2="15"></line>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 324 B |
129
lib/components/base/Notifications.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vue-notification-group">
|
||||||
|
<transition-group name="notifs">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in notifications"
|
||||||
|
:key="item.id"
|
||||||
|
class="vue-notification-wrapper"
|
||||||
|
@click="notifications.splice(index, 1)"
|
||||||
|
@mouseenter="stopTimer(item)"
|
||||||
|
@mouseleave="setNotificationTimer(item)"
|
||||||
|
>
|
||||||
|
<div class="vue-notification-template vue-notification" :class="{ [item.type]: true }">
|
||||||
|
<div class="notification-title" v-html="item.title"></div>
|
||||||
|
<div class="notification-content" v-html="item.text"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const notifications = ref([])
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
addNotification: (notification) => {
|
||||||
|
const existingNotif = notifications.value.find(
|
||||||
|
(x) =>
|
||||||
|
x.text === notification.text &&
|
||||||
|
x.title === notification.title &&
|
||||||
|
x.type === notification.type
|
||||||
|
)
|
||||||
|
if (existingNotif) {
|
||||||
|
setNotificationTimer(existingNotif)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.id = new Date()
|
||||||
|
|
||||||
|
setNotificationTimer(notification)
|
||||||
|
notifications.value.push(notification)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function setNotificationTimer(notification) {
|
||||||
|
if (!notification) return
|
||||||
|
|
||||||
|
if (notification.timer) {
|
||||||
|
clearTimeout(notification.timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.timer = setTimeout(() => {
|
||||||
|
notifications.value.splice(notifications.value.indexOf(notification), 1)
|
||||||
|
}, 30000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopTimer(notif) {
|
||||||
|
clearTimeout(notif.timer)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.vue-notification {
|
||||||
|
background: var(--color-blue) !important;
|
||||||
|
color: var(--color-accent-contrast) !important;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0 5px 5px;
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
background: var(--color-green) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warn {
|
||||||
|
background: var(--color-orange) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
background: var(--color-red) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-notification-group {
|
||||||
|
position: fixed;
|
||||||
|
right: 25px;
|
||||||
|
bottom: 25px;
|
||||||
|
z-index: 99999999;
|
||||||
|
width: 300px;
|
||||||
|
|
||||||
|
.vue-notification-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.vue-notification-template {
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
.notification-title {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
margin-right: auto;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content {
|
||||||
|
margin-right: auto;
|
||||||
|
font-size: var(--font-size-md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notifs-enter-active,
|
||||||
|
.notifs-leave-active,
|
||||||
|
.notifs-move {
|
||||||
|
transition: all 0.5s;
|
||||||
|
}
|
||||||
|
.notifs-enter-from,
|
||||||
|
.notifs-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -19,6 +19,7 @@ export { default as FileInput } from './base/FileInput.vue'
|
|||||||
export { default as DropArea } from './base/DropArea.vue'
|
export { default as DropArea } from './base/DropArea.vue'
|
||||||
export { default as Toggle } from './base/Toggle.vue'
|
export { default as Toggle } from './base/Toggle.vue'
|
||||||
export { default as CopyCode } from './base/CopyCode.vue'
|
export { default as CopyCode } from './base/CopyCode.vue'
|
||||||
|
export { default as Notifications } from './base/Notifications.vue'
|
||||||
|
|
||||||
export { default as Categories } from './search/Categories.vue'
|
export { default as Categories } from './search/Categories.vue'
|
||||||
export { default as SearchFilter } from './search/SearchFilter.vue'
|
export { default as SearchFilter } from './search/SearchFilter.vue'
|
||||||
@@ -52,7 +53,7 @@ export { default as DashboardIcon } from '@/assets/icons/dashboard.svg'
|
|||||||
export { default as DownloadIcon } from '@/assets/icons/download.svg'
|
export { default as DownloadIcon } from '@/assets/icons/download.svg'
|
||||||
export { default as DropdownIcon } from '@/assets/icons/dropdown.svg'
|
export { default as DropdownIcon } from '@/assets/icons/dropdown.svg'
|
||||||
export { default as EditIcon } from '@/assets/icons/edit.svg'
|
export { default as EditIcon } from '@/assets/icons/edit.svg'
|
||||||
export { default as ExitIcon } from '@/assets/icons/exit.svg'
|
export { default as ExitIcon } from '@/assets/icons/x.svg'
|
||||||
export { default as ExpandIcon } from '@/assets/icons/expand.svg'
|
export { default as ExpandIcon } from '@/assets/icons/expand.svg'
|
||||||
export { default as ExternalIcon } from '@/assets/icons/external.svg'
|
export { default as ExternalIcon } from '@/assets/icons/external.svg'
|
||||||
export { default as EyeIcon } from '@/assets/icons/eye.svg'
|
export { default as EyeIcon } from '@/assets/icons/eye.svg'
|
||||||
@@ -60,11 +61,14 @@ export { default as EyeOffIcon } from '@/assets/icons/eye-off.svg'
|
|||||||
export { default as FileIcon } from '@/assets/icons/file.svg'
|
export { default as FileIcon } from '@/assets/icons/file.svg'
|
||||||
export { default as FileTextIcon } from '@/assets/icons/file-text.svg'
|
export { default as FileTextIcon } from '@/assets/icons/file-text.svg'
|
||||||
export { default as FilterIcon } from '@/assets/icons/filter.svg'
|
export { default as FilterIcon } from '@/assets/icons/filter.svg'
|
||||||
|
export { default as FolderOpenIcon } from '@/assets/icons/folder-open.svg'
|
||||||
|
export { default as FolderSearchIcon } from '@/assets/icons/folder-search.svg'
|
||||||
export { default as GapIcon } from '@/assets/icons/gap.svg'
|
export { default as GapIcon } from '@/assets/icons/gap.svg'
|
||||||
export { default as GitHubIcon } from '@/assets/icons/github.svg'
|
export { default as GitHubIcon } from '@/assets/icons/github.svg'
|
||||||
export { default as GlobeIcon } from '@/assets/icons/globe.svg'
|
export { default as GlobeIcon } from '@/assets/icons/globe.svg'
|
||||||
export { default as GridIcon } from '@/assets/icons/grid.svg'
|
export { default as GridIcon } from '@/assets/icons/grid.svg'
|
||||||
export { default as HamburgerIcon } from '@/assets/icons/hamburger.svg'
|
export { default as HamburgerIcon } from '@/assets/icons/hamburger.svg'
|
||||||
|
export { default as HammerIcon } from '@/assets/icons/hammer.svg'
|
||||||
export { default as HashIcon } from '@/assets/icons/hash.svg'
|
export { default as HashIcon } from '@/assets/icons/hash.svg'
|
||||||
export { default as HeartIcon } from '@/assets/icons/heart.svg'
|
export { default as HeartIcon } from '@/assets/icons/heart.svg'
|
||||||
export { default as HeartHandshakeIcon } from '@/assets/icons/heart-handshake.svg'
|
export { default as HeartHandshakeIcon } from '@/assets/icons/heart-handshake.svg'
|
||||||
@@ -78,6 +82,7 @@ export { default as LightBulbIcon } from '@/assets/icons/light-bulb.svg'
|
|||||||
export { default as LinkIcon } from '@/assets/icons/link.svg'
|
export { default as LinkIcon } from '@/assets/icons/link.svg'
|
||||||
export { default as ListIcon } from '@/assets/icons/list.svg'
|
export { default as ListIcon } from '@/assets/icons/list.svg'
|
||||||
export { default as LockIcon } from '@/assets/icons/lock.svg'
|
export { default as LockIcon } from '@/assets/icons/lock.svg'
|
||||||
|
export { default as LogInIcon } from '@/assets/icons/log-in.svg'
|
||||||
export { default as LogOutIcon } from '@/assets/icons/log-out.svg'
|
export { default as LogOutIcon } from '@/assets/icons/log-out.svg'
|
||||||
export { default as MoonIcon } from '@/assets/icons/moon.svg'
|
export { default as MoonIcon } from '@/assets/icons/moon.svg'
|
||||||
export { default as OmorphiaIcon } from '@/assets/icons/omorphia.svg'
|
export { default as OmorphiaIcon } from '@/assets/icons/omorphia.svg'
|
||||||
@@ -95,10 +100,12 @@ export { default as SettingsIcon } from '@/assets/icons/settings.svg'
|
|||||||
export { default as ShieldIcon } from '@/assets/icons/shield.svg'
|
export { default as ShieldIcon } from '@/assets/icons/shield.svg'
|
||||||
export { default as SlashIcon } from '@/assets/icons/slash.svg'
|
export { default as SlashIcon } from '@/assets/icons/slash.svg'
|
||||||
export { default as StarIcon } from '@/assets/icons/star.svg'
|
export { default as StarIcon } from '@/assets/icons/star.svg'
|
||||||
|
export { default as StopCircleIcon } from '@/assets/icons/stop-circle.svg'
|
||||||
export { default as SunIcon } from '@/assets/icons/sun.svg'
|
export { default as SunIcon } from '@/assets/icons/sun.svg'
|
||||||
export { default as SunriseIcon } from '@/assets/icons/sunrise.svg'
|
export { default as SunriseIcon } from '@/assets/icons/sunrise.svg'
|
||||||
export { default as TagIcon } from '@/assets/icons/tag.svg'
|
export { default as TagIcon } from '@/assets/icons/tag.svg'
|
||||||
export { default as TagsIcon } from '@/assets/icons/tags.svg'
|
export { default as TagsIcon } from '@/assets/icons/tags.svg'
|
||||||
|
export { default as TerminalSquareIcon } from '@/assets/icons/terminal-square.svg'
|
||||||
export { default as TransferIcon } from '@/assets/icons/transfer.svg'
|
export { default as TransferIcon } from '@/assets/icons/transfer.svg'
|
||||||
export { default as TrashIcon } from '@/assets/icons/trash.svg'
|
export { default as TrashIcon } from '@/assets/icons/trash.svg'
|
||||||
export { default as UndoIcon } from '@/assets/icons/undo.svg'
|
export { default as UndoIcon } from '@/assets/icons/undo.svg'
|
||||||
@@ -113,5 +120,6 @@ export { default as UsersIcon } from '@/assets/icons/users.svg'
|
|||||||
export { default as VersionIcon } from '@/assets/icons/version.svg'
|
export { default as VersionIcon } from '@/assets/icons/version.svg'
|
||||||
export { default as WikiIcon } from '@/assets/icons/wiki.svg'
|
export { default as WikiIcon } from '@/assets/icons/wiki.svg'
|
||||||
export { default as XIcon } from '@/assets/icons/x.svg'
|
export { default as XIcon } from '@/assets/icons/x.svg'
|
||||||
|
export { default as XCircleIcon } from '@/assets/icons/x-circle.svg'
|
||||||
|
|
||||||
export { default as ModrinthIcon } from '@/assets/branding/logo.svg'
|
export { default as ModrinthIcon } from '@/assets/branding/logo.svg'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "omorphia",
|
"name": "omorphia",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.4.16",
|
"version": "0.4.17",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
|
|||||||