Skip to content

Commit

Permalink
Merge branch 'pyro' of github.com:/modrinth/code into pyro
Browse files Browse the repository at this point in the history
  • Loading branch information
not-nullptr committed Oct 16, 2024
2 parents 24aea4e + 0c4c5d9 commit 6679900
Show file tree
Hide file tree
Showing 21 changed files with 405 additions and 215 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/app-frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@modrinth/app-frontend",
"private": true,
"version": "0.8.8",
"version": "0.8.9",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion apps/app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "theseus_gui"
version = "0.8.8"
version = "0.8.9"
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
license = "GPL-3.0-only"
repository = "https://github.com/modrinth/code/apps/app/"
Expand Down
83 changes: 0 additions & 83 deletions apps/app/src/api/ads-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,86 +21,3 @@ document.addEventListener(
window.open = (url, target, features) => {
window.top.postMessage({ modrinthOpenUrl: url }, 'https://modrinth.com')
}

function muteAudioContext() {
if (window.AudioContext || window.webkitAudioContext) {
const AudioContext = window.AudioContext || window.webkitAudioContext
const originalCreateMediaElementSource = AudioContext.prototype.createMediaElementSource
const originalCreateMediaStreamSource = AudioContext.prototype.createMediaStreamSource
const originalCreateMediaStreamTrackSource = AudioContext.prototype.createMediaStreamTrackSource
const originalCreateBufferSource = AudioContext.prototype.createBufferSource
const originalCreateOscillator = AudioContext.prototype.createOscillator

AudioContext.prototype.createGain = function () {
const gain = originalCreateGain.call(this)
gain.gain.value = 0
return gain
}

AudioContext.prototype.createMediaElementSource = function (mediaElement) {
const source = originalCreateMediaElementSource.call(this, mediaElement)
source.connect(this.createGain())
return source
}

AudioContext.prototype.createMediaStreamSource = function (mediaStream) {
const source = originalCreateMediaStreamSource.call(this, mediaStream)
source.connect(this.createGain())
return source
}

AudioContext.prototype.createMediaStreamTrackSource = function (mediaStreamTrack) {
const source = originalCreateMediaStreamTrackSource.call(this, mediaStreamTrack)
source.connect(this.createGain())
return source
}

AudioContext.prototype.createBufferSource = function () {
const source = originalCreateBufferSource.call(this)
source.connect(this.createGain())
return source
}

AudioContext.prototype.createOscillator = function () {
const oscillator = originalCreateOscillator.call(this)
oscillator.connect(this.createGain())
return oscillator
}
}
}

function muteVideo(mediaElement) {
let count = Number(mediaElement.getAttribute('data-modrinth-muted-count') ?? 0)

if (!mediaElement.muted || mediaElement.volume !== 0) {
mediaElement.muted = true
mediaElement.volume = 0

mediaElement.setAttribute('data-modrinth-muted-count', count + 1)
}

if (count > 5) {
// Video is detected as malicious, so it is removed from the page
mediaElement.remove()
}
}

function muteVideos() {
document.querySelectorAll('video, audio').forEach(function (mediaElement) {
muteVideo(mediaElement)

if (!mediaElement.hasAttribute('data-modrinth-muted')) {
mediaElement.addEventListener('volumechange', () => muteVideo(mediaElement))

mediaElement.setAttribute('data-modrinth-muted', 'true')
}
})
}

document.addEventListener('DOMContentLoaded', () => {
muteVideos()
muteAudioContext()

const observer = new MutationObserver(muteVideos)
observer.observe(document.body, { childList: true, subtree: true })
})
2 changes: 1 addition & 1 deletion apps/app/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
]
},
"productName": "Modrinth App",
"version": "0.8.8",
"version": "0.8.9",
"mainBinaryName": "Modrinth App",
"identifier": "ModrinthApp",
"plugins": {
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@formatjs/cli": "^6.2.12",
"@nuxt/devtools": "^1.3.3",
"@nuxtjs/turnstile": "^0.8.0",
"@types/dompurify": "^3.0.5",
"@types/node": "^20.1.0",
"@vintl/compact-number": "^2.0.5",
"@vintl/how-ago": "^3.0.1",
Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/src/components/ui/AdPlaceholder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ onMounted(() => {
{
divId: "modrinth-rail-1",
baseDivId: "pb-slot-square-2",
targeting: {
location: "web",
},
},
]);
});
Expand Down
9 changes: 8 additions & 1 deletion apps/frontend/src/components/ui/servers/LogParser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ const parsedLog = computed(() => {
});
const sanitizedLog = computed(() => {
return DOMPurify.sanitize(parsedLog.value);
return DOMPurify.sanitize(parsedLog.value, {
ALLOWED_TAGS: ["span"],
ALLOWED_ATTR: ["style"],
ALLOWED_CSS_STYLES: {
color: true,
"background-color": true,
},
});
});
</script>

