Implement ads in desktop app (#2318)
* Implement ads in desktop app * Finish ads * use git dep instead * attempt to fix linux build (temp) * bump version + lint * comment more * fix build * try to fix linux build * Fix crashing on windows * Fix icons not showing * Remove useless env vars * Actual linux build fix * Run fmt * Fix scrolling * fix clippy * bump version + fix localhost * rev linux build patch * update version num * update csp * update csp * update csp * Switch to mousewheel event
This commit is contained in:
parent
4bafae881f
commit
acf26940d6
166
Cargo.lock
generated
166
Cargo.lock
generated
@ -663,7 +663,7 @@ dependencies = [
|
|||||||
"cocoa-foundation 0.1.2",
|
"cocoa-foundation 0.1.2",
|
||||||
"core-foundation 0.9.4",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics 0.23.2",
|
"core-graphics 0.23.2",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
@ -679,7 +679,7 @@ dependencies = [
|
|||||||
"cocoa-foundation 0.2.0",
|
"cocoa-foundation 0.2.0",
|
||||||
"core-foundation 0.10.0",
|
"core-foundation 0.10.0",
|
||||||
"core-graphics 0.24.0",
|
"core-graphics 0.24.0",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
@ -817,7 +817,7 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation 0.9.4",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics-types 0.1.3",
|
"core-graphics-types 0.1.3",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -830,7 +830,7 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"core-foundation 0.10.0",
|
"core-foundation 0.10.0",
|
||||||
"core-graphics-types 0.2.0",
|
"core-graphics-types 0.2.0",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1531,6 +1531,15 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared 0.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -1538,7 +1547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-macros",
|
"foreign-types-macros",
|
||||||
"foreign-types-shared",
|
"foreign-types-shared 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1552,6 +1561,12 @@ dependencies = [
|
|||||||
"syn 2.0.74",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types-shared"
|
name = "foreign-types-shared"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -2227,6 +2242,22 @@ dependencies = [
|
|||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -2841,6 +2872,23 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -3221,6 +3269,60 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types 0.3.2",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.74",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "300.3.1+3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -4008,11 +4110,13 @@ dependencies = [
|
|||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
|
"native-tls",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -4026,6 +4130,7 @@ dependencies = [
|
|||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"system-configuration",
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@ -4220,6 +4325,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schemars"
|
name = "schemars"
|
||||||
version = "0.8.21"
|
version = "0.8.21"
|
||||||
@ -4272,6 +4386,29 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"core-foundation 0.9.4",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
@ -4581,7 +4718,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-graphics 0.23.2",
|
"core-graphics 0.23.2",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
@ -5474,7 +5611,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "theseus"
|
name = "theseus"
|
||||||
version = "0.8.3-1"
|
version = "0.8.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
@ -5525,7 +5662,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "theseus_gui"
|
name = "theseus_gui"
|
||||||
version = "0.8.3-1"
|
version = "0.8.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"cocoa 0.25.0",
|
"cocoa 0.25.0",
|
||||||
@ -5702,6 +5839,16 @@ dependencies = [
|
|||||||
"syn 2.0.74",
|
"syn 2.0.74",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@ -6882,8 +7029,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wry"
|
name = "wry"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/modrinth/wry?rev=23b0ee4#23b0ee4ea1c1956db7edefac8e4fd710f548c85d"
|
||||||
checksum = "49b8049c8f239cdbfaaea4bacb9646f6b208938ceec0acd5b3e99cd05f70903f"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"block",
|
"block",
|
||||||
|
|||||||
@ -16,3 +16,6 @@ strip = true # Remove debug symbols
|
|||||||
|
|
||||||
[profile.dev.package.sqlx-macros]
|
[profile.dev.package.sqlx-macros]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
wry = { git = "https://github.com/modrinth/wry", rev = "23b0ee4" }
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@modrinth/app-frontend",
|
"name": "@modrinth/app-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.8.3-1",
|
"version": "0.8.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { useInstall } from '@/store/install.js'
|
|||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { open } from '@tauri-apps/plugin-shell'
|
import { open } from '@tauri-apps/plugin-shell'
|
||||||
import { get_opening_command, initialize_state } from '@/helpers/state'
|
import { get_opening_command, initialize_state } from '@/helpers/state'
|
||||||
|
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
@ -126,6 +127,7 @@ initialize_state()
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleClose = async () => {
|
const handleClose = async () => {
|
||||||
|
await saveWindowState(StateFlags.ALL)
|
||||||
await getCurrentWindow().close()
|
await getCurrentWindow().close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { Promotion } from '@modrinth/ui'
|
|
||||||
import { get as getCreds } from '@/helpers/mr_auth.js'
|
import { get as getCreds } from '@/helpers/mr_auth.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { get_user } from '@/helpers/cache.js'
|
import { get_user } from '@/helpers/cache.js'
|
||||||
|
import { ChevronRightIcon } from '@modrinth/assets'
|
||||||
|
import { init_ads_window } from '@/helpers/ads.js'
|
||||||
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
|
||||||
const showAd = ref(true)
|
const showAd = ref(true)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
scroll() {
|
||||||
|
updateAdPosition()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const creds = await getCreds().catch(handleError)
|
const creds = await getCreds().catch(handleError)
|
||||||
if (creds && creds.user_id) {
|
if (creds && creds.user_id) {
|
||||||
const user = await get_user(creds.user_id).catch(handleError)
|
const user = await get_user(creds.user_id).catch(handleError)
|
||||||
@ -16,8 +24,98 @@ if (creds && creds.user_id) {
|
|||||||
showAd.value = false
|
showAd.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const adsWrapper = ref(null)
|
||||||
|
let resizeObserver
|
||||||
|
let scrollHandler
|
||||||
|
let intersectionObserver
|
||||||
|
let mutationObserver
|
||||||
|
onMounted(() => {
|
||||||
|
if (showAd.value) {
|
||||||
|
updateAdPosition()
|
||||||
|
|
||||||
|
resizeObserver = new ResizeObserver(updateAdPosition)
|
||||||
|
resizeObserver.observe(adsWrapper.value)
|
||||||
|
|
||||||
|
intersectionObserver = new IntersectionObserver(updateAdPosition)
|
||||||
|
intersectionObserver.observe(adsWrapper.value)
|
||||||
|
|
||||||
|
mutationObserver = new MutationObserver(updateAdPosition)
|
||||||
|
mutationObserver.observe(adsWrapper.value, { attributes: true, childList: true, subtree: true })
|
||||||
|
|
||||||
|
// Add scroll event listener
|
||||||
|
scrollHandler = () => {
|
||||||
|
requestAnimationFrame(updateAdPosition)
|
||||||
|
}
|
||||||
|
window.addEventListener('scroll', scrollHandler, { passive: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateAdPosition() {
|
||||||
|
if (adsWrapper.value) {
|
||||||
|
const rect = adsWrapper.value.getBoundingClientRect()
|
||||||
|
|
||||||
|
let y = rect.top + window.scrollY
|
||||||
|
let height = rect.bottom - rect.top
|
||||||
|
|
||||||
|
// Prevent ad from overlaying the app bar
|
||||||
|
if (y <= 52) {
|
||||||
|
y = 52
|
||||||
|
height = rect.bottom - 52
|
||||||
|
|
||||||
|
if (height < 0) {
|
||||||
|
height = 0
|
||||||
|
y = -1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init_ads_window(rect.left + window.scrollX, y, rect.right - rect.left, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unlisten = await listen('ads-scroll', (event) => {
|
||||||
|
if (adsWrapper.value) {
|
||||||
|
adsWrapper.value.parentNode.scrollTop += event.payload.scroll
|
||||||
|
updateAdPosition()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (intersectionObserver) {
|
||||||
|
intersectionObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (mutationObserver) {
|
||||||
|
mutationObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (scrollHandler) {
|
||||||
|
window.removeEventListener('scroll', scrollHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
unlisten()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Promotion v-if="showAd" :external="false" query-param="?r=launcher" />
|
<div
|
||||||
|
v-if="showAd"
|
||||||
|
ref="adsWrapper"
|
||||||
|
class="ad-parent relative mb-3 flex w-full justify-center rounded-2xl bg-bg-raised cursor-pointer"
|
||||||
|
>
|
||||||
|
<div class="flex max-h-[250px] min-h-[250px] min-w-[300px] max-w-[300px] flex-col gap-4 p-6">
|
||||||
|
<p class="m-0 text-2xl font-bold text-contrast">90% of ad revenue goes to creators</p>
|
||||||
|
<a
|
||||||
|
href="https://modrinth.com/plus"
|
||||||
|
class="mt-auto items-center gap-1 text-purple hover:underline"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Support creators and Modrinth ad-free with
|
||||||
|
<span class="font-bold">Modrinth+</span>
|
||||||
|
</span>
|
||||||
|
<ChevronRightIcon class="relative top-[3px] h-5 w-5" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
9
apps/app-frontend/src/helpers/ads.js
Normal file
9
apps/app-frontend/src/helpers/ads.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
|
export async function init_ads_window(x, y, width, height) {
|
||||||
|
return await invoke('plugin:ads|init_ads_window', { x, y, width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hide_ads_window() {
|
||||||
|
return await invoke('plugin:ads|hide_ads_window')
|
||||||
|
}
|
||||||
@ -528,7 +528,8 @@ const isModProject = computed(() => ['modpack', 'mod'].includes(projectType.valu
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="searchWrapper" class="search-container">
|
<div ref="searchWrapper" class="search-container">
|
||||||
<aside class="filter-panel">
|
<aside class="filter-panel" @scroll="$refs.promo.scroll()">
|
||||||
|
<PromotionWrapper ref="promo" />
|
||||||
<Card v-if="instanceContext" class="small-instance">
|
<Card v-if="instanceContext" class="small-instance">
|
||||||
<router-link :to="`/instance/${encodeURIComponent(instanceContext.path)}`" class="instance">
|
<router-link :to="`/instance/${encodeURIComponent(instanceContext.path)}`" class="instance">
|
||||||
<Avatar
|
<Avatar
|
||||||
@ -675,8 +676,7 @@ const isModProject = computed(() => ['modpack', 'mod'].includes(projectType.valu
|
|||||||
</Card>
|
</Card>
|
||||||
</aside>
|
</aside>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<PromotionWrapper class="mt-4" />
|
<Card class="project-type-container mt-4">
|
||||||
<Card class="project-type-container">
|
|
||||||
<NavRow :links="selectableProjectTypes" />
|
<NavRow :links="selectableProjectTypes" />
|
||||||
</Card>
|
</Card>
|
||||||
<Card class="search-panel-container">
|
<Card class="search-panel-container">
|
||||||
@ -878,7 +878,6 @@ const isModProject = computed(() => ['modpack', 'mod'].includes(projectType.valu
|
|||||||
|
|
||||||
.filter-panel {
|
.filter-panel {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 20rem;
|
|
||||||
padding: 1rem 0.5rem 1rem 1rem;
|
padding: 1rem 0.5rem 1rem 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -903,8 +902,8 @@ const isModProject = computed(() => ['modpack', 'mod'].includes(projectType.valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
margin: 0 1rem 0.5rem 20.5rem;
|
margin: 0 1rem 0.5rem calc(300px + 2.5rem);
|
||||||
width: calc(100% - 20.5rem);
|
width: calc(100% - calc(300px + 2.5rem));
|
||||||
|
|
||||||
.offline {
|
.offline {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onUnmounted, computed } from 'vue'
|
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import RowDisplay from '@/components/RowDisplay.vue'
|
import RowDisplay from '@/components/RowDisplay.vue'
|
||||||
import { list } from '@/helpers/profile.js'
|
import { list } from '@/helpers/profile.js'
|
||||||
@ -8,6 +8,11 @@ import { useBreadcrumbs } from '@/store/breadcrumbs'
|
|||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { get_search_results } from '@/helpers/cache.js'
|
import { get_search_results } from '@/helpers/cache.js'
|
||||||
|
import { hide_ads_window } from '@/helpers/ads.js'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
hide_ads_window()
|
||||||
|
})
|
||||||
|
|
||||||
const featuredModpacks = ref({})
|
const featuredModpacks = ref({})
|
||||||
const featuredMods = ref({})
|
const featuredMods = ref({})
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onUnmounted, ref, shallowRef } from 'vue'
|
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
|
||||||
import GridDisplay from '@/components/GridDisplay.vue'
|
import GridDisplay from '@/components/GridDisplay.vue'
|
||||||
import { list } from '@/helpers/profile.js'
|
import { list } from '@/helpers/profile.js'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
@ -10,6 +10,11 @@ import { Button } from '@modrinth/ui'
|
|||||||
import { PlusIcon } from '@modrinth/assets'
|
import { PlusIcon } from '@modrinth/assets'
|
||||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||||
import { NewInstanceImage } from '@/assets/icons'
|
import { NewInstanceImage } from '@/assets/icons'
|
||||||
|
import { hide_ads_window } from '@/helpers/ads.js'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
hide_ads_window()
|
||||||
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const breadcrumbs = useBreadcrumbs()
|
const breadcrumbs = useBreadcrumbs()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch, onMounted } from 'vue'
|
||||||
import { LogOutIcon, LogInIcon, BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
import { LogOutIcon, LogInIcon, BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||||
import { Card, Slider, DropdownSelect, Toggle, ConfirmModal, Button } from '@modrinth/ui'
|
import { Card, Slider, DropdownSelect, Toggle, ConfirmModal, Button } from '@modrinth/ui'
|
||||||
import { handleError, useTheming } from '@/store/state'
|
import { handleError, useTheming } from '@/store/state'
|
||||||
@ -13,6 +13,11 @@ import { open } from '@tauri-apps/plugin-dialog'
|
|||||||
import { getOS } from '@/helpers/utils.js'
|
import { getOS } from '@/helpers/utils.js'
|
||||||
import { getVersion } from '@tauri-apps/api/app'
|
import { getVersion } from '@tauri-apps/api/app'
|
||||||
import { get_user, purge_cache_types } from '@/helpers/cache.js'
|
import { get_user, purge_cache_types } from '@/helpers/cache.js'
|
||||||
|
import { hide_ads_window } from '@/helpers/ads.js'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
hide_ads_window()
|
||||||
|
})
|
||||||
|
|
||||||
const pageOptions = ['Home', 'Library']
|
const pageOptions = ['Home', 'Library']
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="instance-container">
|
<div class="instance-container">
|
||||||
<div class="side-cards">
|
<div class="side-cards pb-4" @scroll="$refs.promo.scroll()">
|
||||||
<Card class="instance-card" @contextmenu.prevent.stop="handleRightClick">
|
<Card class="instance-card" @contextmenu.prevent.stop="handleRightClick">
|
||||||
<Avatar size="lg" :src="instance.icon_path ? convertFileSrc(instance.icon_path) : null" />
|
<Avatar size="md" :src="instance.icon_path ? convertFileSrc(instance.icon_path) : null" />
|
||||||
<div class="instance-info">
|
<div class="instance-info">
|
||||||
<h2 class="name">{{ instance.name }}</h2>
|
<h2 class="name">{{ instance.name }}</h2>
|
||||||
<span class="metadata"> {{ instance.loader }} {{ instance.game_version }} </span>
|
<span class="metadata"> {{ instance.loader }} {{ instance.game_version }} </span>
|
||||||
@ -61,9 +61,9 @@
|
|||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
<PromotionWrapper ref="promo" class="mt-4" />
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<PromotionWrapper />
|
|
||||||
<RouterView v-slot="{ Component }">
|
<RouterView v-slot="{ Component }">
|
||||||
<template v-if="Component">
|
<template v-if="Component">
|
||||||
<Suspense @pending="loadingBar.startLoading()" @resolve="loadingBar.stopLoading()">
|
<Suspense @pending="loadingBar.startLoading()" @resolve="loadingBar.stopLoading()">
|
||||||
@ -311,7 +311,6 @@ onUnmounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
width: 17rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
@ -325,12 +324,13 @@ Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.side-cards {
|
.side-cards {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
|
width: 300px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1rem;
|
|
||||||
min-height: calc(100% - 3.25rem);
|
min-height: calc(100vh - 3.25rem);
|
||||||
max-height: calc(100% - 3.25rem);
|
max-height: calc(100vh - 3.25rem);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@ -374,10 +374,7 @@ Button {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
padding: 1rem;
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-left: 19rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.instance-info {
|
.instance-info {
|
||||||
@ -451,10 +448,10 @@ Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
width: 100%;
|
margin: 0 1rem 0.5rem 20rem;
|
||||||
|
width: calc(100% - 20rem);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1rem 1rem 0 0;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="root-container">
|
<div class="root-container">
|
||||||
<div v-if="data" class="project-sidebar">
|
<div v-if="data" class="project-sidebar" @scroll="$refs.promo.scroll()">
|
||||||
<Card v-if="instance" class="small-instance">
|
<Card v-if="instance" class="small-instance">
|
||||||
<router-link class="instance" :to="`/instance/${encodeURIComponent(instance.path)}`">
|
<router-link class="instance" :to="`/instance/${encodeURIComponent(instance.path)}`">
|
||||||
<Avatar
|
<Avatar
|
||||||
@ -20,7 +20,7 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</Card>
|
</Card>
|
||||||
<Card class="sidebar-card" @contextmenu.prevent.stop="handleRightClick">
|
<Card class="sidebar-card" @contextmenu.prevent.stop="handleRightClick">
|
||||||
<Avatar size="lg" :src="data.icon_url" />
|
<Avatar size="md" :src="data.icon_url" />
|
||||||
<div class="instance-info">
|
<div class="instance-info">
|
||||||
<h2 class="name">{{ data.title }}</h2>
|
<h2 class="name">{{ data.title }}</h2>
|
||||||
{{ data.description }}
|
{{ data.description }}
|
||||||
@ -61,7 +61,9 @@
|
|||||||
Site
|
Site
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<hr class="card-divider" />
|
</Card>
|
||||||
|
<PromotionWrapper ref="promo" />
|
||||||
|
<Card class="sidebar-card">
|
||||||
<div class="stats">
|
<div class="stats">
|
||||||
<div class="stat">
|
<div class="stat">
|
||||||
<DownloadIcon aria-hidden="true" />
|
<DownloadIcon aria-hidden="true" />
|
||||||
@ -163,7 +165,6 @@
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data" class="content-container">
|
<div v-if="data" class="content-container">
|
||||||
<PromotionWrapper />
|
|
||||||
<Card class="tabs">
|
<Card class="tabs">
|
||||||
<NavRow
|
<NavRow
|
||||||
v-if="data.gallery.length > 0"
|
v-if="data.gallery.length > 0"
|
||||||
@ -309,11 +310,13 @@ async function fetchProjectData() {
|
|||||||
|
|
||||||
await fetchProjectData()
|
await fetchProjectData()
|
||||||
|
|
||||||
|
const promo = ref(null)
|
||||||
watch(
|
watch(
|
||||||
() => route.params.id,
|
() => route.params.id,
|
||||||
async () => {
|
async () => {
|
||||||
if (route.params.id && route.path.startsWith('/project')) {
|
if (route.params.id && route.path.startsWith('/project')) {
|
||||||
await fetchProjectData()
|
await fetchProjectData()
|
||||||
|
promo.value.scroll()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -377,7 +380,7 @@ const handleOptionsClick = (args) => {
|
|||||||
|
|
||||||
.project-sidebar {
|
.project-sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 20rem;
|
width: calc(300px + 1.5rem);
|
||||||
min-height: calc(100vh - 3.25rem);
|
min-height: calc(100vh - 3.25rem);
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
max-height: calc(100vh - 3.25rem);
|
max-height: calc(100vh - 3.25rem);
|
||||||
@ -403,7 +406,7 @@ const handleOptionsClick = (args) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-left: 19.5rem;
|
margin-left: calc(300px + 1rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.button-group {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "theseus_gui"
|
name = "theseus_gui"
|
||||||
version = "0.8.3-1"
|
version = "0.8.3"
|
||||||
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
|
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
repository = "https://github.com/modrinth/code/apps/app/"
|
repository = "https://github.com/modrinth/code/apps/app/"
|
||||||
@ -57,6 +57,9 @@ cocoa = "0.25.0"
|
|||||||
objc = "0.2.7"
|
objc = "0.2.7"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
tauri-plugin-updater = { version = "2.0.0-rc.1", optional = true, features = ["native-tls-vendored", "zip"], default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||||
|
|||||||
@ -217,6 +217,18 @@ fn main() {
|
|||||||
.default_permission(
|
.default_permission(
|
||||||
DefaultPermissionRule::AllowAllCommands,
|
DefaultPermissionRule::AllowAllCommands,
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
.plugin(
|
||||||
|
"ads",
|
||||||
|
InlinedPlugin::new()
|
||||||
|
.commands(&[
|
||||||
|
"init_ads_window",
|
||||||
|
"hide_ads_window",
|
||||||
|
"scroll_ads_window",
|
||||||
|
])
|
||||||
|
.default_permission(
|
||||||
|
DefaultPermissionRule::AllowAllCommands,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.expect("Failed to run tauri-build");
|
.expect("Failed to run tauri-build");
|
||||||
|
|||||||
15
apps/app/capabilities/ads.json
Normal file
15
apps/app/capabilities/ads.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"identifier": "ads",
|
||||||
|
"description": "",
|
||||||
|
"local": false,
|
||||||
|
"remote": {
|
||||||
|
"urls": ["https://modrinth.com/*", "http://localhost:3000/*"]
|
||||||
|
},
|
||||||
|
"webviews": [
|
||||||
|
"ads-window"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
"shell:allow-open",
|
||||||
|
"ads:default"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -35,6 +35,7 @@
|
|||||||
"cache:default",
|
"cache:default",
|
||||||
"settings:default",
|
"settings:default",
|
||||||
"tags:default",
|
"tags:default",
|
||||||
"utils:default"
|
"utils:default",
|
||||||
|
"ads:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
{"core":{"identifier":"core","description":"","local":true,"windows":["main"],"permissions":["core:default","core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","core:window:allow-create","core:window:allow-maximize","core:window:allow-toggle-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-start-dragging","core:webview:allow-set-webview-zoom"]},"plugins":{"identifier":"plugins","description":"","local":true,"windows":["main"],"permissions":["dialog:allow-open","dialog:allow-confirm","shell:allow-open","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","deep-link:default","window-state:default","window-state:allow-restore-state","window-state:allow-save-window-state","auth:default","import:default","jre:default","logs:default","metadata:default","mr-auth:default","profile-create:default","pack:default","process:default","profile:default","cache:default","settings:default","tags:default","utils:default"]}}
|
{"ads":{"identifier":"ads","description":"","remote":{"urls":["https://modrinth.com/*","http://localhost:3000/*"]},"local":false,"webviews":["ads-window"],"permissions":["shell:allow-open","ads:default"]},"core":{"identifier":"core","description":"","local":true,"windows":["main"],"permissions":["core:default","core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","core:window:allow-create","core:window:allow-maximize","core:window:allow-toggle-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-start-dragging","core:webview:allow-set-webview-zoom"]},"plugins":{"identifier":"plugins","description":"","local":true,"windows":["main"],"permissions":["dialog:allow-open","dialog:allow-confirm","shell:allow-open","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","deep-link:default","window-state:default","window-state:allow-restore-state","window-state:allow-save-window-state","auth:default","import:default","jre:default","logs:default","metadata:default","mr-auth:default","profile-create:default","pack:default","process:default","profile:default","cache:default","settings:default","tags:default","utils:default","ads:default"]}}
|
||||||
@ -299,6 +299,55 @@
|
|||||||
},
|
},
|
||||||
"Identifier": {
|
"Identifier": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "ads:default -> Default plugin permissions.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:default"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-hide-ads-window -> Enables the hide_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-hide-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-init-ads-window -> Enables the init_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-init-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-scroll-ads-window -> Enables the scroll_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-scroll-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-hide-ads-window -> Denies the hide_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-hide-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-init-ads-window -> Denies the init_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-init-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-scroll-ads-window -> Denies the scroll_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-scroll-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "auth:default -> Default plugin permissions.",
|
"description": "auth:default -> Default plugin permissions.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -299,6 +299,55 @@
|
|||||||
},
|
},
|
||||||
"Identifier": {
|
"Identifier": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "ads:default -> Default plugin permissions.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:default"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-hide-ads-window -> Enables the hide_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-hide-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-init-ads-window -> Enables the init_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-init-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:allow-scroll-ads-window -> Enables the scroll_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:allow-scroll-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-hide-ads-window -> Denies the hide_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-hide-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-init-ads-window -> Denies the init_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-init-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ads:deny-scroll-ads-window -> Denies the scroll_ads_window command without any pre-configured scope.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ads:deny-scroll-ads-window"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "auth:default -> Default plugin permissions.",
|
"description": "auth:default -> Default plugin permissions.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
17
apps/app/src/api/ads-init.js
Normal file
17
apps/app/src/api/ads-init.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
let target = e.target
|
||||||
|
while (target != null) {
|
||||||
|
if (target.matches('a')) {
|
||||||
|
e.preventDefault()
|
||||||
|
if (target.href) {
|
||||||
|
window.top.postMessage({ modrinthOpenUrl: target.href }, 'https://modrinth.com')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
target = target.parentElement
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.open = (url, target, features) => {
|
||||||
|
window.top.postMessage({ modrinthOpenUrl: url }, 'https://modrinth.com')
|
||||||
|
}
|
||||||
82
apps/app/src/api/ads.rs
Normal file
82
apps/app/src/api/ads.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use tauri::plugin::TauriPlugin;
|
||||||
|
use tauri::{
|
||||||
|
Emitter, LogicalPosition, LogicalSize, Manager, Runtime, WebviewUrl,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
|
tauri::plugin::Builder::<R>::new("ads")
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
init_ads_window,
|
||||||
|
hide_ads_window,
|
||||||
|
scroll_ads_window,
|
||||||
|
])
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
const LINK_SCRIPT: &str = include_str!("ads-init.js");
|
||||||
|
|
||||||
|
// TODO: make ads work on linux
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn init_ads_window<R: Runtime>(
|
||||||
|
app: tauri::AppHandle<R>,
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
) -> crate::api::Result<()> {
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
{
|
||||||
|
if let Some(webview) = app.webviews().get("ads-window") {
|
||||||
|
let _ = webview.set_position(LogicalPosition::new(x, y));
|
||||||
|
let _ = webview.set_size(LogicalSize::new(width, height));
|
||||||
|
} else if let Some(window) = app.get_window("main") {
|
||||||
|
let _ = window.add_child(
|
||||||
|
tauri::webview::WebviewBuilder::new(
|
||||||
|
"ads-window",
|
||||||
|
WebviewUrl::External(
|
||||||
|
"https://modrinth.com/wrapper/app-ads".parse().unwrap(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.initialization_script(LINK_SCRIPT)
|
||||||
|
.user_agent("ModrinthApp Ads Webview")
|
||||||
|
.zoom_hotkeys_enabled(false)
|
||||||
|
.transparent(true),
|
||||||
|
LogicalPosition::new(x, y),
|
||||||
|
LogicalSize::new(width, height),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn hide_ads_window<R: Runtime>(
|
||||||
|
app: tauri::AppHandle<R>,
|
||||||
|
) -> crate::api::Result<()> {
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
{
|
||||||
|
if let Some(webview) = app.webviews().get("ads-window") {
|
||||||
|
let _ = webview.set_position(LogicalPosition::new(-1000, -1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
struct ScrollEvent {
|
||||||
|
scroll: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn scroll_ads_window<R: Runtime>(
|
||||||
|
app: tauri::AppHandle<R>,
|
||||||
|
scroll: f32,
|
||||||
|
) -> crate::api::Result<()> {
|
||||||
|
let _ = app.emit("ads-scroll", ScrollEvent { scroll });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ pub mod settings;
|
|||||||
pub mod tags;
|
pub mod tags;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
pub mod ads;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
|
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
|
||||||
|
|||||||
@ -31,6 +31,8 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
|||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
app.asset_protocol_scope()
|
app.asset_protocol_scope()
|
||||||
.allow_directory(state.directories.caches_dir(), true)?;
|
.allow_directory(state.directories.caches_dir(), true)?;
|
||||||
|
app.asset_protocol_scope()
|
||||||
|
.allow_directory(state.directories.caches_dir().join("icons"), true)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -39,7 +41,7 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
|||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn show_window(app: tauri::AppHandle) {
|
fn show_window(app: tauri::AppHandle) {
|
||||||
let win = app.get_webview_window("main").unwrap();
|
let win = app.get_window("main").unwrap();
|
||||||
if let Err(e) = win.show() {
|
if let Err(e) = win.show() {
|
||||||
MessageDialog::new()
|
MessageDialog::new()
|
||||||
.set_type(MessageType::Error)
|
.set_type(MessageType::Error)
|
||||||
@ -179,6 +181,7 @@ fn main() {
|
|||||||
.plugin(api::tags::init())
|
.plugin(api::tags::init())
|
||||||
.plugin(api::utils::init())
|
.plugin(api::utils::init())
|
||||||
.plugin(api::cache::init())
|
.plugin(api::cache::init())
|
||||||
|
.plugin(api::ads::init())
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
initialize_state,
|
initialize_state,
|
||||||
is_dev,
|
is_dev,
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"productName": "Modrinth App",
|
"productName": "Modrinth App",
|
||||||
"version": "0.8.3-1",
|
"version": "0.8.3",
|
||||||
"identifier": "ModrinthApp",
|
"identifier": "ModrinthApp",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"deep-link": {
|
"deep-link": {
|
||||||
@ -70,10 +70,10 @@
|
|||||||
"resizable": true,
|
"resizable": true,
|
||||||
"title": "Modrinth App",
|
"title": "Modrinth App",
|
||||||
"width": 1280,
|
"width": 1280,
|
||||||
"minHeight": 700,
|
"minHeight": 750,
|
||||||
"minWidth": 1100,
|
"minWidth": 1100,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"zoomHotkeysEnabled": true,
|
"zoomHotkeysEnabled": false,
|
||||||
"decorations": false
|
"decorations": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -86,7 +86,17 @@
|
|||||||
],
|
],
|
||||||
"enable": true
|
"enable": true
|
||||||
},
|
},
|
||||||
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://*.cloudflare.com https://api.mclo.gs; font-src https://cdn-raw.modrinth.com/fonts/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost; script-src https://*.cloudflare.com 'self'; frame-src https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'; style-src unsafe-inline 'self'"
|
"csp": {
|
||||||
|
"default-src": "'self' customprotocol: asset:",
|
||||||
|
"connect-src": "ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://*.cloudflare.com https://api.mclo.gs https://cmp.inmobi.com",
|
||||||
|
"font-src": [
|
||||||
|
"https://cdn-raw.modrinth.com/fonts/inter/"
|
||||||
|
],
|
||||||
|
"img-src": "https: 'unsafe-inline' 'self' asset: http://asset.localhost blob: data:",
|
||||||
|
"style-src": "'unsafe-inline' 'self'",
|
||||||
|
"script-src": "https://cmp.inmobi.com https://*.cloudflare.com 'self'",
|
||||||
|
"frame-src": "https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
"minHeight": 700,
|
"minHeight": 700,
|
||||||
"minWidth": 1100,
|
"minWidth": 1100,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"zoomHotkeysEnabled": true,
|
"zoomHotkeysEnabled": false,
|
||||||
"decorations": true
|
"decorations": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
94
apps/frontend/src/public/promo-frame.html
Normal file
94
apps/frontend/src/public/promo-frame.html
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Modrinth App Ad</title>
|
||||||
|
<script
|
||||||
|
src="https://dn0qt3r0xannq.cloudfront.net/modrinth-7JfmkEIXEp/modrinth-longform/prebid-load.js"
|
||||||
|
async
|
||||||
|
></script>
|
||||||
|
<link rel="preload" href="https://www.googletagservices.com/tag/js/gpt.js" as="script" />
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ads-container {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#plus-link {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modrinth-rail-1 {
|
||||||
|
border-radius: 1rem;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="ads-container">
|
||||||
|
<a id="plus-link" href="https://modrinth.com/plus" target="_blank"></a>
|
||||||
|
<div id="modrinth-rail-1" />
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
window.tude = window.tude || { cmd: [] };
|
||||||
|
tude.cmd.push(function () {
|
||||||
|
tude.refreshAdsViaDivMappings([
|
||||||
|
{
|
||||||
|
divId: "modrinth-rail-1",
|
||||||
|
baseDivId: "pb-slot-square-2",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener(
|
||||||
|
"message",
|
||||||
|
(event) => {
|
||||||
|
if (event.data.modrinthOpenUrl && window.__TAURI_INTERNALS__) {
|
||||||
|
window.__TAURI_INTERNALS__.invoke("plugin:shell|open", {
|
||||||
|
path: event.data.modrinthOpenUrl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
window.addEventListener("mousewheel", (event) => {
|
||||||
|
if (window.__TAURI_INTERNALS__) {
|
||||||
|
window.__TAURI_INTERNALS__.invoke("plugin:ads|scroll_ads_window", {
|
||||||
|
scroll: event.deltaY,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("plus-link").addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (event.data.modrinthOpenUrl && window.__TAURI_INTERNALS__) {
|
||||||
|
window.__TAURI_INTERNALS__.invoke("plugin:shell|open", {
|
||||||
|
path: this.href,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("contextmenu", (event) => event.preventDefault());
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "theseus"
|
name = "theseus"
|
||||||
version = "0.8.3-1"
|
version = "0.8.3"
|
||||||
authors = ["Jai A <jaiagr+gpg@pm.me>"]
|
authors = ["Jai A <jaiagr+gpg@pm.me>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@ -833,7 +833,6 @@ a,
|
|||||||
// MARKDOWN
|
// MARKDOWN
|
||||||
|
|
||||||
.markdown-body {
|
.markdown-body {
|
||||||
overflow-y: auto;
|
|
||||||
h1:first-child {
|
h1:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user