Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6328d4d
feat: base content card component
IMB11 Jan 16, 2026
548c1f3
fix: tooltips + colors
IMB11 Jan 16, 2026
847d752
feat: fix orgs
IMB11 Jan 16, 2026
bd5f036
Merge branch 'main' into worlds-and-shared-instances-components
IMB11 Jan 16, 2026
b54276f
feat: add ContentModpackCard
IMB11 Jan 19, 2026
74cc230
fix: extract types
IMB11 Jan 19, 2026
4a26d17
feat: selection v-model
IMB11 Jan 19, 2026
9732087
add show icon in selected for combobox with stories
tdgao Jan 19, 2026
1501b11
feat: add project combobox
tdgao Jan 19, 2026
b5a5a6a
clean up project combobox
tdgao Jan 19, 2026
51d84ca
feat: start install to play modal
tdgao Jan 19, 2026
95ea6df
fix: events
IMB11 Jan 20, 2026
f46a4fb
feat: figma alignments
IMB11 Jan 22, 2026
e0c871c
feat: migrate toggle to tailwind
IMB11 Jan 22, 2026
1850de7
fix: row borders
IMB11 Jan 22, 2026
144bde8
feat: disabled state
IMB11 Jan 22, 2026
ff5ed40
feat: virtual list impl for card table based on window scroll
IMB11 Jan 22, 2026
6f84acb
fix: lint
IMB11 Jan 22, 2026
bd5fbb3
feat: virtualization + smaller contentcard items
IMB11 Jan 22, 2026
d4af422
feat: fix gap + border issues on last elm
IMB11 Jan 22, 2026
067b346
fix: use TeleportOverflowMenu
IMB11 Jan 22, 2026
4877eae
fix: hasUpdate type
IMB11 Jan 22, 2026
af35e92
fix: fallback to svg if src is invalid on avatar component
IMB11 Jan 22, 2026
1712ed2
fix: storybook
IMB11 Jan 24, 2026
16f46a4
feat: start on updater modal
IMB11 Jan 24, 2026
1e70473
feat: finish content updater modal
IMB11 Jan 26, 2026
0c12fbe
feat: i18n pass
IMB11 Jan 26, 2026
61e69ac
Merge branch 'main' into worlds-and-shared-instances-components
IMB11 Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 1 addition & 66 deletions apps/frontend/src/assets/styles/components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,7 @@
:where(input) {
box-sizing: border-box;
max-height: 40px;

&:not(.stylized-toggle) {
max-width: 100%;
}
max-width: 100%;
}

:where(.adjacent-input, &.adjacent-input) {
Expand Down Expand Up @@ -271,10 +268,6 @@
&:not(&.small) {
flex-direction: column;
align-items: flex-start;

.stylized-toggle {
flex-basis: 0;
}
}
}
}
Expand Down Expand Up @@ -650,64 +643,6 @@ tr.button-transparent {
}
}

.switch {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
-webkit-tap-highlight-color: transparent;
cursor: pointer;

&:focus {
//outline: 0; Bad for accessibility
}
}

.stylized-toggle {
@extend .button-base;

box-sizing: content-box;
min-height: 32px;
height: 32px;
width: 52px;
max-width: 52px;
border-radius: var(--size-rounded-max);
display: inline-block;
position: relative;
margin: 0;
transition: all 0.2s ease;
background: var(--color-button-bg);

&:after {
content: '';
position: absolute;
top: 7px;
left: 7px;
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--color-toggle-handle);
transition: all 0.2s cubic-bezier(0.5, 0.1, 0.75, 1.35);
outline: 2px solid transparent;

@media (prefers-reduced-motion) {
transition: none;
}
}

&:checked {
background-color: var(--color-brand);

&:after {
transform: translatex(20px);
background: var(--color-brand-inverted);
}
}

&:hover &:focus {
background: var(--color-button-bg);
}
}

