diff --git a/frontend/renderer/plugins/vuetify.ts b/frontend/renderer/plugins/vuetify.ts
index cc4d0f0cb..671d21539 100644
--- a/frontend/renderer/plugins/vuetify.ts
+++ b/frontend/renderer/plugins/vuetify.ts
@@ -1,11 +1,11 @@
// eslint-disable-next-line import/no-unassigned-import
-import '@mdi/font/css/materialdesignicons.css'
-// eslint-disable-next-line import/no-unassigned-import
import 'vuetify/styles'
import { I18n, useI18n } from 'vue-i18n'
import { createVuetify, ThemeDefinition } from 'vuetify'
+import { mdi } from 'vuetify/iconsets/mdi-svg'
import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n'
+import { aliases, set } from '#assets/icons'
import tokens from '#assets/sass/tokens.module.scss'
const lightTheme: ThemeDefinition = {
@@ -44,6 +44,14 @@ export default (i18n: I18n, NonNullable, stri
adapter: createVueI18nAdapter({ i18n, useI18n }),
},
ssr: true,
+ icons: {
+ aliases,
+ defaultSet: 'ocelot',
+ sets: {
+ ocelot: set,
+ mdi,
+ },
+ },
theme: {
defaultTheme: 'light',
themes: {
diff --git a/frontend/src/assets/icons/OcelotIcons.stories.ts b/frontend/src/assets/icons/OcelotIcons.stories.ts
new file mode 100644
index 000000000..79124f41b
--- /dev/null
+++ b/frontend/src/assets/icons/OcelotIcons.stories.ts
@@ -0,0 +1,36 @@
+import { VIcon } from 'vuetify/components'
+
+import { iconNames } from '#assets/icons'
+import { SBComp } from '#types/SBComp'
+
+import type { Meta, StoryObj } from '@storybook/vue3'
+
+// More on how to set up stories at: https://storybook.js.org/docs/vue/writing-stories/introduction
+const meta = {
+ title: 'Icons/Ocelot Icon Set',
+ component: VIcon as SBComp,
+ // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/vue/writing-docs/autodocs
+ tags: ['autodocs'],
+ argTypes: {
+ icon: { control: 'select', options: iconNames },
+ size: { control: 'select', options: ['x-small', 'small', 'default', 'large', 'x-large'] },
+ color: {
+ control: {
+ type: 'color',
+ presetColors: ['#000000', '#ff0000', '#00ff00', '#0000ff'],
+ },
+ },
+ },
+ args: { size: 'default', icon: '$heart', color: '' }, // default value
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+/*
+ *👇 Render functions are a framework specific feature to allow you control on how the component renders.
+ * See https://storybook.js.org/docs/vue/api/csf
+ * to learn how to use render functions.
+ */
+export const Primary: Story = {
+ args: {},
+}
diff --git a/frontend/src/assets/icons/OcelotIcons.test.ts b/frontend/src/assets/icons/OcelotIcons.test.ts
new file mode 100644
index 000000000..684539c28
--- /dev/null
+++ b/frontend/src/assets/icons/OcelotIcons.test.ts
@@ -0,0 +1,28 @@
+import { mount } from '@vue/test-utils'
+import { navigate } from 'vike/client/router'
+import { describe, it, expect, beforeEach, vi } from 'vitest'
+import { VIcon } from 'vuetify/components'
+
+vi.mock('vike/client/router')
+vi.mocked(navigate).mockResolvedValue()
+
+describe('Ocelot Icons', () => {
+ const Wrapper = () => {
+ return mount(VIcon, {
+ props: {
+ icon: '$history',
+ color: 'green',
+ size: 'large',
+ },
+ })
+ }
+ let wrapper: ReturnType
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders and tests if the ocelot icon "$history" is installed', () => {
+ expect(wrapper.element).toMatchSnapshot()
+ })
+})
diff --git a/frontend/src/assets/icons/__snapshots__/OcelotIcons.test.ts.snap b/frontend/src/assets/icons/__snapshots__/OcelotIcons.test.ts.snap
new file mode 100644
index 000000000..5f0268616
--- /dev/null
+++ b/frontend/src/assets/icons/__snapshots__/OcelotIcons.test.ts.snap
@@ -0,0 +1,28 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Ocelot Icons > renders and tests if the ocelot icon "$history" is installed 1`] = `
+
+
+
+
+
+
+`;
diff --git a/frontend/src/assets/icons/helpers/convertSvgToVue.js b/frontend/src/assets/icons/helpers/convertSvgToVue.js
new file mode 100644
index 000000000..9f689cc47
--- /dev/null
+++ b/frontend/src/assets/icons/helpers/convertSvgToVue.js
@@ -0,0 +1,31 @@
+// usage:
+// put source files in folder 'svgs'
+// folder 'svgComponents' have to exist
+// call script with command 'node convertSvgToVue.js'
+// delete source files or whole folder
+// run 'lint --fix' afterwards
+
+import { readdirSync, readFileSync, writeFileSync } from 'fs'
+import { join, parse } from 'path'
+
+const inputDir = '../svgs'
+const outputDir = '../svgComponents'
+
+readdirSync(inputDir).forEach((file) => {
+ const filePath = join(inputDir, file)
+ const fileName = parse(file).name
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
+ const content = readFileSync(filePath, 'utf8')
+
+ // add 'fill' and 'stroke' attributes to SVG code
+ const modifiedContent = content.replace(
+ /
diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts
index f968b1202..7c69f4c08 100644
--- a/frontend/vitest.config.ts
+++ b/frontend/vitest.config.ts
@@ -22,6 +22,8 @@ export default mergeConfig(
// storybook
'**/*{.,-}stories.?(c|m)[jt]s?(x)',
'src/stories/**/*',
+ // scripts
+ 'src/assets/icons/helpers/convertSvgToVue.js',
],
thresholds: {
lines: 84,