You've already forked AstralRinth
forked from didirus/AstralRinth
Merge commit '3b8963fad01131c0946a4c23b2a6a67c2531f10b' into feature-clean
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@modrinth/app-frontend",
|
||||
"private": true,
|
||||
"version": "0.8.701",
|
||||
"version": "0.8.702",
|
||||
"development_build": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="ad-parent relative mb-3 flex w-full justify-center rounded-2xl bg-bg-raised">
|
||||
<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>
|
||||
<p class="m-0 text-2xl font-bold text-contrast">75% of ad revenue goes to creators</p>
|
||||
<nuxt-link to="/plus" class="mt-auto items-center gap-1 text-purple hover:underline">
|
||||
<span>
|
||||
Support creators and Modrinth ad-free with
|
||||
|
||||
@@ -231,6 +231,7 @@
|
||||
</template>
|
||||
<template #revenue> <CurrencyIcon aria-hidden="true" /> Revenue </template>
|
||||
<template #analytics> <ChartIcon aria-hidden="true" /> Analytics </template>
|
||||
<template #moderation> <ModerationIcon aria-hidden="true" /> Moderation </template>
|
||||
<template #sign-out> <LogOutIcon aria-hidden="true" /> Sign out </template>
|
||||
</OverflowMenu>
|
||||
<ButtonStyled v-else color="brand">
|
||||
@@ -778,6 +779,7 @@ const userMenuOptions = computed(() => {
|
||||
link: "/settings",
|
||||
},
|
||||
];
|
||||
|
||||
// TODO: Only show if user has projects
|
||||
options = [
|
||||
...options,
|
||||
@@ -801,6 +803,24 @@ const userMenuOptions = computed(() => {
|
||||
link: "/dashboard/analytics",
|
||||
},
|
||||
];
|
||||
|
||||
if (
|
||||
(auth.value && auth.value.user && auth.value.user.role === "moderator") ||
|
||||
auth.value.user.role === "admin"
|
||||
) {
|
||||
options = [
|
||||
...options,
|
||||
{
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
id: "moderation",
|
||||
color: "orange",
|
||||
link: "/moderation/review",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
options = [
|
||||
...options,
|
||||
{
|
||||
|
||||
@@ -88,20 +88,6 @@
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
<div class="grid-display__item">
|
||||
<div class="label">Current balance</div>
|
||||
<div class="value">
|
||||
{{ $formatMoney(auth.user.payout_data.balance, true) }}
|
||||
</div>
|
||||
<NuxtLink
|
||||
v-if="auth.user.payout_data.balance > 0"
|
||||
class="goto-link"
|
||||
to="/dashboard/revenue"
|
||||
>
|
||||
Withdraw earnings
|
||||
<ChevronRightIcon class="featured-header-chevron" aria-hidden="true" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -2,21 +2,24 @@
|
||||
<div>
|
||||
<section class="universal-card">
|
||||
<h2 class="text-2xl">Revenue</h2>
|
||||
<div v-if="auth.user.payout_data.balance >= minWithdraw">
|
||||
<div v-if="userBalance.available >= minWithdraw">
|
||||
<p>
|
||||
You have
|
||||
<strong>{{ $formatMoney(auth.user.payout_data.balance) }}</strong>
|
||||
available to withdraw.
|
||||
<strong>{{ $formatMoney(userBalance.available) }}</strong>
|
||||
available to withdraw. <strong>{{ $formatMoney(userBalance.pending) }}</strong> of your
|
||||
balance is <nuxt-link class="text-link" to="/legal/cmp-info#pending">pending</nuxt-link>.
|
||||
</p>
|
||||
</div>
|
||||
<p v-else>
|
||||
You have made
|
||||
<strong>{{ $formatMoney(auth.user.payout_data.balance) }}</strong
|
||||
<strong>{{ $formatMoney(userBalance.available) }}</strong
|
||||
>, which is under the minimum of ${{ minWithdraw }} to withdraw.
|
||||
<strong>{{ $formatMoney(userBalance.pending) }}</strong> of your balance is
|
||||
<nuxt-link class="text-link" to="/legal/cmp-info#pending">pending</nuxt-link>.
|
||||
</p>
|
||||
<div class="input-group mt-4">
|
||||
<nuxt-link
|
||||
v-if="auth.user.payout_data.balance >= minWithdraw"
|
||||
v-if="userBalance.available >= minWithdraw"
|
||||
class="iconified-button brand-button"
|
||||
to="/dashboard/revenue/withdraw"
|
||||
>
|
||||
@@ -81,6 +84,10 @@ import { TransferIcon, HistoryIcon, PayPalIcon, SaveIcon, XIcon } from "@modrint
|
||||
const auth = await useAuth();
|
||||
const minWithdraw = ref(0.01);
|
||||
|
||||
const { data: userBalance } = await useAsyncData(`payout/balance`, () =>
|
||||
useBaseFetch(`payout/balance`, { apiVersion: 3 }),
|
||||
);
|
||||
|
||||
async function updateVenmo() {
|
||||
startLoading();
|
||||
try {
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<p>
|
||||
You are initiating a transfer of your revenue from Modrinth's Creator Monetization Program.
|
||||
How much of your
|
||||
<strong>{{ $formatMoney(auth.user.payout_data.balance) }}</strong> balance would you like to
|
||||
<strong>{{ $formatMoney(userBalance.available) }}</strong> balance would you like to transfer
|
||||
transfer to {{ selectedMethod.name }}?
|
||||
</p>
|
||||
<div class="confirmation-input">
|
||||
@@ -212,10 +212,13 @@ const country = ref(
|
||||
countries.value.find((x) => x.id === (auth.value.user.payout_data.paypal_region ?? "US")),
|
||||
);
|
||||
|
||||
const { data: payoutMethods, refresh: refreshPayoutMethods } = await useAsyncData(
|
||||
`payout/methods?country=${country.value.id}`,
|
||||
() => useBaseFetch(`payout/methods?country=${country.value.id}`, { apiVersion: 3 }),
|
||||
);
|
||||
const [{ data: userBalance }, { data: payoutMethods, refresh: refreshPayoutMethods }] =
|
||||
await Promise.all([
|
||||
useAsyncData(`payout/balance`, () => useBaseFetch(`payout/balance`, { apiVersion: 3 })),
|
||||
useAsyncData(`payout/methods?country=${country.value.id}`, () =>
|
||||
useBaseFetch(`payout/methods?country=${country.value.id}`, { apiVersion: 3 }),
|
||||
),
|
||||
]);
|
||||
|
||||
const selectedMethodId = ref(payoutMethods.value[0].id);
|
||||
const selectedMethod = computed(() =>
|
||||
@@ -295,10 +298,10 @@ const knownErrors = computed(() => {
|
||||
if (!parsedAmount.value && amount.value.length > 0) {
|
||||
errors.push(`${amount.value} is not a valid amount`);
|
||||
} else if (
|
||||
parsedAmount.value > auth.value.user.payout_data.balance ||
|
||||
parsedAmount.value > userBalance.value.available ||
|
||||
parsedAmount.value > maxWithdrawAmount.value
|
||||
) {
|
||||
const maxAmount = Math.min(auth.value.user.payout_data.balance, maxWithdrawAmount.value);
|
||||
const maxAmount = Math.min(userBalance.value.available, maxWithdrawAmount.value);
|
||||
errors.push(`The amount must be no more than ${data.$formatMoney(maxAmount)}`);
|
||||
} else if (parsedAmount.value <= fees.value || parsedAmount.value < minWithdrawAmount.value) {
|
||||
const minAmount = Math.max(fees.value + 0.01, minWithdrawAmount.value);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="markdown-body">
|
||||
<h1>Rewards Program Information</h1>
|
||||
<p><em>Last modified: May 13, 2024</em></p>
|
||||
<p><em>Last modified: Sep 12, 2024</em></p>
|
||||
<p>
|
||||
This page was created for transparency for how the rewards program works on Modrinth. Feel
|
||||
free to join our Discord or email
|
||||
@@ -15,10 +15,11 @@
|
||||
<h2>Rewards Distribution</h2>
|
||||
<p>
|
||||
We collect ad revenue on our website and app through our ad network
|
||||
<a href="https://adrinth.com">Adrinth</a>. We then distribute this ad revenue to creators.
|
||||
<a href="https://adrinth.com">Adrinth</a>, which is powered by
|
||||
<a href="https://aditude.io">Aditude</a>. We then distribute this ad revenue to creators.
|
||||
</p>
|
||||
<p>
|
||||
The advertising revenue of the entire website and app is split 90% to creators and 10% to
|
||||
The advertising revenue of the entire website and app is split 75% to creators and 25% to
|
||||
Modrinth.
|
||||
</p>
|
||||
<p>
|
||||
@@ -42,10 +43,10 @@
|
||||
</ul>
|
||||
<p>In this scenario, the earnings for each creator and Modrinth would be as follows:</p>
|
||||
<ul>
|
||||
<li>Modrinth: $10 (10% of $100, the site's earnings for the day)</li>
|
||||
<li>User A: $58.69 ($90 * (10 + 30 + 100 + 10)/230)</li>
|
||||
<li>User B: $12.52 (0.4 * $90 * (50 + 20 + 10 + 0)/230)</li>
|
||||
<li>User C: $18.78 (0.6 * $90 * (50 + 20 + 10 + 0)/230)</li>
|
||||
<li>Modrinth: $25 (25% of $100, the site's earnings for the day)</li>
|
||||
<li>User A: $48.91 ($75 * (10 + 30 + 100 + 10)/230)</li>
|
||||
<li>User B: $10.43 (0.4 * $75 * (50 + 20 + 10 + 0)/230)</li>
|
||||
<li>User C: $15.65 (0.6 * $75 * (50 + 20 + 10 + 0)/230)</li>
|
||||
<li>Note: 230 is the sum of all page views and in-app downloads from above</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -72,19 +73,62 @@
|
||||
</p>
|
||||
<h3>What methods can I use withdraw money from my account? Are there any fees?</h3>
|
||||
<p>
|
||||
Right now, you can use PayPal or Venmo to withdraw money from your Modrinth account. We are
|
||||
working on more methods to withdraw money from your account. There are fees to withdraw money
|
||||
from your Modrinth account—see the revenue page in your dashboard for more information.
|
||||
Right now, you can use PayPal or Venmo to withdraw money from your Modrinth account. Gift card
|
||||
withdrawal is also available. We are working on more methods to withdraw money from your
|
||||
account. There are fees to withdraw money from your Modrinth account—see the revenue page in
|
||||
your dashboard for more information.
|
||||
</p>
|
||||
<h3>Modrinth used to give 100% of project page revenue to creators. What changed?</h3>
|
||||
<h3 id="pending">What does "pending" revenue mean in my dashboard?</h3>
|
||||
<p>
|
||||
While this is true, our new system (as of 08/05/23) gives more of the site's revenue to
|
||||
creators, so creators will earn more. In the old system, we would earn revenue through
|
||||
advertisements in search and user profile pages. This amounted on average each month to about
|
||||
15-20% of the site's total advertising revenue (so a 80-85% split to creators). The new system
|
||||
gives creators more revenue and a more favorable split towards creators (90%).
|
||||
Modrinth receives ad revenue from our ad providers on a NET 60 day basis. Due to this, not all
|
||||
revenue is not immediately available to withdraw. We pay creators as soon as we receive the
|
||||
money from our ad providers, which is 60 days after the last day of each month. This table
|
||||
outlines some example dates of how NET 60 payments are made:
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Payment available date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>January 1st</td>
|
||||
<td>March 31st</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>January 15th</td>
|
||||
<td>March 31st</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>March 3rd</td>
|
||||
<td>May 30th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>June 30th</td>
|
||||
<td>August 29th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>July 14th</td>
|
||||
<td>September 29th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>October 12th</td>
|
||||
<td>December 30th</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>How do I know Modrinth is being transparent about revenue?</h3>
|
||||
<p>
|
||||
We aim to be as transparent as possible with creator revenue. All of our code is open source,
|
||||
including our
|
||||
<a href="https://github.com/modrinth/labrinth/blob/master/src/queue/payouts.rs#L561">
|
||||
revenue distribution system </a
|
||||
>. We also have an
|
||||
<a href="https://api.modrinth.com/v3/payout/platform_revenue">API route</a> that allows users
|
||||
to query exact daily revenue for the site.
|
||||
</p>
|
||||
<h3></h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
border-radius: 1rem;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
@@ -58,19 +58,18 @@
|
||||
]);
|
||||
});
|
||||
|
||||
let lastUrl = null
|
||||
window.addEventListener(
|
||||
"message",
|
||||
(event) => {
|
||||
if (event.data.modrinthOpenUrl && window.__TAURI_INTERNALS__ && lastUrl !== event.data.modrinthOpenUrl) {
|
||||
lastUrl = event.data.modrinthOpenUrl
|
||||
// window.__TAURI_INTERNALS__.invoke("plugin:shell|open", {
|
||||
// path: event.data.modrinthOpenUrl,
|
||||
// });
|
||||
if (event.data.modrinthAdClick && window.__TAURI_INTERNALS__) {
|
||||
window.__TAURI_INTERNALS__.invoke("plugin:ads|record_ads_click", {});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
lastUrl = null
|
||||
}, 500)
|
||||
if (event.data.modrinthOpenUrl && window.__TAURI_INTERNALS__) {
|
||||
window.__TAURI_INTERNALS__.invoke("plugin:ads|open_link", {
|
||||
path: event.data.modrinthOpenUrl,
|
||||
origin: event.origin,
|
||||
});
|
||||
}
|
||||
},
|
||||
false,
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<div class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD">
|
||||
<a href="https://modrinth.com/plus" rel="noopener nofollow sponsored" :target="target"></a>
|
||||
<div class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-0">
|
||||
<div class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-1">
|
||||
<div class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2">
|
||||
<ModrinthPlusIcon class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-3" />
|
||||
<span>
|
||||
<span>
|
||||
90% of ad revenue goes to creators. Go ad-free while supporting creators with
|
||||
</span>
|
||||
<strong>Modrinth Plus.</strong>
|
||||
<span> Subscribe today!</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-4">
|
||||
<a rel="noopener sponsored" :target="target" href="https://adrinth.com"> Ad via Adrinth </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ModrinthPlusIcon } from '@modrinth/assets'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
external: boolean
|
||||
}>(),
|
||||
{
|
||||
external: true,
|
||||
},
|
||||
)
|
||||
|
||||
const target = computed(() => (props.external ? '_blank' : '_self'))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD {
|
||||
position: relative;
|
||||
margin-bottom: var(--gap-md);
|
||||
background: var(--color-ad);
|
||||
border: 1px solid var(--color-ad-raised);
|
||||
border-radius: var(--radius-lg);
|
||||
container-type: inline-size;
|
||||
width: 100%;
|
||||
|
||||
> a {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
&:has(> a:first-child:active) {
|
||||
scale: 0.99;
|
||||
}
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-0 {
|
||||
font-size: 14px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-1 {
|
||||
color: var(--color-base);
|
||||
padding: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--color-base);
|
||||
margin-right: 7.5rem;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2 b,
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2 strong {
|
||||
color: var(--color-ad-highlight);
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-3 {
|
||||
padding-top: 1px;
|
||||
height: 1.5rem;
|
||||
width: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-4 a {
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
right: -1px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
color: var(--color-ad-contrast);
|
||||
background: var(--color-ad-raised);
|
||||
letter-spacing: 0.1ch;
|
||||
margin: 0;
|
||||
padding: 2px 10px;
|
||||
border-top-left-radius: var(--radius-lg);
|
||||
border-bottom-right-radius: var(--radius-lg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.GBBNWLJVGRHFLYVGSZKSSKNTHFYXHMBD-2 a {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -22,7 +22,6 @@ export { default as Page } from './base/Page.vue'
|
||||
export { default as Pagination } from './base/Pagination.vue'
|
||||
export { default as PopoutMenu } from './base/PopoutMenu.vue'
|
||||
export { default as ProjectCard } from './base/ProjectCard.vue'
|
||||
export { default as Promotion } from './base/Promotion.vue'
|
||||
export { default as ScrollablePanel } from './base/ScrollablePanel.vue'
|
||||
export { default as Slider } from './base/Slider.vue'
|
||||
export { default as StatItem } from './base/StatItem.vue'
|
||||
|
||||
Reference in New Issue
Block a user