Expand Down
26 changes: 18 additions & 8 deletions apps/frontend/src/components/ui/servers/PanelTerminal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@
<div
class="absolute -bottom-2 -right-2 h-7 w-7"
:style="{
// background should be solid red bottom right corner of a circle
background: `radial-gradient(circle at 0% 0%, transparent 50%, var(--color-raised-bg) 52%)`,
}"
></div>
<div
class="absolute -bottom-2 -left-2 h-7 w-7"
:style="{
// background should be solid red bottom right corner of a circle
background: `radial-gradient(circle at 100% 0%, transparent 50%, var(--color-raised-bg) 52%)`,
}"
></div>
Expand Down Expand Up @@ -118,6 +116,8 @@ const clientHeight = ref(0);
const isFullScreen = ref(props.fullScreen);
const initial = ref(false);
const userHasScrolled = ref(false);
const isScrolledToBottom = ref(true);
const totalHeight = computed(
() =>
Expand All @@ -126,7 +126,6 @@ const totalHeight = computed(
);
watch(totalHeight, () => {
console.log(initial.value);
if (!initial.value) {
scrollToBottom();
}
Expand All @@ -136,7 +135,7 @@ watch(totalHeight, () => {
const lerp = (start: number, end: number, t: number) => start * (1 - t) + end * t;
const getBlurStyle = (i: number) => {
const properBlurIteration = i + 1; // Adjusting iteration for reverse order
const properBlurIteration = i + 1;
const blur = lerp(0, 2 ** (properBlurIteration - 3), bottomThreshold.value);
const singular = 100 / progressiveBlurIterations.value;
let mask = "linear-gradient(";
Expand All @@ -162,9 +161,10 @@ const getBlurStyle = (i: number) => {
backdropFilter: `blur(${blur}px)`,
mask,
position: "absolute" as any,
zIndex: progressiveBlurIterations.value - i, // Adjusting z-index for reverse order
zIndex: progressiveBlurIterations.value - i,
};
};
const getItemOffset = (index: number) => {
return itemHeights.value.slice(0, index).reduce((sum, height) => sum + height, 0);
};
Expand Down Expand Up @@ -205,11 +205,16 @@ const handleScroll = () => {
if (scrollContainer.value) {
scrollTop.value = scrollContainer.value.scrollTop;
clientHeight.value = scrollContainer.value.clientHeight;
const scrollHeight = scrollContainer.value.scrollHeight;
isScrolledToBottom.value = scrollTop.value + clientHeight.value >= scrollHeight - 32; // threshold
if (!isScrolledToBottom.value) {
userHasScrolled.value = true;
}
}
const maxBottom = 256;
// when we're at the very bottom of the scroll container, bottomThreshold should be 0
// when we're maxBottom pixels from the bottom of the scroll container, bottomThreshold should be 1
bottomThreshold.value = Math.min(
1,
((scrollContainer.value?.scrollHeight || 1) - scrollTop.value - clientHeight.value) / maxBottom,
Expand Down Expand Up @@ -242,6 +247,8 @@ const updateClientHeight = () => {
const scrollToBottom = () => {
if (scrollContainer.value) {
scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight + 99999999;
userHasScrolled.value = false;
isScrolledToBottom.value = true;
}
};
Expand Down Expand Up @@ -303,7 +310,9 @@ watch(
nextTick(() => {
updateItemHeights();
scrollToBottom();
if (!userHasScrolled.value || isScrolledToBottom.value) {
scrollToBottom();
}
});
},
{ deep: true, immediate: true },
Expand All @@ -329,6 +338,7 @@ watch(isFullScreen, () => {
});
});
</script>

<style scoped>
.terminal-font {
font-family: var(--mono-font);
Expand Down
108 changes: 79 additions & 29 deletions apps/frontend/src/components/ui/servers/SaveBanner.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
<template>
<div
class="save-banner fixed bottom-8 left-4 right-4 z-50 mx-auto h-fit w-full max-w-4xl rounded-2xl border-2 border-solid border-divider bg-bg-raised p-4 transition-all duration-300"
>
<div class="flex flex-col items-center justify-between gap-2 md:flex-row">
<span class="font-bold text-contrast">Careful, you have unsaved changes!</span>
<div class="flex gap-2">
<Button transparent :loading="props.isUpdating" @click="props.reset"> Reset </Button>
<Button color="primary" :loading="props.isUpdating" @click="props.save"> Save </Button>
<Button
v-if="props.restart"
color="primary"
:loading="props.isUpdating"
@click="saveAndRestart"
>
Save & Restart
</Button>
<transition name="save-banner">
<div
v-if="props.isVisible"
data-pyro-save-banner
class="save-banner fixed bottom-8 left-4 right-4 z-50 mx-auto h-fit w-full max-w-4xl rounded-2xl border-2 border-solid border-divider bg-bg-raised p-4 transition-all duration-300"
>
<div class="flex flex-col items-center justify-between gap-2 md:flex-row">
<span class="font-bold text-contrast">Careful, you have unsaved changes!</span>
<div class="flex gap-2">
<ButtonStyled type="transparent" color="standard" transparent>
<button :disabled="props.isUpdating" @click="props.reset">Reset</button>
</ButtonStyled>
<ButtonStyled type="standard" color="brand">
<button :disabled="props.isUpdating" @click="props.save">
{{ props.isUpdating ? "Saving..." : "Save" }}
</button>
</ButtonStyled>
<ButtonStyled v-if="props.restart" type="standard" color="brand">
<button :disabled="props.isUpdating" @click="saveAndRestart">
{{ props.isUpdating ? "Saving..." : "Save & Restart" }}
</button>
</ButtonStyled>
</div>
</div>
</div>
</div>
</transition>
</template>

<script setup lang="ts">
import { Button } from "@modrinth/ui";
import { ButtonStyled } from "@modrinth/ui";
import type { Server } from "~/composables/pyroServers";
const props = defineProps<{
isUpdating: boolean;
restart?: boolean;
save: () => void;
reset: () => void;
isVisible: boolean;
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>;
}>();
Expand All @@ -39,18 +47,60 @@ const saveAndRestart = async () => {
</script>

<style scoped>
.save-banner {
animation: slide-up 200ms ease;
.save-banner-enter-active {
transition:
opacity 800ms,
transform 800ms;
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(100%);
}
to {
opacity: 1;
transform: translateY(0);
}
.save-banner-leave-active {
transition:
opacity 200ms,
transform 200ms;
}
.save-banner-enter-active {
transition-timing-function: linear(
0 0%,
0.01 0.8%,
0.04 1.6%,
0.161 3.3%,
0.816 9.4%,
1.046 11.9%,
1.189 14.4%,
1.231 15.7%,
1.254 17%,
1.259 17.8%,
1.257 18.6%,
1.236 20.45%,
1.194 22.3%,
1.057 27%,
0.999 29.4%,
0.955 32.1%,
0.942 33.5%,
0.935 34.9%,
0.933 36.65%,
0.939 38.4%,
1 47.3%,
1.011 49.95%,
1.017 52.6%,
1.016 56.4%,
1 65.2%,
0.996 70.2%,
1.001 87.2%,
1 100%
);
}
.save-banner-enter-from,
.save-banner-leave-to {
opacity: 0;
transform: translateY(100%) scale(0.98);
}
.save-banner-enter-to,
.save-banner-leave-from {
opacity: 1;
transform: none;
}
</style>
Loading

0 comments on commit 6679900

Please sign in to comment.