Initial commit
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@modrinth/app-frontend",
|
||||
"private": true,
|
||||
"version": "0.8.5",
|
||||
"version": "0.8.501",
|
||||
"development_build": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
PlusIcon,
|
||||
SettingsIcon,
|
||||
XIcon,
|
||||
DownloadIcon,
|
||||
// DownloadIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, Notifications } from '@modrinth/ui'
|
||||
import { useLoading, useTheming } from '@/store/state'
|
||||
@@ -24,7 +24,7 @@ import { handleError, useNotifications } from '@/store/notifications.js'
|
||||
import { command_listener, warning_listener } from '@/helpers/events.js'
|
||||
import { MinimizeIcon, MaximizeIcon } from '@/assets/icons'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { isDev, getOS, restartApp } from '@/helpers/utils.js'
|
||||
import { isDev, getOS } from '@/helpers/utils.js'
|
||||
import { initAnalytics, debugAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
@@ -42,7 +42,7 @@ import { get_opening_command, initialize_state } from '@/helpers/state'
|
||||
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||
import { renderString } from '@modrinth/utils'
|
||||
import { useFetch } from '@/helpers/fetch.js'
|
||||
import { check } from '@tauri-apps/plugin-updater'
|
||||
// import { check } from '@tauri-apps/plugin-updater'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
@@ -99,6 +99,7 @@ async function setupApp() {
|
||||
|
||||
initAnalytics()
|
||||
if (!telemetry) {
|
||||
console.info("[AstralRinth] Telemetry disabled by default (Hard patched in code).")
|
||||
optOutAnalytics()
|
||||
}
|
||||
if (dev) debugAnalytics()
|
||||
@@ -121,18 +122,18 @@ async function setupApp() {
|
||||
}),
|
||||
)
|
||||
|
||||
useFetch(
|
||||
`https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`,
|
||||
'criticalAnnouncements',
|
||||
true,
|
||||
).then((res) => {
|
||||
if (res && res.header && res.body) {
|
||||
criticalErrorMessage.value = res
|
||||
}
|
||||
})
|
||||
// useFetch(
|
||||
// `https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`,
|
||||
// 'criticalAnnouncements',
|
||||
// true,
|
||||
// ).then((res) => {
|
||||
// if (res && res.header && res.body) {
|
||||
// criticalErrorMessage.value = res
|
||||
// }
|
||||
// })
|
||||
|
||||
get_opening_command().then(handleCommand)
|
||||
checkUpdates()
|
||||
// checkUpdates()
|
||||
}
|
||||
|
||||
const stateFailed = ref(false)
|
||||
@@ -243,19 +244,19 @@ async function handleCommand(e) {
|
||||
}
|
||||
}
|
||||
|
||||
const updateAvailable = ref(false)
|
||||
async function checkUpdates() {
|
||||
const update = await check()
|
||||
console.log(update)
|
||||
updateAvailable.value = !!update
|
||||
// const updateAvailable = ref(false)
|
||||
// async function checkUpdates() {
|
||||
// const update = await check()
|
||||
// console.log(update)
|
||||
// updateAvailable.value = !!update
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
checkUpdates()
|
||||
},
|
||||
5 * 1000 * 60,
|
||||
)
|
||||
}
|
||||
// setTimeout(
|
||||
// () => {
|
||||
// checkUpdates()
|
||||
// },
|
||||
// 5 * 1000 * 60,
|
||||
// )
|
||||
// }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -289,14 +290,14 @@ async function checkUpdates() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings pages-list">
|
||||
<button
|
||||
<!-- <button
|
||||
v-if="updateAvailable"
|
||||
v-tooltip="'Install update'"
|
||||
class="btn btn-outline btn-primary icon-only collapsed-button"
|
||||
@click="restartApp()"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</button>
|
||||
</button> -->
|
||||
<Button
|
||||
v-tooltip="'Create profile'"
|
||||
class="sleek-primary collapsed-button"
|
||||
|
||||
@@ -12,3 +12,6 @@ export { default as NewInstanceImage } from './new-instance.svg'
|
||||
export { default as MenuIcon } from './menu.svg'
|
||||
export { default as BugIcon } from './bug.svg'
|
||||
export { default as ChatIcon } from './messages-square.svg'
|
||||
export { default as Pirate } from './pirate.svg'
|
||||
export { default as Microsoft } from './microsoft.svg'
|
||||
export { default as PirateShip } from './pirate-ship.svg'
|
||||
|
||||
17
apps/app-frontend/src/assets/icons/microsoft.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="10mm" height="10mm" viewBox="0 0 10 10" version="1.1" id="svg26662" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" sodipodi:docname="lic.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview id="namedview26664" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" inkscape:document-units="mm" showgrid="false" inkscape:zoom="14.638496" inkscape:cx="17.112414" inkscape:cy="34.258984" inkscape:window-width="1488" inkscape:window-height="1230" inkscape:window-x="2794" inkscape:window-y="123" inkscape:window-maximized="0" inkscape:current-layer="layer1" />
|
||||
<defs id="defs26659" />
|
||||
<g inkscape:label="Слой 1" inkscape:groupmode="layer" id="layer1">
|
||||
<g id="g26657" transform="matrix(3.9940568,0,0,3.954914,-1082.6556,16143.384)">
|
||||
<path id="path26649" style="fill:#05a6f0;fill-opacity:1;stroke-width:0.18168;stroke-miterlimit:5.8;paint-order:fill markers stroke" d="m 271.06666,-4080.4646 v 0.8986 c 0,0.1289 0.0997,0.2334 0.22634,0.2398 h 0.91261 v -1.1384 z" />
|
||||
<path id="path26651" style="fill:#ffba08;fill-opacity:1;stroke-width:0.18168;stroke-miterlimit:5.8;paint-order:fill markers stroke" d="m 272.43195,-4080.4646 v 1.1384 h 0.89917 0.0124 c 0.12669,-0.01 0.22686,-0.1109 0.22686,-0.2398 v -0.8986 z" />
|
||||
<path id="path26653" style="fill:#e25127;fill-opacity:1;stroke-width:0.18168;stroke-miterlimit:5.8;paint-order:fill markers stroke" d="m 271.3054,-4081.8547 c -0.13246,0 -0.23874,0.1073 -0.23874,0.2403 v 0.8955 h 1.13895 v -1.1358 z" />
|
||||
<path id="path26655" style="fill:#81bc06;fill-opacity:1;stroke:none;stroke-width:0.184849;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5.8;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" d="m 272.43195,-4081.8547 v 1.1358 h 1.13843 v -0.8955 c 0,-0.133 -0.1068,-0.2403 -0.23926,-0.2403 z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
53
apps/app-frontend/src/assets/icons/pirate-ship.svg
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<svg height="800px" width="800px" version="1.1" id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 511.672 511.672" xml:space="preserve">
|
||||
<path style="fill:#ED5564;" d="M227.674,44.901c0,0,0.047-0.031,0.141-0.109c-0.031,0.031-3.342,2.437-9.088,3.514
|
||||
c-7.745,1.437-16.208-0.109-25.14-4.591c-31.386-15.771-68.175-0.968-69.721-0.344l0.016,0.062c-3.88,1.593-6.621,5.403-6.621,9.869
|
||||
c0,5.887,4.771,10.649,10.657,10.649c1.694,0,3.295-0.406,4.716-1.109c4.466-1.624,30.816-10.416,51.381-0.078
|
||||
c10.954,5.497,20.706,7.371,28.919,7.371c17.028,0,27.42-8.073,28.044-8.573L227.674,44.901z"/>
|
||||
<g>
|
||||
<path style="fill:#7F4545;" d="M234.514,31.973c-5.887,0-10.657,4.778-10.657,10.665v351.704h21.322V42.638
|
||||
C245.179,36.751,240.401,31.973,234.514,31.973z"/>
|
||||
<path style="fill:#7F4545;" d="M511.672,319.655c0-5.887-4.777-10.665-10.648-10.665c-1.031,0-2.016,0.156-2.951,0.422l0,0
|
||||
l-0.234,0.062l0,0l-108.213,31.073l5.871,20.487l108.463-31.137l0,0C508.408,328.618,511.672,324.512,511.672,319.655z"/>
|
||||
</g>
|
||||
<path style="fill:#A85D5D;" d="M10.689,308.99l99.725,33.385c0,0,39.116,41.239,124.1,41.239c85,0,106.611-29.138,106.611-29.138
|
||||
l85.258-24.484c9.588,160.21-122.656,149.561-122.656,149.561H115.294c-86.171-5.996-73.633-88.568-73.633-88.568l-13.187-9.728
|
||||
l-4.208-18.021L0,351.635L10.689,308.99z"/>
|
||||
<path style="fill:#965353;" d="M426.664,335.317c-5.871,132.337-122.938,122.905-122.938,122.905H115.294
|
||||
c-57.409-3.981-71.001-41.973-73.68-66.879c-0.765,5.84-9.205,82.432,73.68,88.209h188.433
|
||||
C303.727,479.553,433.004,489.968,426.664,335.317z"/>
|
||||
<g>
|
||||
<path style="fill:#434A54;" d="M277.166,415.594c0,5.887,4.763,10.649,10.649,10.649c5.888,0,10.649-4.763,10.649-10.649
|
||||
s-4.762-10.665-10.649-10.665C281.929,404.929,277.166,409.707,277.166,415.594z"/>
|
||||
<path style="fill:#434A54;" d="M234.514,415.594c0,5.887,4.778,10.649,10.665,10.649s10.657-4.763,10.657-10.649
|
||||
s-4.77-10.665-10.657-10.665S234.514,409.707,234.514,415.594z"/>
|
||||
<path style="fill:#434A54;" d="M191.877,415.594c0,5.887,4.771,10.649,10.657,10.649s10.665-4.763,10.665-10.649
|
||||
s-4.778-10.665-10.665-10.665S191.877,409.707,191.877,415.594z"/>
|
||||
<path style="fill:#434A54;" d="M149.24,415.594c0,5.887,4.771,10.649,10.657,10.649s10.657-4.763,10.657-10.649
|
||||
s-4.771-10.665-10.657-10.665S149.24,409.707,149.24,415.594z"/>
|
||||
<path style="fill:#434A54;" d="M99.569,330.305C114.942,207.719,74.616,95.869,74.616,95.869h260.169
|
||||
c80.105,93.783,24.953,234.561,24.953,234.561C262.832,285.849,99.569,330.305,99.569,330.305z"/>
|
||||
</g>
|
||||
<g style="opacity:0.1;">
|
||||
<path style="fill:#FFFFFF;" d="M334.785,95.869h-21.314c69.206,81.026,37.445,197.147,27.529,227.222
|
||||
c6.434,2.123,12.695,4.56,18.738,7.339C359.738,330.43,414.891,189.652,334.785,95.869z"/>
|
||||
</g>
|
||||
<path style="fill:#E6E9ED;" d="M170.555,196.477c0-35.321,28.638-63.959,63.959-63.959c35.329,0,63.951,28.638,63.951,63.959
|
||||
c0,18.941-8.213,35.961-21.299,47.672v26.952h-85.289v-26.952C178.792,232.438,170.555,215.418,170.555,196.477z"/>
|
||||
<g>
|
||||
<path style="fill:#434A54;" d="M250.503,196.477c0,5.887,4.778,10.665,10.665,10.665c5.888,0,10.658-4.778,10.658-10.665
|
||||
s-4.771-10.665-10.658-10.665C255.282,185.812,250.503,190.59,250.503,196.477z"/>
|
||||
<path style="fill:#434A54;" d="M197.21,196.477c0,5.887,4.771,10.665,10.657,10.665s10.657-4.778,10.657-10.665
|
||||
s-4.771-10.665-10.657-10.665S197.21,190.59,197.21,196.477z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path style="fill:#CCD1D9;" d="M277.166,271.085c-0.016-5.871-4.777-10.649-10.673-10.649c-5.887,0-10.657,4.778-10.657,10.665
|
||||
h21.33V271.085z"/>
|
||||
<path style="fill:#CCD1D9;" d="M255.836,271.085c0-5.871-4.77-10.649-10.657-10.649s-10.665,4.778-10.665,10.665h21.322V271.085z" />
|
||||
<path style="fill:#CCD1D9;" d="M234.514,271.085c0-5.871-4.771-10.649-10.657-10.649s-10.657,4.778-10.657,10.665h21.314V271.085z" />
|
||||
<path style="fill:#CCD1D9;" d="M213.199,271.085c-0.008-5.871-4.778-10.649-10.665-10.649s-10.657,4.778-10.657,10.665h21.322
|
||||
L213.199,271.085L213.199,271.085z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
12
apps/app-frontend/src/assets/icons/pirate.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="10mm" height="10mm" viewBox="0 0 10 10" version="1.1" id="svg26662" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" sodipodi:docname="pir.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview id="namedview26664" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" inkscape:document-units="mm" showgrid="false" inkscape:zoom="10.35098" inkscape:cx="16.375261" inkscape:cy="42.073312" inkscape:window-width="1488" inkscape:window-height="1230" inkscape:window-x="2794" inkscape:window-y="123" inkscape:window-maximized="0" inkscape:current-layer="layer1" />
|
||||
<defs id="defs26659" />
|
||||
<g inkscape:label="Слой 1" inkscape:groupmode="layer" id="layer1">
|
||||
<path id="path26647" style="fill:#e7f9fb;fill-opacity:1;stroke:none;stroke-width:0.734686;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5.8;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" d="M 0.953646,0 C 0.4245958,0 0,0.42377 0,0.950056 V 9.051658 C 0,9.577943 0.4245958,9.9999995 0.953646,9.9999995 H 9.044545 C 9.573595,9.9999995 10,9.577943 10,9.051658 V 0.950056 C 10,0.42377 9.573595,0 9.044545,0 Z m 4.0319653,0.680202 c 0.7122257,0 1.1971907,0.171336 1.6235677,0.587681 C 7.149602,1.795597 7.303455,2.529484 7.076165,3.503527 6.954393,4.024672 6.743646,4.411034 6.384675,4.767983 6.046182,5.105514 5.7597,5.274565 5.369942,5.364516 4.7470347,5.510152 4.177518,5.313116 3.618915,4.763985 3.260174,4.411034 3.0504322,4.028385 2.9274247,3.503527 2.6985267,2.5272 2.8504547,1.797596 3.392573,1.267883 3.8051351,0.866387 4.2970505,0.680202 4.9856113,0.680202 Z M 4.1253339,2.785916 C 3.7727965,2.786202 3.5578276,2.980097 3.5578276,3.29821 c 0,0.197035 0.074385,0.320683 0.2711164,0.455467 C 4.0618628,3.91359 4.4444125,3.833637 4.5886441,3.596619 4.6788251,3.450984 4.6839941,3.154002 4.6001321,3.01265 4.5082281,2.855593 4.3583101,2.784203 4.1277751,2.784203 Z m 1.7295441,0 c -0.20506,0 -0.404923,0.09423 -0.493868,0.26557 C 5.226026,3.311345 5.34091,3.641452 5.60714,3.779948 5.859588,3.90845 6.185962,3.822778 6.372268,3.574345 6.463308,3.45441 6.469338,3.164568 6.383758,3.033211 6.273759,2.864731 6.062581,2.784774 5.85752,2.784774 Z M 1.8659927,5.307119 c 0.00862,-5.71e-4 0.020104,0 0.03073,0 0.2179844,2.86e-4 0.5876389,0.16848 1.6846262,0.695051 C 4.3488321,6.369399 4.9972712,6.669808 5.018122,6.669808 5.038222,6.669237 5.68049,6.371113 6.440564,6.008738 7.200522,5.64465 7.88377,5.323396 7.958155,5.323396 8.14742,5.283416 8.403142,5.409066 8.509492,5.577544 8.663431,5.82598 8.604552,6.167795 8.374795,6.361404 8.316205,6.409954 6.898963,7.091579 5.226428,7.875439 2.6791977,9.069933 2.1554033,9.312944 1.9972712,9.312944 c -0.2153996,0 -0.2679571,0 -0.3915391,-0.114223 C 1.3150575,8.936006 1.3506989,8.509952 1.6827021,8.264656 1.7519171,8.213256 2.1996325,7.990519 2.6777048,7.764356 3.1557197,7.54162 3.5582872,7.334304 3.5756915,7.334304 c 0.01436,0 -0.3826933,-0.217025 -0.8872167,-0.448042 C 2.1839513,6.654959 1.7142365,6.421657 1.646802,6.369971 1.4819495,6.24718 1.4026824,6.080128 1.4026824,5.863103 c 0,-0.219881 0.09535,-0.394643 0.2731268,-0.491448 0.063758,-0.03141 0.1203366,-0.05711 0.1901261,-0.06282 z M 7.094115,7.62329 7.661622,7.905994 c 0.784456,0.383506 0.930354,0.522573 0.930354,0.881807 0,0.219881 -0.105403,0.397498 -0.280307,0.480311 -0.151641,0.06568 -0.331859,0.06853 -0.513628,0 C 7.59815,9.193862 5.819639,8.388875 5.788334,8.354036 c -0.01436,0 0.273414,-0.182758 0.639363,-0.378651 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -1,68 +1,89 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="mode !== 'isolated'"
|
||||
ref="button"
|
||||
v-tooltip.right="'Minecraft accounts'"
|
||||
class="button-base avatar-button"
|
||||
:class="{ expanded: mode === 'expanded' }"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<Avatar
|
||||
:size="mode === 'expanded' ? 'xs' : 'sm'"
|
||||
:src="
|
||||
selectedAccount
|
||||
? `https://mc-heads.net/avatar/${selectedAccount.id}/128`
|
||||
: 'https://launcher-files.modrinth.com/assets/steve_head.png'
|
||||
"
|
||||
/>
|
||||
<div v-if="mode !== 'isolated'" ref="button" v-tooltip.right="'Minecraft accounts'" class="button-base avatar-button"
|
||||
:class="{ expanded: mode === 'expanded' }" @click="toggleMenu">
|
||||
<Avatar :size="mode === 'expanded' ? 'xs' : 'sm'" :src="selectedAccount
|
||||
? `https://mc-heads.net/avatar/${selectedAccount.username}/128`
|
||||
: 'https://launcher-files.modrinth.com/assets/steve_head.png'
|
||||
" />
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<Card
|
||||
v-if="showCard || mode === 'isolated'"
|
||||
ref="card"
|
||||
class="account-card"
|
||||
:class="{ expanded: mode === 'expanded', isolated: mode === 'isolated' }"
|
||||
>
|
||||
<Card v-if="showCard || mode === 'isolated'" ref="card" class="account-card"
|
||||
:class="{ expanded: mode === 'expanded', isolated: mode === 'isolated' }">
|
||||
<div v-if="selectedAccount" class="selected account">
|
||||
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.id}/128`" />
|
||||
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.username}/128`" />
|
||||
<div>
|
||||
<h4>{{ selectedAccount.username }}</h4>
|
||||
<h4>
|
||||
<component :is="getAccountType(selectedAccount)" class="vector-icon" /> {{ selectedAccount.username }}
|
||||
</h4>
|
||||
<p>Selected</p>
|
||||
</div>
|
||||
<Button v-tooltip="'Log out'" icon-only color="raised" @click="logout(selectedAccount.id)">
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="logged-out account">
|
||||
<div v-else class="login-section account">
|
||||
<h4>Not signed in</h4>
|
||||
<Button v-tooltip="'Log in'" icon-only color="primary" @click="login()">
|
||||
<LogInIcon />
|
||||
<Button v-tooltip="'Log in'" icon-only @click="login()">
|
||||
<MicrosoftIcon />
|
||||
</Button>
|
||||
<Button v-tooltip="'Add offline'" icon-only @click="tryOfflineLogin()">
|
||||
<PirateIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="displayAccounts.length > 0" class="account-group">
|
||||
<div v-for="account in displayAccounts" :key="account.id" class="account-row">
|
||||
<Button class="option account" @click="setAccount(account)">
|
||||
<Avatar :src="`https://mc-heads.net/avatar/${account.id}/128`" class="icon" />
|
||||
<p>{{ account.username }}</p>
|
||||
<Avatar :src="`https://mc-heads.net/avatar/${account.username}/128`" class="icon" />
|
||||
<p class="account-type">
|
||||
<component :is="getAccountType(account)" class="vector-icon" />
|
||||
{{ account.username }}
|
||||
</p>
|
||||
</Button>
|
||||
<Button v-tooltip="'Log out'" icon-only @click="logout(account.id)">
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Button v-if="accounts.length > 0" @click="login()">
|
||||
<PlusIcon />
|
||||
Add account
|
||||
</Button>
|
||||
<div v-if="accounts.length > 0" class="login-section account centered">
|
||||
<Button v-tooltip="'Log in'" icon-only @click="login()">
|
||||
<MicrosoftIcon />
|
||||
</Button>
|
||||
<Button v-tooltip="'Add offline'" icon-only @click="tryOfflineLogin()">
|
||||
<PirateIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</transition>
|
||||
<ModalWrapper ref="loginOfflineModal" class="modal" header="Offline auth">
|
||||
<div class="modal-body">
|
||||
<div class="label">Offline account</div>
|
||||
<input type="text" v-model="playerName" placeholder="Provide offline player name" />
|
||||
<Button icon-only color="secondary" @click="offlineLoginFinally()">
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<ModalWrapper ref="loginErrorModal" class="modal" header="Error while proceed">
|
||||
<div class="modal-body">
|
||||
<div class="label">Error occurred while adding offline account</div>
|
||||
<Button color="primary" @click="retryOfflineLogin()">
|
||||
Try again
|
||||
</Button>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<ModalWrapper ref="unexpectedErrorModal" class="modal" header="Ошибка">
|
||||
<div class="modal-body">
|
||||
<div class="label">Unexcepted error</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { PlusIcon, TrashIcon, LogInIcon } from '@modrinth/assets'
|
||||
import { PlusIcon, TrashIcon, LogInIcon, PirateIcon as Offline, MicrosoftIcon as License, MicrosoftIcon, PirateIcon } from '@modrinth/assets'
|
||||
import { Avatar, Button, Card } from '@modrinth/ui'
|
||||
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted } from 'vue'
|
||||
import {
|
||||
offline_login,
|
||||
users,
|
||||
remove_user,
|
||||
set_default_user,
|
||||
@@ -73,7 +94,7 @@ import { handleError } from '@/store/state.js'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||
import ModalWrapper from './modal/ModalWrapper.vue'
|
||||
|
||||
defineProps({
|
||||
mode: {
|
||||
@@ -87,6 +108,46 @@ const emit = defineEmits(['change'])
|
||||
|
||||
const accounts = ref({})
|
||||
const defaultUser = ref()
|
||||
const loginOfflineModal = ref(null)
|
||||
const loginErrorModal = ref(null)
|
||||
const unexpectedErrorModal = ref(null)
|
||||
const playerName = ref('')
|
||||
|
||||
async function tryOfflineLogin() { // Patched
|
||||
loginOfflineModal.value.show()
|
||||
}
|
||||
|
||||
async function offlineLoginFinally() { // Patched
|
||||
let name = playerName.value
|
||||
if (name.length > 1 && name.length < 20 && name !== '') {
|
||||
const loggedIn = await offline_login(name).catch(handleError)
|
||||
loginOfflineModal.value.hide()
|
||||
if (loggedIn) {
|
||||
await setAccount(loggedIn)
|
||||
await refreshValues()
|
||||
} else {
|
||||
unexpectedErrorModal.value.show()
|
||||
}
|
||||
playerName.value = ''
|
||||
} else {
|
||||
playerName.value = ''
|
||||
loginOfflineModal.value.hide()
|
||||
loginErrorModal.value.show()
|
||||
}
|
||||
}
|
||||
|
||||
function retryOfflineLogin() { // Patched
|
||||
loginErrorModal.value.hide()
|
||||
tryOfflineLogin()
|
||||
}
|
||||
|
||||
function getAccountType(account) { // Patched
|
||||
if (account.access_token != "null" && account.access_token != null && account.access_token != "") {
|
||||
return License
|
||||
} else {
|
||||
return Offline
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshValues() {
|
||||
defaultUser.value = await get_default_user().catch(handleError)
|
||||
@@ -151,13 +212,8 @@ const handleClickOutside = (event) => {
|
||||
|
||||
function toggleMenu(override = true) {
|
||||
if (showCard.value || !override) {
|
||||
if (showCard.value) {
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
showCard.value = false
|
||||
} else {
|
||||
hide_ads_window()
|
||||
showCard.value = true
|
||||
}
|
||||
}
|
||||
@@ -189,12 +245,18 @@ onUnmounted(() => {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.logged-out {
|
||||
.login-section {
|
||||
background: var(--color-bg);
|
||||
border-radius: var(--radius-lg);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.vector-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.account {
|
||||
width: max-content;
|
||||
display: flex;
|
||||
@@ -255,6 +317,12 @@ onUnmounted(() => {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.centered {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.account-group {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-show="shown"
|
||||
ref="contextMenu"
|
||||
class="context-menu"
|
||||
:style="{
|
||||
left: left,
|
||||
top: top,
|
||||
}"
|
||||
>
|
||||
<div v-show="shown" ref="contextMenu" class="context-menu" :style="{
|
||||
left: left,
|
||||
top: top,
|
||||
}">
|
||||
<div v-for="(option, index) in options" :key="index" @click.stop="optionClicked(option.name)">
|
||||
<hr v-if="option.type === 'divider'" class="divider" />
|
||||
<div
|
||||
v-else-if="!(isLinkedData(item) && option.name === `add_content`)"
|
||||
class="item clickable"
|
||||
:class="[option.color ?? 'base']"
|
||||
>
|
||||
<div v-else-if="!(isLinkedData(item) && option.name === `add_content`)" class="item clickable"
|
||||
:class="[option.color ?? 'base']">
|
||||
<slot :name="option.name" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,7 +17,6 @@
|
||||
|
||||
<script setup>
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
const emit = defineEmits(['menu-closed', 'option-clicked'])
|
||||
|
||||
@@ -38,7 +29,6 @@ const shown = ref(false)
|
||||
|
||||
defineExpose({
|
||||
showMenu: (event, passedItem, passedOptions) => {
|
||||
hide_ads_window()
|
||||
item.value = passedItem
|
||||
options.value = passedOptions
|
||||
|
||||
@@ -71,9 +61,6 @@ const isLinkedData = (item) => {
|
||||
}
|
||||
|
||||
const hideContextMenu = () => {
|
||||
if (shown.value) {
|
||||
show_ads_window()
|
||||
}
|
||||
shown.value = false
|
||||
emit('menu-closed')
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { get as getCreds } from '@/helpers/mr_auth.js'
|
||||
import { handleError } from '@/store/notifications.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)
|
||||
|
||||
defineExpose({
|
||||
scroll() {
|
||||
updateAdPosition()
|
||||
},
|
||||
})
|
||||
|
||||
const creds = await getCreds().catch(handleError)
|
||||
if (creds && creds.user_id) {
|
||||
const user = await get_user(creds.user_id).catch(handleError)
|
||||
|
||||
const MIDAS_BITFLAG = 1 << 0
|
||||
if (user && (user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG) {
|
||||
showAd.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const adsWrapper = ref(null)
|
||||
let resizeObserver
|
||||
let scrollHandler
|
||||
let intersectionObserver
|
||||
let mutationObserver
|
||||
onMounted(() => {
|
||||
if (showAd.value) {
|
||||
updateAdPosition(true)
|
||||
|
||||
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(overrideShown = false) {
|
||||
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, overrideShown)
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<template>
|
||||
<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>
|
||||
@@ -4,13 +4,8 @@
|
||||
<ChatIcon />
|
||||
<span> Get support </span>
|
||||
</a>
|
||||
<Button
|
||||
v-if="currentLoadingBars.length > 0"
|
||||
ref="infoButton"
|
||||
icon-only
|
||||
class="icon-button show-card-icon"
|
||||
@click="toggleCard()"
|
||||
>
|
||||
<Button v-if="currentLoadingBars.length > 0" ref="infoButton" icon-only class="icon-button show-card-icon"
|
||||
@click="toggleCard()">
|
||||
<DownloadIcon />
|
||||
</Button>
|
||||
<div v-if="offline" class="status">
|
||||
@@ -25,33 +20,19 @@
|
||||
<router-link :to="`/instance/${encodeURIComponent(selectedProcess.profile.path)}`">
|
||||
{{ selectedProcess.profile.name }}
|
||||
</router-link>
|
||||
<div
|
||||
v-if="currentProcesses.length > 1"
|
||||
class="arrow button-base"
|
||||
:class="{ rotate: showProfiles }"
|
||||
@click="toggleProfiles()"
|
||||
>
|
||||
<div v-if="currentProcesses.length > 1" class="arrow button-base" :class="{ rotate: showProfiles }"
|
||||
@click="toggleProfiles()">
|
||||
<DropdownIcon />
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
v-tooltip="'Stop instance'"
|
||||
icon-only
|
||||
class="icon-button stop"
|
||||
@click="stop(selectedProcess)"
|
||||
>
|
||||
<Button v-tooltip="'Stop instance'" icon-only class="icon-button stop" @click="stop(selectedProcess)">
|
||||
<StopCircleIcon />
|
||||
</Button>
|
||||
<Button v-tooltip="'View logs'" icon-only class="icon-button" @click="goToTerminal()">
|
||||
<TerminalSquareIcon />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="currentLoadingBars.length > 0"
|
||||
ref="infoButton"
|
||||
icon-only
|
||||
class="icon-button show-card-icon"
|
||||
@click="toggleCard()"
|
||||
>
|
||||
<Button v-if="currentLoadingBars.length > 0" ref="infoButton" icon-only class="icon-button show-card-icon"
|
||||
@click="toggleCard()">
|
||||
<DownloadIcon />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -59,6 +40,40 @@
|
||||
<span class="circle stopped" />
|
||||
<span class="running-text"> No instances running </span>
|
||||
</div>
|
||||
<div v-if="updateState">
|
||||
<a>
|
||||
<Button class="download" :disabled="installState" @click="confirmUpdating(), getRemote(false, false)">
|
||||
<DownloadIcon />
|
||||
{{
|
||||
installState
|
||||
? "Downloading new update..."
|
||||
: "Download new update"
|
||||
}}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
<ModalWrapper ref="confirmUpdate" :has-to-type="false" header="Request to update the AstralRinth launcher">
|
||||
<div class="modal-body">
|
||||
<div class="markdown-body">
|
||||
<p>
|
||||
Before updating, make sure that you have saved all running instances and made a backup copy of the instances
|
||||
that are valuable to you. Remember that the authors of the product are not responsible for the breakdown of
|
||||
your files, so you should always make copies of them and keep them in a safe place.
|
||||
</p>
|
||||
</div>
|
||||
<span>Version on remote server • <p id="releaseData" class="cosmic inline-fix"></p></span>
|
||||
<span>Version on local device •
|
||||
<p class="cosmic inline-fix">v{{ version }}</p>
|
||||
</span>
|
||||
<div class="button-group push-right">
|
||||
<Button class="download-modal" @click="confirmUpdate.hide()">
|
||||
Decline</Button>
|
||||
<Button class="download-modal" @click="approvedUpdating()">
|
||||
Accept
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</div>
|
||||
<transition name="download">
|
||||
<Card v-if="showCard === true && currentLoadingBars.length > 0" ref="card" class="info-card">
|
||||
@@ -74,32 +89,14 @@
|
||||
</Card>
|
||||
</transition>
|
||||
<transition name="download">
|
||||
<Card
|
||||
v-if="showProfiles === true && currentProcesses.length > 0"
|
||||
ref="profiles"
|
||||
class="profile-card"
|
||||
>
|
||||
<Button
|
||||
v-for="process in currentProcesses"
|
||||
:key="process.uuid"
|
||||
class="profile-button"
|
||||
@click="selectProcess(process)"
|
||||
>
|
||||
<Card v-if="showProfiles === true && currentProcesses.length > 0" ref="profiles" class="profile-card">
|
||||
<Button v-for="process in currentProcesses" :key="process.uuid" class="profile-button"
|
||||
@click="selectProcess(process)">
|
||||
<div class="text"><span class="circle running" /> {{ process.profile.name }}</div>
|
||||
<Button
|
||||
v-tooltip="'Stop instance'"
|
||||
icon-only
|
||||
class="icon-button stop"
|
||||
@click.stop="stop(process)"
|
||||
>
|
||||
<Button v-tooltip="'Stop instance'" icon-only class="icon-button stop" @click.stop="stop(process)">
|
||||
<StopCircleIcon />
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="'View logs'"
|
||||
icon-only
|
||||
class="icon-button"
|
||||
@click.stop="goToTerminal(process.profile.path)"
|
||||
>
|
||||
<Button v-tooltip="'View logs'" icon-only class="icon-button" @click.stop="goToTerminal(process.profile.path)">
|
||||
<TerminalSquareIcon />
|
||||
</Button>
|
||||
</Button>
|
||||
@@ -120,6 +117,23 @@ import { handleError } from '@/store/notifications.js'
|
||||
import { ChatIcon } from '@/assets/icons'
|
||||
import { get_many } from '@/helpers/profile.js'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { version } from '../../../package.json'
|
||||
|
||||
import { installState, getRemote, updateState } from '@/helpers/update.js'
|
||||
import ModalWrapper from './modal/ModalWrapper.vue'
|
||||
|
||||
const confirmUpdate = ref(null)
|
||||
|
||||
const confirmUpdating = async () => {
|
||||
confirmUpdate.value.show()
|
||||
}
|
||||
|
||||
const approvedUpdating = async () => {
|
||||
confirmUpdate.value.hide()
|
||||
await getRemote(true, true)
|
||||
}
|
||||
|
||||
await getRemote(true, false)
|
||||
|
||||
const router = useRouter()
|
||||
const card = ref(null)
|
||||
@@ -277,6 +291,101 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.inline-fix {
|
||||
display: inline-flex;
|
||||
margin-top: -2rem;
|
||||
margin-bottom: -2rem;
|
||||
//margin-left: 0.3rem;
|
||||
}
|
||||
|
||||
.cosmic {
|
||||
color: #3e8cde;
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
:deep(table) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
:deep(hr),
|
||||
:deep(h1),
|
||||
:deep(h2) {
|
||||
max-width: max(60rem, 90%);
|
||||
}
|
||||
|
||||
:deep(ul),
|
||||
:deep(ol) {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: var(--gap-lg);
|
||||
text-align: left;
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.download {
|
||||
color: #3e8cde;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
// padding: var(--gap-sm) var(--gap-lg);
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.download:hover,
|
||||
.download:focus,
|
||||
.download:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
.download-modal {
|
||||
color: #3e8cde;
|
||||
padding: var(--gap-sm) var(--gap-lg);
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
|
||||
.download-modal:hover,
|
||||
.download-modal:focus,
|
||||
.download-modal:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
.action-groups {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -288,6 +397,7 @@ onBeforeUnmount(() => {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.rotate {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
@@ -309,8 +419,10 @@ onBeforeUnmount(() => {
|
||||
gap: var(--gap-xs);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-ms-user-select: none; /* IE 10 and IE 11 */
|
||||
-webkit-user-select: none;
|
||||
/* Safari */
|
||||
-ms-user-select: none;
|
||||
/* IE 10 and IE 11 */
|
||||
user-select: none;
|
||||
|
||||
&.clickable:hover {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ConfirmModal } from '@modrinth/ui'
|
||||
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
import { useTheming } from '@/store/theme.js'
|
||||
|
||||
const themeStore = useTheming()
|
||||
@@ -36,7 +36,6 @@ const modal = ref(null)
|
||||
|
||||
defineExpose({
|
||||
show: () => {
|
||||
hide_ads_window()
|
||||
modal.value.show()
|
||||
},
|
||||
hide: () => {
|
||||
@@ -45,25 +44,13 @@ defineExpose({
|
||||
},
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
function proceed() {
|
||||
emit('proceed')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmModal
|
||||
ref="modal"
|
||||
:confirmation-text="confirmationText"
|
||||
:has-to-type="hasToType"
|
||||
:title="title"
|
||||
:description="description"
|
||||
:proceed-label="proceedLabel"
|
||||
:on-hide="onModalHide"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
@proceed="proceed"
|
||||
/>
|
||||
<ConfirmModal ref="modal" :confirmation-text="confirmationText" :has-to-type="hasToType" :title="title"
|
||||
:description="description" :proceed-label="proceedLabel" :on-hide="onModalHide"
|
||||
:noblur="!themeStore.advancedRendering" @proceed="proceed" />
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Modal } from '@modrinth/ui'
|
||||
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
import { useTheming } from '@/store/theme.js'
|
||||
|
||||
const themeStore = useTheming()
|
||||
@@ -18,7 +18,7 @@ const props = defineProps({
|
||||
onHide: {
|
||||
type: Function,
|
||||
default() {
|
||||
return () => {}
|
||||
return () => { }
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -27,7 +27,6 @@ const modal = ref(null)
|
||||
|
||||
defineExpose({
|
||||
show: () => {
|
||||
hide_ads_window()
|
||||
modal.value.show()
|
||||
},
|
||||
hide: () => {
|
||||
@@ -37,7 +36,6 @@ defineExpose({
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
props.onHide()
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ShareModal } from '@modrinth/ui'
|
||||
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
import { useTheming } from '@/store/theme.js'
|
||||
|
||||
const themeStore = useTheming()
|
||||
@@ -33,7 +33,6 @@ const modal = ref(null)
|
||||
|
||||
defineExpose({
|
||||
show: (passedContent) => {
|
||||
hide_ads_window()
|
||||
modal.value.show(passedContent)
|
||||
},
|
||||
hide: () => {
|
||||
@@ -41,21 +40,9 @@ defineExpose({
|
||||
modal.value.hide()
|
||||
},
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ShareModal
|
||||
ref="modal"
|
||||
:header="header"
|
||||
:share-title="shareTitle"
|
||||
:share-text="shareText"
|
||||
:link="link"
|
||||
:open-in-new-tab="openInNewTab"
|
||||
:on-hide="onModalHide"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
/>
|
||||
<ShareModal ref="modal" :header="header" :share-title="shareTitle" :share-text="shareText" :link="link"
|
||||
:open-in-new-tab="openInNewTab" :on-hide="onModalHide" :noblur="!themeStore.advancedRendering" />
|
||||
</template>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
export async function init_ads_window(x, y, width, height, overrideShown = false) {
|
||||
return await invoke('plugin:ads|init_ads_window', { x, y, width, height, overrideShown })
|
||||
}
|
||||
|
||||
export async function show_ads_window() {
|
||||
return await invoke('plugin:ads|show_ads_window')
|
||||
}
|
||||
|
||||
export async function hide_ads_window(reset) {
|
||||
return await invoke('plugin:ads|hide_ads_window', { reset })
|
||||
}
|
||||
@@ -13,6 +13,10 @@ import { invoke } from '@tauri-apps/api/core'
|
||||
// await authenticate_await_completion()
|
||||
// }
|
||||
|
||||
export async function offline_login(name) {
|
||||
return await invoke('plugin:auth|offline_login', { name: name })
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user with Hydra - part 1.
|
||||
* This begins the authentication flow quasi-synchronously.
|
||||
|
||||
176
apps/app-frontend/src/helpers/update.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import { ref } from 'vue'
|
||||
import { version } from '../../package.json'
|
||||
import { getArtifact, getOS } from '@/helpers/utils.js'
|
||||
|
||||
export const allowState = ref(false)
|
||||
export const installState = ref(false)
|
||||
export const updateState = ref(false)
|
||||
export const latestBetaCommitTruncatedSha = ref('')
|
||||
export const latestBetaCommitLink = ref('')
|
||||
export const launcherUrl = 'https://www.astralium.su/get/ar'
|
||||
|
||||
const os = ref('')
|
||||
const releaseLink = `https://api.github.com/repos/DIDIRUS4/AstralRinth/releases/latest`
|
||||
const branchesLink = `https://api.github.com/repos/DIDIRUS4/AstralRinth/branches`
|
||||
const failedFetch = [`Failed to fetch remote releases:`, `Failed to fetch remote commits:`]
|
||||
const localVersion = `v${version}`
|
||||
const betaBranch = `beta` // Github repository beta branch
|
||||
const osNames = ['macos', 'windows', 'linux']
|
||||
const macExtension = `.dmg` // MacOS file type for download
|
||||
const windowsExtension = `.msi` // Windows file type for download
|
||||
const blacklistedBuilds = [
|
||||
`dev`,
|
||||
`nightly`,
|
||||
`dirty`,
|
||||
`dirty-dev`,
|
||||
`dirty-nightly`,
|
||||
`dirty_dev`,
|
||||
`dirty_nightly`,
|
||||
] // This is blacklisted builds for download. For example, file.startsWith('dev') is not allowed.
|
||||
|
||||
/**
|
||||
* Asynchronously fetches branches and their latest commit information from the specified URLs.
|
||||
*
|
||||
* @return {Promise<void>} This function does not return anything directly but updates the latestBetaCommitTruncatedSha and latestBetaCommitLink values.
|
||||
*/
|
||||
export async function getBranches() {
|
||||
fetch(branchesLink)
|
||||
.then(async (response) => {
|
||||
if (response.ok) {
|
||||
response.json().then((data) => {
|
||||
const branches = data.map((branch) => branch)
|
||||
branches.forEach((branch) => {
|
||||
fetch(branch.commit.url).then(async (data) => {
|
||||
if (data.ok) {
|
||||
data.json().then((data) => {
|
||||
const truncatedSha = data.sha.slice(0, 7)
|
||||
const commitLink = data.html_url
|
||||
if (branch.name.toLowerCase() == betaBranch) {
|
||||
latestBetaCommitTruncatedSha.value = truncatedSha
|
||||
latestBetaCommitLink.value = commitLink
|
||||
}
|
||||
})
|
||||
} else {
|
||||
throw new Error(data.status)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
throw new Error(response.status)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
latestBetaCommitTruncatedSha.value = error.message
|
||||
latestBetaCommitLink.value = undefined
|
||||
console.error(failedFetch[1], error)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous function to get remote data and handle updates and downloads.
|
||||
*
|
||||
* @param {boolean} elementIdBool - Indicates whether to disable an element ID.
|
||||
* @param {boolean} downloadArtifactBool - Indicates whether to download an artifact.
|
||||
*/
|
||||
export async function getRemote(elementIdBool, downloadArtifactBool) {
|
||||
fetch(releaseLink)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status)
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then(async (data) => {
|
||||
os.value = await getOS()
|
||||
const latestRelease = data.name
|
||||
let remoteVersion = undefined
|
||||
|
||||
if (!elementIdBool) {
|
||||
const releaseData = document.getElementById('releaseData')
|
||||
if (releaseData == null) {
|
||||
console.error('Release data element not found.')
|
||||
return false
|
||||
}
|
||||
releaseData.textContent = latestRelease
|
||||
remoteVersion = `${releaseData.textContent}`
|
||||
} else {
|
||||
remoteVersion = latestRelease
|
||||
}
|
||||
if (osNames.includes(os.value.toLowerCase())) {
|
||||
if (remoteVersion.startsWith(localVersion)) {
|
||||
updateState.value = false
|
||||
allowState.value = false
|
||||
} else {
|
||||
updateState.value = true
|
||||
allowState.value = true
|
||||
}
|
||||
} else {
|
||||
updateState.value = false
|
||||
allowState.value = false
|
||||
}
|
||||
console.log('Update available state is', updateState.value)
|
||||
console.log('Remote version is', remoteVersion)
|
||||
console.log('Local version is', localVersion)
|
||||
console.log('Operating System is', os.value)
|
||||
|
||||
if (downloadArtifactBool) {
|
||||
installState.value = true
|
||||
const builds = data.assets
|
||||
const fileName = getInstaller(getExtension(), builds)
|
||||
if (fileName != null) {
|
||||
await getArtifact(fileName[1], fileName[0], os.value, true)
|
||||
}
|
||||
installState.value = false
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(failedFetch[0], error)
|
||||
if (!elementIdBool) {
|
||||
const errorData = document.getElementById('releaseData')
|
||||
if (errorData) {
|
||||
errorData.textContent = `${error.message}`
|
||||
}
|
||||
updateState.value = false
|
||||
allowState.value = false
|
||||
installState.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the installer for a specific operating system.
|
||||
*
|
||||
* @param {string} osExtension - The file extension of the installer.
|
||||
* @param {Array} builds - The list of builds.
|
||||
* @return {Array|null} An array containing the installer name and URL if found, or null if not found.
|
||||
*/
|
||||
function getInstaller(osExtension, builds) {
|
||||
for (let i of builds) {
|
||||
let blacklistedItem = false
|
||||
blacklistedBuilds.forEach((item) => {
|
||||
if (i.name.startsWith(item)) {
|
||||
return (blacklistedItem = true)
|
||||
}
|
||||
})
|
||||
if (i.name.endsWith(osExtension) && !blacklistedItem) {
|
||||
console.log(i.browser_download_url)
|
||||
return [i.name, i.browser_download_url]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to get the extension based on the operating system.
|
||||
*
|
||||
* @return {string} The extension based on the operating system.
|
||||
*/
|
||||
function getExtension() {
|
||||
if (os.value.toLowerCase() == osNames[0]) {
|
||||
return macExtension
|
||||
} else if (os.value.toLowerCase() == osNames[1]) {
|
||||
return windowsExtension
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -10,6 +10,11 @@ export async function getOS() {
|
||||
return await invoke('plugin:utils|get_os')
|
||||
}
|
||||
|
||||
export async function getArtifact(downloadurl, filename, ostype, autoupdatesupported) {
|
||||
console.log('Downloading build', downloadurl, filename, ostype, autoupdatesupported)
|
||||
return await invoke('plugin:utils|get_artifact', { downloadurl, filename, ostype, autoupdatesupported })
|
||||
}
|
||||
|
||||
export async function openPath(path) {
|
||||
return await invoke('plugin:utils|open_path', { path })
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import { get as getInstance, get_projects as getInstanceProjects } from '@/helpe
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { get_search_results } from '@/helpers/cache.js'
|
||||
import { debounce } from '@/helpers/utils.js'
|
||||
import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -529,7 +528,6 @@ const isModProject = computed(() => ['modpack', 'mod'].includes(projectType.valu
|
||||
<template>
|
||||
<div ref="searchWrapper" class="search-container">
|
||||
<aside class="filter-panel" @scroll="$refs.promo.scroll()">
|
||||
<PromotionWrapper ref="promo" />
|
||||
<Card v-if="instanceContext" class="small-instance">
|
||||
<router-link :to="`/instance/${encodeURIComponent(instanceContext.path)}`" class="instance">
|
||||
<Avatar
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||
import { ref, onUnmounted, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import RowDisplay from '@/components/RowDisplay.vue'
|
||||
import { list } from '@/helpers/profile.js'
|
||||
@@ -8,11 +8,6 @@ import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import { handleError } from '@/store/notifications.js'
|
||||
import dayjs from 'dayjs'
|
||||
import { get_search_results } from '@/helpers/cache.js'
|
||||
import { hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
onMounted(() => {
|
||||
hide_ads_window(true)
|
||||
})
|
||||
|
||||
const featuredModpacks = ref({})
|
||||
const featuredMods = ref({})
|
||||
@@ -105,31 +100,27 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<RowDisplay
|
||||
v-if="total > 0"
|
||||
:instances="[
|
||||
{
|
||||
label: 'Jump back in',
|
||||
route: '/library',
|
||||
instances: recentInstances,
|
||||
instance: true,
|
||||
downloaded: true,
|
||||
},
|
||||
{
|
||||
label: 'Popular packs',
|
||||
route: '/browse/modpack',
|
||||
instances: featuredModpacks,
|
||||
downloaded: false,
|
||||
},
|
||||
{
|
||||
label: 'Popular mods',
|
||||
route: '/browse/mod',
|
||||
instances: featuredMods,
|
||||
downloaded: false,
|
||||
},
|
||||
]"
|
||||
:can-paginate="true"
|
||||
/>
|
||||
<RowDisplay v-if="total > 0" :instances="[
|
||||
{
|
||||
label: 'Jump back in',
|
||||
route: '/library',
|
||||
instances: recentInstances,
|
||||
instance: true,
|
||||
downloaded: true,
|
||||
},
|
||||
{
|
||||
label: 'Popular packs',
|
||||
route: '/browse/modpack',
|
||||
instances: featuredModpacks,
|
||||
downloaded: false,
|
||||
},
|
||||
{
|
||||
label: 'Popular mods',
|
||||
route: '/browse/mod',
|
||||
instances: featuredMods,
|
||||
downloaded: false,
|
||||
},
|
||||
]" :can-paginate="true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
|
||||
import { onUnmounted, ref, shallowRef } from 'vue'
|
||||
import GridDisplay from '@/components/GridDisplay.vue'
|
||||
import { list } from '@/helpers/profile.js'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -10,11 +10,6 @@ import { Button } from '@modrinth/ui'
|
||||
import { PlusIcon } from '@modrinth/assets'
|
||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||
import { NewInstanceImage } from '@/assets/icons'
|
||||
import { hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
onMounted(() => {
|
||||
hide_ads_window(true)
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { LogOutIcon, LogInIcon, BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { ref, watch } from 'vue'
|
||||
import { LogOutIcon, LogInIcon, BoxIcon, FolderSearchIcon, TrashIcon, PirateShipIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { Card, Slider, DropdownSelect, Toggle, Button } from '@modrinth/ui'
|
||||
import { handleError, useTheming } from '@/store/state'
|
||||
import { get, set } from '@/helpers/settings'
|
||||
@@ -8,24 +8,27 @@ import { get_java_versions, get_max_memory, set_java_version } from '@/helpers/j
|
||||
import { get as getCreds, logout } from '@/helpers/mr_auth.js'
|
||||
import JavaSelector from '@/components/ui/JavaSelector.vue'
|
||||
import ModrinthLoginScreen from '@/components/ui/tutorial/ModrinthLoginScreen.vue'
|
||||
import { optOutAnalytics, optInAnalytics } from '@/helpers/analytics'
|
||||
import { optOutAnalytics } from '@/helpers/analytics'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
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 { hide_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
|
||||
onMounted(() => {
|
||||
hide_ads_window()
|
||||
})
|
||||
import { version, development_build } from '../../package.json'
|
||||
import {
|
||||
getRemote,
|
||||
getBranches,
|
||||
launcherUrl,
|
||||
latestBetaCommitLink,
|
||||
latestBetaCommitTruncatedSha,
|
||||
} from '@/helpers/update.js'
|
||||
|
||||
const pageOptions = ['Home', 'Library']
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
const version = await getVersion()
|
||||
|
||||
const accessSettings = async () => {
|
||||
const settings = await get()
|
||||
|
||||
@@ -51,7 +54,7 @@ watch(
|
||||
const setSettings = JSON.parse(JSON.stringify(newSettings))
|
||||
|
||||
if (setSettings.telemetry) {
|
||||
optInAnalytics()
|
||||
// optInAnalytics()
|
||||
} else {
|
||||
optOutAnalytics()
|
||||
}
|
||||
@@ -147,6 +150,9 @@ async function purgeCache() {
|
||||
'search_results',
|
||||
]).catch(handleError)
|
||||
}
|
||||
|
||||
await getRemote(false, false)
|
||||
await getBranches()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -175,14 +181,9 @@ async function purgeCache() {
|
||||
Sign in
|
||||
</button>
|
||||
</div>
|
||||
<ConfirmModalWrapper
|
||||
ref="purgeCacheConfirmModal"
|
||||
title="Are you sure you want to purge the cache?"
|
||||
<ConfirmModalWrapper ref="purgeCacheConfirmModal" title="Are you sure you want to purge the cache?"
|
||||
description="If you proceed, your entire cache will be purged. This may slow down the app temporarily."
|
||||
:has-to-type="false"
|
||||
proceed-label="Purge cache"
|
||||
@proceed="purgeCache"
|
||||
/>
|
||||
:has-to-type="false" proceed-label="Purge cache" @proceed="purgeCache" />
|
||||
<div class="adjacent-input">
|
||||
<label for="purge-cache">
|
||||
<span class="label__title">App cache</span>
|
||||
@@ -225,20 +226,12 @@ async function purgeCache() {
|
||||
<span class="label__title">Color theme</span>
|
||||
<span class="label__description">Change the global launcher color theme.</span>
|
||||
</label>
|
||||
<DropdownSelect
|
||||
id="theme"
|
||||
name="Theme dropdown"
|
||||
:options="themeStore.themeOptions"
|
||||
:default-value="settings.theme"
|
||||
:model-value="settings.theme"
|
||||
class="theme-dropdown"
|
||||
@change="
|
||||
(e) => {
|
||||
<DropdownSelect id="theme" name="Theme dropdown" :options="themeStore.themeOptions"
|
||||
:default-value="settings.theme" :model-value="settings.theme" class="theme-dropdown" @change="(e) => {
|
||||
themeStore.setThemeState(e.option.toLowerCase())
|
||||
settings.theme = themeStore.selectedTheme
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="advanced-rendering">
|
||||
@@ -248,70 +241,45 @@ async function purgeCache() {
|
||||
without hardware-accelerated rendering.
|
||||
</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="advanced-rendering"
|
||||
:model-value="themeStore.advancedRendering"
|
||||
:checked="themeStore.advancedRendering"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
<Toggle id="advanced-rendering" :model-value="themeStore.advancedRendering"
|
||||
:checked="themeStore.advancedRendering" @update:model-value="(e) => {
|
||||
themeStore.advancedRendering = e
|
||||
settings.advanced_rendering = themeStore.advancedRendering
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="minimize-launcher">
|
||||
<span class="label__title">Minimize launcher</span>
|
||||
<span class="label__description"
|
||||
>Minimize the launcher when a Minecraft process starts.</span
|
||||
>
|
||||
<span class="label__description">Minimize the launcher when a Minecraft process starts.</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="minimize-launcher"
|
||||
:model-value="settings.hide_on_process_start"
|
||||
:checked="settings.hide_on_process_start"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
<Toggle id="minimize-launcher" :model-value="settings.hide_on_process_start"
|
||||
:checked="settings.hide_on_process_start" @update:model-value="(e) => {
|
||||
settings.hide_on_process_start = e
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div v-if="getOS() != 'MacOS'" class="adjacent-input">
|
||||
<label for="native-decorations">
|
||||
<span class="label__title">Native decorations</span>
|
||||
<span class="label__description">Use system window frame (app restart required).</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="native-decorations"
|
||||
:model-value="settings.native_decorations"
|
||||
:checked="settings.native_decorations"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
<Toggle id="native-decorations" :model-value="settings.native_decorations"
|
||||
:checked="settings.native_decorations" @update:model-value="(e) => {
|
||||
settings.native_decorations = e
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="opening-page">
|
||||
<span class="label__title">Default landing page</span>
|
||||
<span class="label__description">Change the page to which the launcher opens on.</span>
|
||||
</label>
|
||||
<DropdownSelect
|
||||
id="opening-page"
|
||||
name="Opening page dropdown"
|
||||
:options="pageOptions"
|
||||
:default-value="settings.default_page"
|
||||
:model-value="settings.default_page"
|
||||
class="opening-page"
|
||||
@change="
|
||||
(e) => {
|
||||
<DropdownSelect id="opening-page" name="Opening page dropdown" :options="pageOptions"
|
||||
:default-value="settings.default_page" :model-value="settings.default_page" class="opening-page" @change="(e) => {
|
||||
settings.default_page = e.option
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
@@ -330,13 +298,7 @@ async function purgeCache() {
|
||||
effect)
|
||||
</span>
|
||||
</label>
|
||||
<Slider
|
||||
id="max-downloads"
|
||||
v-model="settings.max_concurrent_downloads"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:step="1"
|
||||
/>
|
||||
<Slider id="max-downloads" v-model="settings.max_concurrent_downloads" :min="1" :max="10" :step="1" />
|
||||
</div>
|
||||
|
||||
<div class="adjacent-input">
|
||||
@@ -348,13 +310,7 @@ async function purgeCache() {
|
||||
effect)
|
||||
</span>
|
||||
</label>
|
||||
<Slider
|
||||
id="max-writes"
|
||||
v-model="settings.max_concurrent_writes"
|
||||
:min="1"
|
||||
:max="50"
|
||||
:step="1"
|
||||
/>
|
||||
<Slider id="max-writes" v-model="settings.max_concurrent_writes" :min="1" :max="50" :step="1" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
@@ -367,21 +323,16 @@ async function purgeCache() {
|
||||
<label for="opt-out-analytics">
|
||||
<span class="label__title">Telemetry</span>
|
||||
<span class="label__description">
|
||||
Modrinth collects anonymized analytics and usage data to improve our user experience and
|
||||
(Always disabled by AstralRinth) • Modrinth collects anonymized analytics and usage data to improve our user experience and
|
||||
customize your experience. By disabling this option, you opt out and your data will no
|
||||
longer be collected.
|
||||
longer be collected.
|
||||
</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="opt-out-analytics"
|
||||
:model-value="settings.telemetry"
|
||||
:checked="settings.telemetry"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
<Toggle id="opt-out-analytics" :model-value="settings.telemetry" :disabled="!settings.telemetry" :checked="settings.telemetry"
|
||||
@update:model-value="(e) => {
|
||||
settings.telemetry = e
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="disable-discord-rpc">
|
||||
@@ -393,11 +344,7 @@ async function purgeCache() {
|
||||
mods. (app restart required to take effect)
|
||||
</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="disable-discord-rpc"
|
||||
v-model="settings.discord_rpc"
|
||||
:checked="settings.discord_rpc"
|
||||
/>
|
||||
<Toggle id="disable-discord-rpc" v-model="settings.discord_rpc" :checked="settings.discord_rpc" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
@@ -410,36 +357,20 @@ async function purgeCache() {
|
||||
<label :for="'java-' + version">
|
||||
<span class="label__title">Java {{ version }} location</span>
|
||||
</label>
|
||||
<JavaSelector
|
||||
:id="'java-selector-' + version"
|
||||
v-model="javaVersions[version]"
|
||||
:version="version"
|
||||
@update:model-value="updateJavaVersion"
|
||||
/>
|
||||
<JavaSelector :id="'java-selector-' + version" v-model="javaVersions[version]" :version="version"
|
||||
@update:model-value="updateJavaVersion" />
|
||||
</template>
|
||||
<hr class="card-divider" />
|
||||
<label for="java-args">
|
||||
<span class="label__title">Java arguments</span>
|
||||
</label>
|
||||
<input
|
||||
id="java-args"
|
||||
v-model="settings.launchArgs"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="installation-input"
|
||||
placeholder="Enter java arguments..."
|
||||
/>
|
||||
<input id="java-args" v-model="settings.launchArgs" autocomplete="off" type="text" class="installation-input"
|
||||
placeholder="Enter java arguments..." />
|
||||
<label for="env-vars">
|
||||
<span class="label__title">Environmental variables</span>
|
||||
</label>
|
||||
<input
|
||||
id="env-vars"
|
||||
v-model="settings.envVars"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="installation-input"
|
||||
placeholder="Enter environmental variables..."
|
||||
/>
|
||||
<input id="env-vars" v-model="settings.envVars" autocomplete="off" type="text" class="installation-input"
|
||||
placeholder="Enter environmental variables..." />
|
||||
<hr class="card-divider" />
|
||||
<div class="adjacent-input">
|
||||
<label for="max-memory">
|
||||
@@ -448,14 +379,7 @@ async function purgeCache() {
|
||||
The memory allocated to each instance when it is ran.
|
||||
</span>
|
||||
</label>
|
||||
<Slider
|
||||
id="max-memory"
|
||||
v-model="settings.memory.maximum"
|
||||
:min="8"
|
||||
:max="maxMemory"
|
||||
:step="64"
|
||||
unit="mb"
|
||||
/>
|
||||
<Slider id="max-memory" v-model="settings.memory.maximum" :min="8" :max="maxMemory" :step="64" unit="mb" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
@@ -469,39 +393,24 @@ async function purgeCache() {
|
||||
<span class="label__title">Pre launch</span>
|
||||
<span class="label__description"> Ran before the instance is launched. </span>
|
||||
</label>
|
||||
<input
|
||||
id="pre-launch"
|
||||
v-model="settings.hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter pre-launch command..."
|
||||
/>
|
||||
<input id="pre-launch" v-model="settings.hooks.pre_launch" autocomplete="off" type="text"
|
||||
placeholder="Enter pre-launch command..." />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="wrapper">
|
||||
<span class="label__title">Wrapper</span>
|
||||
<span class="label__description"> Wrapper command for launching Minecraft. </span>
|
||||
</label>
|
||||
<input
|
||||
id="wrapper"
|
||||
v-model="settings.hooks.wrapper"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter wrapper command..."
|
||||
/>
|
||||
<input id="wrapper" v-model="settings.hooks.wrapper" autocomplete="off" type="text"
|
||||
placeholder="Enter wrapper command..." />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="post-exit">
|
||||
<span class="label__title">Post exit</span>
|
||||
<span class="label__description"> Ran after the game closes. </span>
|
||||
</label>
|
||||
<input
|
||||
id="post-exit"
|
||||
v-model="settings.hooks.post_exit"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter post-exit command..."
|
||||
/>
|
||||
<input id="post-exit" v-model="settings.hooks.post_exit" autocomplete="off" type="text"
|
||||
placeholder="Enter post-exit command..." />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
@@ -517,58 +426,71 @@ async function purgeCache() {
|
||||
Overwrites the options.txt file to start in full screen when launched.
|
||||
</span>
|
||||
</label>
|
||||
<Toggle
|
||||
id="fullscreen"
|
||||
:model-value="settings.force_fullscreen"
|
||||
:checked="settings.force_fullscreen"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
<Toggle id="fullscreen" :model-value="settings.force_fullscreen" :checked="settings.force_fullscreen"
|
||||
@update:model-value="(e) => {
|
||||
settings.force_fullscreen = e
|
||||
}
|
||||
"
|
||||
/>
|
||||
" />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="width">
|
||||
<span class="label__title">Width</span>
|
||||
<span class="label__description"> The width of the game window when launched. </span>
|
||||
</label>
|
||||
<input
|
||||
id="width"
|
||||
v-model="settings.game_resolution[0]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
placeholder="Enter width..."
|
||||
/>
|
||||
<input id="width" v-model="settings.game_resolution[0]" :disabled="settings.force_fullscreen" autocomplete="off"
|
||||
type="number" placeholder="Enter width..." />
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label for="height">
|
||||
<span class="label__title">Height</span>
|
||||
<span class="label__description"> The height of the game window when launched. </span>
|
||||
</label>
|
||||
<input
|
||||
id="height"
|
||||
v-model="settings.game_resolution[1]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
class="input"
|
||||
placeholder="Enter height..."
|
||||
/>
|
||||
<input id="height" v-model="settings.game_resolution[1]" :disabled="settings.force_fullscreen"
|
||||
autocomplete="off" type="number" class="input" placeholder="Enter height..." />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<div class="label">
|
||||
<div class="label inline-fix">
|
||||
<h3>
|
||||
<span class="label__title size-card-header">About</span>
|
||||
<span class="label__title size-card-header in"
|
||||
> About
|
||||
<p v-if="development_build" class="development option">
|
||||
You are using a development version, there may be errors.
|
||||
</p>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
<span class="label__title">App version</span>
|
||||
<span class="label__description">Modrinth App v{{ version }} </span>
|
||||
<span class="label__title inl">AstralRinth <PirateShipIcon /> Version • {{ version }}</span>
|
||||
|
||||
<span class="label__description"
|
||||
>Latest beta commit •
|
||||
<a class="github" :href="latestBetaCommitLink">{{
|
||||
latestBetaCommitTruncatedSha
|
||||
}}</a></span
|
||||
>
|
||||
<span class="label__description"
|
||||
>All latest versions always published on GitHub
|
||||
<a class="github" :href="launcherUrl">Our GitHub repository</a></span
|
||||
>
|
||||
|
||||
<span class="label__title">Update Checker</span>
|
||||
|
||||
<span class="label__description"
|
||||
>Version on remote server •
|
||||
<p id="releaseData" class="cosmic inline-fix"></p>
|
||||
</span>
|
||||
<span class="label__description"
|
||||
>Version on local device •
|
||||
<p class="cosmic inline-fix">v{{ version }}</p></span
|
||||
>
|
||||
</label>
|
||||
<div class="inline-item-group">
|
||||
<Button icon-only @click="getRemote(false, false), getBranches()">
|
||||
<UpdatedIcon /> Check for updates
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -606,4 +528,112 @@ async function purgeCache() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.development {
|
||||
color: #ff6a00;
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 1.5s ease;
|
||||
}
|
||||
.development:hover,
|
||||
.development:focus,
|
||||
.development:active {
|
||||
color: #4800d3;
|
||||
text-shadow: #801313;
|
||||
}
|
||||
|
||||
.cosmic {
|
||||
color: #3e8cde;
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
.cosmic:hover,
|
||||
.cosmic:focus,
|
||||
.cosmic:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
.download {
|
||||
color: #3e8cde;
|
||||
border: none;
|
||||
padding: var(--gap-sm) var(--gap-lg);
|
||||
//background-color: rgba(0, 0, 0, 0.0);
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
.download:hover,
|
||||
.download:focus,
|
||||
.download:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
a.github {
|
||||
color: #3e8cde;
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
|
||||
a.github:hover,
|
||||
a.github:focus,
|
||||
a.github:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
.inline-item-group {
|
||||
display: inline-flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.inline-fix {
|
||||
display: inline-flex;
|
||||
margin-top: -2rem;
|
||||
margin-bottom: -2rem;
|
||||
}
|
||||
|
||||
.download-modal {
|
||||
color: #3e8cde;
|
||||
padding: var(--gap-sm) var(--gap-lg);
|
||||
text-decoration: none;
|
||||
text-shadow:
|
||||
0 0 4px rgba(79, 173, 255, 0.5),
|
||||
0 0 8px rgba(14, 98, 204, 0.5),
|
||||
0 0 12px rgba(122, 31, 199, 0.5);
|
||||
transition: color 0.35s ease;
|
||||
}
|
||||
.download-modal:hover,
|
||||
.download-modal:focus,
|
||||
.download-modal:active {
|
||||
color: #10fae5;
|
||||
text-shadow: #26065e;
|
||||
}
|
||||
|
||||
.option {
|
||||
background: var(--color-bg);
|
||||
border-radius: var(--radius-lg);
|
||||
width: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
margin-left: 0.5rem;
|
||||
font-size: 1rem;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
</RouterLink>
|
||||
</div>
|
||||
</Card>
|
||||
<PromotionWrapper ref="promo" class="mt-4" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<RouterView v-slot="{ Component }">
|
||||
@@ -136,7 +135,6 @@ import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
import { get_project, get_version_many } from '@/helpers/cache.js'
|
||||
import dayjs from 'dayjs'
|
||||
import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
<PromotionWrapper ref="promo" />
|
||||
<Card class="sidebar-card">
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
@@ -262,7 +261,6 @@ import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import { install as installVersion } from '@/store/install.js'
|
||||
import { get_project, get_project_many, get_team, get_version_many } from '@/helpers/cache.js'
|
||||
import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>ModrinthApp</string>
|
||||
<string>AstralRinthApp</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>modrinth</string>
|
||||
<string>modrinthscheme</string>
|
||||
<string>astralrinth</string>
|
||||
<string>astralrinthscheme</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
@@ -12,6 +12,7 @@ fn main() {
|
||||
"auth",
|
||||
InlinedPlugin::new()
|
||||
.commands(&[
|
||||
"offline_login",
|
||||
"login",
|
||||
"remove_user",
|
||||
"get_default_user",
|
||||
@@ -206,6 +207,7 @@ fn main() {
|
||||
"utils",
|
||||
InlinedPlugin::new()
|
||||
.commands(&[
|
||||
"get_artifact",
|
||||
"get_os",
|
||||
"should_disable_mouseover",
|
||||
"highlight_in_folder",
|
||||
@@ -217,19 +219,6 @@ fn main() {
|
||||
.default_permission(
|
||||
DefaultPermissionRule::AllowAllCommands,
|
||||
),
|
||||
)
|
||||
.plugin(
|
||||
"ads",
|
||||
InlinedPlugin::new()
|
||||
.commands(&[
|
||||
"init_ads_window",
|
||||
"hide_ads_window",
|
||||
"scroll_ads_window",
|
||||
"show_ads_window",
|
||||
])
|
||||
.default_permission(
|
||||
DefaultPermissionRule::AllowAllCommands,
|
||||
),
|
||||
),
|
||||
)
|
||||
.expect("Failed to run tauri-build");
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"identifier": "ads",
|
||||
"description": "",
|
||||
"local": false,
|
||||
"remote": {
|
||||
"urls": ["https://modrinth.com/*", "http://localhost:3000/*"]
|
||||
},
|
||||
"webviews": [
|
||||
"ads-window"
|
||||
],
|
||||
"permissions": [
|
||||
"shell:allow-open",
|
||||
"ads:default"
|
||||
]
|
||||
}
|
||||
@@ -35,7 +35,6 @@
|
||||
"cache:default",
|
||||
"settings:default",
|
||||
"tags:default",
|
||||
"utils:default",
|
||||
"ads:default"
|
||||
"utils:default"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"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"]},"updater":{"identifier":"updater","description":"","local":true,"windows":["main"],"permissions":["updater: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"]},"updater":{"identifier":"updater","description":"","local":true,"windows":["main"],"permissions":["updater:default"]}}
|
||||
@@ -299,69 +299,6 @@
|
||||
},
|
||||
"Identifier": {
|
||||
"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:allow-show-ads-window -> Enables the show_ads_window command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ads:allow-show-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": "ads:deny-show-ads-window -> Denies the show_ads_window command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ads:deny-show-ads-window"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:default -> Default plugin permissions.",
|
||||
"type": "string",
|
||||
@@ -390,6 +327,13 @@
|
||||
"auth:allow-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:allow-offline-login -> Enables the offline_login command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auth:allow-offline-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:allow-remove-user -> Enables the remove_user command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -425,6 +369,13 @@
|
||||
"auth:deny-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:deny-offline-login -> Denies the offline_login command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auth:deny-offline-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:deny-remove-user -> Denies the remove_user command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -3988,6 +3939,13 @@
|
||||
"utils:default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:allow-get-artifact -> Enables the get_artifact command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"utils:allow-get-artifact"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:allow-get-opening-command -> Enables the get_opening_command command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -4037,6 +3995,13 @@
|
||||
"utils:allow-show-launcher-logs-folder"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:deny-get-artifact -> Denies the get_artifact command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"utils:deny-get-artifact"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:deny-get-opening-command -> Denies the get_opening_command command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@@ -299,69 +299,6 @@
|
||||
},
|
||||
"Identifier": {
|
||||
"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:allow-show-ads-window -> Enables the show_ads_window command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ads:allow-show-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": "ads:deny-show-ads-window -> Denies the show_ads_window command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ads:deny-show-ads-window"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:default -> Default plugin permissions.",
|
||||
"type": "string",
|
||||
@@ -390,6 +327,13 @@
|
||||
"auth:allow-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:allow-offline-login -> Enables the offline_login command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auth:allow-offline-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:allow-remove-user -> Enables the remove_user command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -425,6 +369,13 @@
|
||||
"auth:deny-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:deny-offline-login -> Denies the offline_login command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auth:deny-offline-login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "auth:deny-remove-user -> Denies the remove_user command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -3988,6 +3939,13 @@
|
||||
"utils:default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:allow-get-artifact -> Enables the get_artifact command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"utils:allow-get-artifact"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:allow-get-opening-command -> Enables the get_opening_command command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -4037,6 +3995,13 @@
|
||||
"utils:allow-show-launcher-logs-folder"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:deny-get-artifact -> Denies the get_artifact command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"utils:deny-get-artifact"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "utils:deny-get-opening-command -> Denies the get_opening_command command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 34 KiB |
BIN
apps/app/icons/icon (1).png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 401 KiB |
|
Before Width: | Height: | Size: 76 KiB |
@@ -1,20 +0,0 @@
|
||||
if (!window.modrinthClickListener) {
|
||||
window.modrinthClickListener = true
|
||||
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')
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
use serde::Serialize;
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{Emitter, LogicalPosition, LogicalSize, Manager, Runtime};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub struct AdsState {
|
||||
pub shown: bool,
|
||||
pub size: Option<LogicalSize<f32>>,
|
||||
pub position: Option<LogicalPosition<f32>>,
|
||||
}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::<R>::new("ads")
|
||||
.setup(|app, _api| {
|
||||
app.manage(RwLock::new(AdsState {
|
||||
shown: true,
|
||||
size: None,
|
||||
position: None,
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
init_ads_window,
|
||||
hide_ads_window,
|
||||
scroll_ads_window,
|
||||
show_ads_window,
|
||||
])
|
||||
.build()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub async fn init_ads_window<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
x: f32,
|
||||
y: f32,
|
||||
width: f32,
|
||||
height: f32,
|
||||
override_shown: bool,
|
||||
) -> crate::api::Result<()> {
|
||||
use tauri::WebviewUrl;
|
||||
const LINK_SCRIPT: &str = include_str!("ads-init.js");
|
||||
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
state.size = Some(LogicalSize::new(width, height));
|
||||
state.position = Some(LogicalPosition::new(x, y));
|
||||
|
||||
if override_shown {
|
||||
state.shown = true;
|
||||
}
|
||||
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
if state.shown {
|
||||
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),
|
||||
if state.shown {
|
||||
LogicalPosition::new(x, y)
|
||||
} else {
|
||||
LogicalPosition::new(-1000.0, -1000.0)
|
||||
},
|
||||
LogicalSize::new(width, height),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: make ads work on linux
|
||||
#[tauri::command]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn init_ads_window() {}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn show_ads_window<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
) -> crate::api::Result<()> {
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
|
||||
state.shown = true;
|
||||
if let Some(size) = state.size {
|
||||
let _ = webview.set_size(size);
|
||||
}
|
||||
|
||||
if let Some(position) = state.position {
|
||||
let _ = webview.set_position(position);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn hide_ads_window<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
reset: Option<bool>,
|
||||
) -> crate::api::Result<()> {
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
state.shown = false;
|
||||
|
||||
if reset.unwrap_or(false) {
|
||||
state.size = None;
|
||||
state.position = None;
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use theseus::prelude::*;
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::<R>::new("auth")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
offline_login,
|
||||
login,
|
||||
remove_user,
|
||||
get_default_user,
|
||||
@@ -16,6 +17,14 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.build()
|
||||
}
|
||||
|
||||
/// Create new offline user
|
||||
/// This is custom function from Astralium Org.
|
||||
#[tauri::command]
|
||||
pub async fn offline_login(name: &str) -> Result<Credentials> {
|
||||
let credentials = minecraft_auth::offline_auth(name).await?;
|
||||
Ok(credentials)
|
||||
}
|
||||
|
||||
/// Authenticate a user with Hydra - part 1
|
||||
/// This begins the authentication flow quasi-synchronously, returning a URL to visit (that the user will sign in at)
|
||||
#[tauri::command]
|
||||
|
||||
@@ -16,7 +16,6 @@ pub mod settings;
|
||||
pub mod tags;
|
||||
pub mod utils;
|
||||
|
||||
pub mod ads;
|
||||
pub mod cache;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::path::PathBuf;
|
||||
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("utils")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
get_artifact,
|
||||
get_os,
|
||||
should_disable_mouseover,
|
||||
highlight_in_folder,
|
||||
@@ -22,6 +23,12 @@ pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
.build()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_artifact(downloadurl: &str, filename: &str, ostype: &str, autoupdatesupported: bool) -> Result<()> {
|
||||
theseus::download::init_download(downloadurl, filename, ostype, autoupdatesupported).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets OS
|
||||
#[tauri::command]
|
||||
pub fn get_os() -> OS {
|
||||
|
||||
@@ -27,61 +27,61 @@ extern crate objc;
|
||||
async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
||||
theseus::EventState::init(app.clone()).await?;
|
||||
|
||||
#[cfg(feature = "updater")]
|
||||
{
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
// #[cfg(feature = "updater")]
|
||||
// {
|
||||
// use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
let updater = app.updater_builder().build()?;
|
||||
// let updater = app.updater_builder().build()?;
|
||||
|
||||
let update_fut = updater.check();
|
||||
// let update_fut = updater.check();
|
||||
|
||||
State::init().await?;
|
||||
// State::init().await?;
|
||||
|
||||
let check_bar = theseus::init_loading(
|
||||
theseus::LoadingBarType::CheckingForUpdates,
|
||||
1.0,
|
||||
"Checking for updates...",
|
||||
)
|
||||
.await?;
|
||||
// let check_bar = theseus::init_loading(
|
||||
// theseus::LoadingBarType::CheckingForUpdates,
|
||||
// 1.0,
|
||||
// "Checking for updates...",
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
let update = update_fut.await;
|
||||
// let update = update_fut.await;
|
||||
|
||||
drop(check_bar);
|
||||
// drop(check_bar);
|
||||
|
||||
if let Some(update) = update.ok().flatten() {
|
||||
tracing::info!("Update found: {:?}", update.download_url);
|
||||
let loader_bar_id = theseus::init_loading(
|
||||
theseus::LoadingBarType::LauncherUpdate {
|
||||
version: update.version.clone(),
|
||||
current_version: update.current_version.clone(),
|
||||
},
|
||||
1.0,
|
||||
"Updating Modrinth App...",
|
||||
)
|
||||
.await?;
|
||||
// if let Some(update) = update.ok().flatten() {
|
||||
// tracing::info!("Update found: {:?}", update.download_url);
|
||||
// let loader_bar_id = theseus::init_loading(
|
||||
// theseus::LoadingBarType::LauncherUpdate {
|
||||
// version: update.version.clone(),
|
||||
// current_version: update.current_version.clone(),
|
||||
// },
|
||||
// 1.0,
|
||||
// "Updating Modrinth App...",
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// 100 MiB
|
||||
const DEFAULT_CONTENT_LENGTH: u64 = 1024 * 1024 * 100;
|
||||
// // 100 MiB
|
||||
// const DEFAULT_CONTENT_LENGTH: u64 = 1024 * 1024 * 100;
|
||||
|
||||
update
|
||||
.download_and_install(
|
||||
|chunk_length, content_length| {
|
||||
let _ = theseus::emit_loading(
|
||||
&loader_bar_id,
|
||||
(chunk_length as f64)
|
||||
/ (content_length
|
||||
.unwrap_or(DEFAULT_CONTENT_LENGTH)
|
||||
as f64),
|
||||
None,
|
||||
);
|
||||
},
|
||||
|| {},
|
||||
)
|
||||
.await?;
|
||||
// update
|
||||
// .download_and_install(
|
||||
// |chunk_length, content_length| {
|
||||
// let _ = theseus::emit_loading(
|
||||
// &loader_bar_id,
|
||||
// (chunk_length as f64)
|
||||
// / (content_length
|
||||
// .unwrap_or(DEFAULT_CONTENT_LENGTH)
|
||||
// as f64),
|
||||
// None,
|
||||
// );
|
||||
// },
|
||||
// || {},
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
app.restart();
|
||||
}
|
||||
}
|
||||
// app.restart();
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(not(feature = "updater"))]
|
||||
{
|
||||
@@ -259,7 +259,6 @@ fn main() {
|
||||
.plugin(api::tags::init())
|
||||
.plugin(api::utils::init())
|
||||
.plugin(api::cache::init())
|
||||
.plugin(api::ads::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
initialize_state,
|
||||
is_dev,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": ["ads", "core", "plugins", "updater"]
|
||||
"capabilities": ["core", "plugins", "updater"]
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"productName": "Modrinth App",
|
||||
"productName": "AstralRinth App",
|
||||
"version": "0.8.5",
|
||||
"identifier": "ModrinthApp",
|
||||
"identifier": "AstralRinth",
|
||||
"plugins": {
|
||||
"deep-link": {
|
||||
"desktop": {
|
||||
@@ -68,7 +68,7 @@
|
||||
"fullscreen": false,
|
||||
"height": 800,
|
||||
"resizable": true,
|
||||
"title": "Modrinth App",
|
||||
"title": "AstralRinth",
|
||||
"width": 1280,
|
||||
"minHeight": 750,
|
||||
"minWidth": 1100,
|
||||
@@ -86,10 +86,10 @@
|
||||
],
|
||||
"enable": true
|
||||
},
|
||||
"capabilities": ["ads", "core", "plugins"],
|
||||
"capabilities": ["core", "plugins"],
|
||||
"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",
|
||||
"connect-src": "https://api.github.com 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/"
|
||||
],
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"fullscreen": false,
|
||||
"height": 800,
|
||||
"resizable": true,
|
||||
"title": "Modrinth App",
|
||||
"title": "AstralRinth",
|
||||
"width": 1280,
|
||||
"minHeight": 700,
|
||||
"minWidth": 1100,
|
||||
|
||||