.textarea-wrapper {
display: flex;
flex-direction: column;
Expand Down
4 changes: 0 additions & 4 deletions apps/frontend/src/assets/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ html {
--color-button-bg-active: #c3c6cb;
--color-button-text-active: var(--color-button-text-hover);

--color-toggle-handle: var(--color-icon);

--color-dropdown-bg: var(--color-button-bg);
--color-dropdown-text: var(--color-button-text);

Expand Down Expand Up @@ -177,8 +175,6 @@ html {
--color-button-bg-active: #616570;
--color-button-text-active: var(--color-button-text-hover);

--color-toggle-handle: var(--color-button-text);

--color-dropdown-bg: var(--color-button-bg);
--color-dropdown-text: var(--color-button-text);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@
<label class="w-full text-lg font-bold text-contrast" for="modpack-hard-reset">
Erase all data
</label>
<input
id="modpack-hard-reset"
v-model="hardReset"
class="switch stylized-toggle shrink-0"
type="checkbox"
/>
<Toggle id="modpack-hard-reset" v-model="hardReset" class="shrink-0" />
</div>
<div>
If enabled, existing mods, worlds, and configurations, will be deleted before installing
Expand Down Expand Up @@ -69,7 +64,7 @@

<script setup lang="ts">
import { DownloadIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, Combobox, injectNotificationManager, NewModal } from '@modrinth/ui'
import { ButtonStyled, Combobox, injectNotificationManager, NewModal, Toggle } from '@modrinth/ui'
import { ModrinthServersFetchError } from '@modrinth/utils'

import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'
Expand Down Expand Up @@ -158,9 +153,3 @@ const hide = () => modal.value?.hide()

defineExpose({ show, hide })
</script>

<style scoped>
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>
14 changes: 2 additions & 12 deletions apps/frontend/src/components/ui/servers/PlatformMrpackModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,7 @@
<label class="w-full text-lg font-bold text-contrast" for="hard-reset">
Erase all data
</label>
<input
id="hard-reset"
v-model="hardReset"
class="switch stylized-toggle shrink-0"
type="checkbox"
/>
<Toggle id="hard-reset" v-model="hardReset" class="shrink-0" />
</div>
<div>
Removes all data on your server, including your worlds, mods, and configuration
Expand Down Expand Up @@ -128,6 +123,7 @@ import {
ButtonStyled,
injectNotificationManager,
NewModal,
Toggle,
} from '@modrinth/ui'
import { ModrinthServersFetchError } from '@modrinth/utils'
import { onMounted, onUnmounted } from 'vue'
Expand Down Expand Up @@ -255,9 +251,3 @@ const hide = () => mrpackModal.value?.hide()

defineExpose({ show, hide })
</script>

<style scoped>
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,7 @@
<label class="w-full text-lg font-bold text-contrast" for="hard-reset">
Erase all data
</label>
<input
id="hard-reset"
v-model="hardReset"
class="switch stylized-toggle shrink-0"
type="checkbox"
/>
<Toggle id="hard-reset" v-model="hardReset" class="shrink-0" />
</div>
<div>
Removes all data on your server, including your worlds, mods, and configuration files,
Expand Down Expand Up @@ -542,9 +537,3 @@ const hide = () => versionSelectModal.value?.hide()

defineExpose({ show, hide })
</script>

<style scoped>
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,6 @@ watch(
</script>

<style scoped>
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}

.button-base:active {
scale: none !important;
}
Expand Down
7 changes: 3 additions & 4 deletions apps/frontend/src/pages/[type]/[id]/settings/members.vue
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,10 @@
monetization weights to this user on the project.
</span>
</label>
<input
<Toggle
:id="`member-${allOrgMembers[index].user.username}-override-perms`"
v-model="allOrgMembers[index].override"
class="switch stylized-toggle"
type="checkbox"
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
:disabled="(props.currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
/>
</div>
<div class="adjacent-input">
Expand Down Expand Up @@ -534,6 +532,7 @@ import {
Checkbox,
ConfirmModal,
injectNotificationManager,
Toggle,
injectProjectPageContext,
} from '@modrinth/ui'
import { Multiselect } from 'vue-multiselect'
Expand Down
13 changes: 2 additions & 11 deletions apps/frontend/src/pages/discover/[type]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
SearchFilterControl,
SearchSidebarFilter,
type SortType,
Toggle,
useSearch,
} from '@modrinth/ui'
import { capitalizeString, cycleValue, type Mod as InstallableMod } from '@modrinth/utils'
Expand Down Expand Up @@ -460,13 +461,7 @@ useSeoMeta({
</div>
<div class="flex flex-row items-center justify-between gap-2 px-6">
<label for="erase-data-on-install"> Erase all data on install </label>
<input
id="erase-data-on-install"
v-model="eraseDataOnInstall"
label="Erase all data on install"
class="switch stylized-toggle flex-none"
type="checkbox"
/>
<Toggle id="erase-data-on-install" v-model="eraseDataOnInstall" class="flex-none" />
</div>
<div class="px-6 py-4 text-sm">
If enabled, existing mods, worlds, and configurations, will be deleted before installing
Expand Down Expand Up @@ -909,8 +904,4 @@ useSeoMeta({
mask-image: linear-gradient(to bottom, black, transparent);
opacity: 0.25;
}

.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>
95 changes: 52 additions & 43 deletions apps/frontend/src/pages/flags.vue
Original file line number Diff line number Diff line change
@@ -1,67 +1,76 @@
<script setup lang="ts">
import { SearchIcon } from '@modrinth/assets'
import { Toggle } from '@modrinth/ui'
import Fuse from 'fuse.js'
import { computed, ref, shallowReactive } from 'vue'

import {
DEFAULT_FEATURE_FLAGS,
type FeatureFlag,
saveFeatureFlags,
useFeatureFlags,
} from '~/composables/featureFlags.ts'

const flags = shallowReactive(useFeatureFlags().value)
const searchQuery = ref('')

const allFlags = computed(() => Object.keys(flags) as FeatureFlag[])

const fuse = computed(
() =>
new Fuse(allFlags.value, {
threshold: 0.4,
}),
)

const filteredFlags = computed(() => {
if (!searchQuery.value.trim()) {
return allFlags.value
}
return fuse.value.search(searchQuery.value).map((result) => result.item)
})
</script>

<template>
<div class="page">
<h1>Feature flags</h1>
<div class="flags">
<div class="mx-auto my-4 box-border w-[calc(100%-2rem)] max-w-[800px]">
<h1 class="mb-4 text-2xl font-bold text-contrast">Feature flags</h1>
<div class="relative mb-2">
<SearchIcon
class="pointer-events-none absolute left-3 top-1/2 size-5 -translate-y-1/2 text-secondary"
/>
<input
v-model="searchQuery"
type="search"
placeholder="Search flags..."
class="w-full rounded-xl bg-bg-raised py-2 pl-10 pr-4"
/>
</div>
<div class="flex flex-col gap-2">
<div
v-for="flag in Object.keys(flags) as FeatureFlag[]"
v-for="flag in filteredFlags"
:key="`flag-${flag}`"
class="adjacent-input small card"
class="flex flex-row flex-wrap items-center gap-2 rounded-2xl bg-bg-raised p-4"
>
<label :for="`toggle-${flag}`">
<span class="label__title">
<label :for="`toggle-${flag}`" class="flex-1">
<span class="block font-semibold capitalize">
{{ flag.replaceAll('_', ' ') }}
</span>
<span class="label__description">
<p>
Default:
<span
:style="`color:var(--color-${
DEFAULT_FEATURE_FLAGS[flag] === false ? 'red' : 'green'
})`"
>{{ DEFAULT_FEATURE_FLAGS[flag] }}</span
>
</p>
</span>
<p class="m-0 text-secondary">
Default:
<span :class="DEFAULT_FEATURE_FLAGS[flag] === false ? 'text-red' : 'text-green'">
{{ DEFAULT_FEATURE_FLAGS[flag] }}
</span>
</p>
</label>
<input
<Toggle
:id="`toggle-${flag}`"
v-model="flags[flag]"
class="switch stylized-toggle"
type="checkbox"
@change="() => saveFeatureFlags()"
@update:model-value="() => saveFeatureFlags()"
/>
</div>
<p v-if="filteredFlags.length === 0" class="text-center text-secondary">
No flags found matching "{{ searchQuery }}"
</p>
</div>
</div>
</template>

<style lang="scss" scoped>
.page {
width: calc(100% - 2 * var(--spacing-card-md));
max-width: 800px;
margin-inline: auto;
box-sizing: border-box;
margin-block: var(--spacing-card-md);
}

.flags {
}

.label__title {
text-transform: capitalize;
}

.label__description p {
margin: 0;
}
</style>
Loading
Loading