diff --git a/src/lib/components/AdInternals.svelte b/src/lib/components/AdInternals.svelte new file mode 100644 index 0000000..a723d87 --- /dev/null +++ b/src/lib/components/AdInternals.svelte @@ -0,0 +1,83 @@ + + +{#if displayPlaceholders} +
+
+ +
+
+{:else} +
+{/if} diff --git a/src/lib/components/AdSpace.svelte b/src/lib/components/AdSpace.svelte new file mode 100644 index 0000000..fb5b418 --- /dev/null +++ b/src/lib/components/AdSpace.svelte @@ -0,0 +1,21 @@ + + +{#if adsEnabled && $pwInitialized} +
+ +
+{/if} diff --git a/src/lib/components/DrawerMenu.svelte b/src/lib/components/DrawerMenu.svelte index 4a274fc..cac20bf 100644 --- a/src/lib/components/DrawerMenu.svelte +++ b/src/lib/components/DrawerMenu.svelte @@ -92,10 +92,9 @@ const version = patch?.version;
  • - + { $t("menu-privacy") } - {$t("term-soon")}
  • diff --git a/src/lib/components/TrackingRampSetup.svelte b/src/lib/components/TrackingRampSetup.svelte new file mode 100644 index 0000000..a64d365 --- /dev/null +++ b/src/lib/components/TrackingRampSetup.svelte @@ -0,0 +1,105 @@ + + + + {#if ga4MeasurementId} + + + {/if} + diff --git a/src/lib/state.svelte.ts b/src/lib/state.svelte.ts index 2a7ee41..2fd7058 100644 --- a/src/lib/state.svelte.ts +++ b/src/lib/state.svelte.ts @@ -53,3 +53,5 @@ export let language = storagable("lang", determineBrowserLanguage()); export let configViewWeaponAbilities = storagable("config.builder.view-weapon-abilities", true); export let configViewWeaponTalents = storagable("config.builder.view-weapon-talents", true); export let showLanguageWarning = storagable("config.app.show-language-warning", true); + +export let pwInitialized = writable(false); diff --git a/src/lib/utils/env-helper.ts b/src/lib/utils/env-helper.ts new file mode 100644 index 0000000..9d4a90e --- /dev/null +++ b/src/lib/utils/env-helper.ts @@ -0,0 +1,11 @@ +import { browser } from "$app/environment"; + +export const env = (name: string) => { + if (!browser) { + return null; + } + + return import.meta.env[name]; +}; + +export const envBool = (name: string) => env(name) === "true"; diff --git a/src/lib/utils/logger.ts b/src/lib/utils/logger.ts new file mode 100644 index 0000000..8fc2d9b --- /dev/null +++ b/src/lib/utils/logger.ts @@ -0,0 +1,147 @@ +import { browser } from "$app/environment"; + +export enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, +} + +const MAX_LOCAL_STORAGE_LOGS = 500; +const LOCAL_STORAGE_KEY = "db:logs"; +const isDevMode = browser ? localStorage.getItem("devmode") === "true" : false; + +export class Logger { + private logLevel: LogLevel = isDevMode ? LogLevel.Debug : LogLevel.Info; + + private print(level: LogLevel, message: string, data: object = {}) { + const logLevelStr = Logger.prefixByLevel(level); + const logFunc = Logger.logFunctionByLevel(level); + + const logMessage = `[${logLevelStr}] ${message}`; + + Logger.storeLog(level, logMessage, data); + + if (this.logLevel > level) { + return; + } + + if (Object.keys(data).length > 0) { + logFunc(logMessage, data); + } else { + logFunc(logMessage); + } + } + + public setLogLevel(level: LogLevel) { + this.logLevel = level; + } + + public debug(message: string, data: object = {}) { + this.print(LogLevel.Debug, message, data); + } + + public info(message: string, data: object = {}) { + this.print(LogLevel.Info, message, data); + } + + public warn(message: string, data: object = {}) { + this.print(LogLevel.Warn, message, data); + } + + public error(message: string, data: object = {}) { + this.print(LogLevel.Error, message, data); + } + + public timer(label: string) { + if (this.logLevel > LogLevel.Debug) { + return; + } + + /*eslint-disable*/ + console.time(label); + /*eslint-enable*/ + } + + public timerEnd(label: string) { + if (this.logLevel > LogLevel.Debug) { + return; + } + + /*eslint-disable*/ + console.timeEnd(label); + /*eslint-enable*/ + } + + private static logFunctionByLevel(level: LogLevel): (...data: unknown[]) => void { + /*eslint-disable*/ + // we do not allow usage of console commands in the project except for this function + switch (level) { + case LogLevel.Trace: + return (...data: unknown[]) => { + console.groupCollapsed(...data); + console.trace(); + console.groupEnd(); + }; + case LogLevel.Debug: + case LogLevel.Info: + return console.info; + case LogLevel.Warn: + return console.warn; + case LogLevel.Error: + return console.error; + } + return console.log; + /*eslint-enable*/ + } + + private static prefixByLevel(level: LogLevel): string { + switch (level) { + case LogLevel.Trace: + return "TRACE"; + case LogLevel.Debug: + return "DEBUG"; + case LogLevel.Info: + return "INFO"; + case LogLevel.Warn: + return "WARN"; + case LogLevel.Error: + return "ERROR"; + } + return "???"; + } + + private static storeLog(level: LogLevel, message: string, data: object) { + if (!browser) { + return; + } + + const logs = Logger.data(); + + while (logs.length >= MAX_LOCAL_STORAGE_LOGS) { + logs.shift(); + } + + const timestamp = Date.now(); + + logs.push({ + data, + level, + message, + timestamp, + }); + + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(logs)); + } + + public static data() { + if (!browser) { + return []; + } + return JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) ?? "[]"); + } +} + +const log = new Logger(); +export default log; diff --git a/src/playwire.d.ts b/src/playwire.d.ts new file mode 100644 index 0000000..4343aeb --- /dev/null +++ b/src/playwire.d.ts @@ -0,0 +1,20 @@ +interface PlaywireUnit { + type: string; + selectorId?: string; +} + +interface Window { + ramp: { + que: unknown[]; + passiveMode: boolean; + addUnits: (units: PlaywireUnit[]) => Promise; + displayUnits: () => void; + destroyUnits: (what: string) => Promise; + processPage: (path: string) => void; + showCmpModal: () => void; + }; + + _pwGA4PageviewId: string; + dataLayer: unknown[]; + gtag: (...args: unknown[]) => void; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index ea3b721..336ec8b 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -13,6 +13,8 @@ import { t } from "$lib/i18n.svelte"; import { crowdinLink } from "$lib/constants"; import { phalanxI18nData } from "$lib/data/phalanx-i18n"; import { phalanxPatch } from "$lib/data/phalanx-patch"; +import TrackingRampSetup from "$lib/components/TrackingRampSetup.svelte"; +import AdSpace from "$lib/components/AdSpace.svelte"; const { children } = $props(); @@ -48,6 +50,8 @@ theme.subscribe((theme) => { Dauntless Builder + +
    @@ -96,3 +100,5 @@ theme.subscribe((theme) => {
    + + diff --git a/src/routes/b/[buildId]/+page.svelte b/src/routes/b/[buildId]/+page.svelte index cfd2c6a..e39cf52 100644 --- a/src/routes/b/[buildId]/+page.svelte +++ b/src/routes/b/[buildId]/+page.svelte @@ -52,6 +52,8 @@ import { phalanxWeapons } from "$lib/data/phalanx-weapons"; import { phalanxArmours } from "$lib/data/phalanx-armours.js"; import { phalanxPerks } from "$lib/data/phalanx-perks.js"; import { phalanxLanternCores } from "$lib/data/phalanx-lantern-cores.js"; +import log from "$lib/utils/logger.js"; +import AdSpace from "$lib/components/AdSpace.svelte"; const { data } = $props(); @@ -65,8 +67,8 @@ let dialog: DialogProps = $state({ open: null, filters: {} }); const updateBuild = () => { data.build.flags = 0; // reset flags when user changes something - const buildId = serialize(data.build).unwrapOr(empty()); - console.log(buildId, data.build); + const buildId = serialize(data.build).unwrapOr(serialize(empty()).unwrapOr("this shouldnt happen")); + log.info(buildId, { ...data.build }); goto(`/b/${buildId}`, { noScroll: true }); }; @@ -273,6 +275,8 @@ const gotoFinderPageUsingCurrentPerks = () => { + + {#if isCopyButtonVisible()}
    . +

    + +

    Advertising Partners Privacy Policies

    + +

    You may consult this list to find the Privacy Policy for each of the advertising partners of Dauntless Builder.

    + +

    + Third-party ad servers or ad networks uses technologies like cookies, JavaScript, or Web Beacons that are used in + their respective advertisements and links that appear on Dauntless Builder, which are sent directly to users' + browser. They automatically receive your IP address when this occurs. These technologies are used to measure the + effectiveness of their advertising campaigns and/or to personalize the advertising content that you see on websites + that you visit. +

    + +

    + Note that Dauntless Builder has no access to or control over these cookies that are used by third-party advertisers. +

    + +

    Third Party Privacy Policies

    + +

    + Dauntless Builder's Privacy Policy does not apply to other advertisers or websites. Thus, we are advising you to + consult the respective Privacy Policies of these third-party ad servers for more detailed information. It may + include their practices and instructions about how to opt-out of certain options. +

    + +

    + You can choose to disable cookies through your individual browser options. To know more detailed information about + cookie management with specific web browsers, it can be found at the browsers' respective websites. +

    + +

    CCPA Privacy Rights (Do Not Sell My Personal Information)

    + +

    Under the CCPA, among other rights, California consumers have the right to:

    +

    + Request that a business that collects a consumer's personal data disclose the categories and specific pieces of + personal data that a business has collected about consumers. +

    +

    Request that a business delete any personal data about the consumer that a business has collected.

    +

    Request that a business that sells a consumer's personal data, not sell the consumer's personal data.

    +

    + If you make a request, we have one month to respond to you. If you would like to exercise any of these rights, + please contact us. +

    + +

    GDPR Data Protection Rights

    + +

    + We would like to make sure you are fully aware of all of your data protection rights. Every user is entitled to the + following: +

    +

    + The right to access – You have the right to request copies of your personal data. We may charge you a small fee for + this service. +

    +

    + The right to rectification – You have the right to request that we correct any information you believe is + inaccurate. You also have the right to request that we complete the information you believe is incomplete. +

    +

    The right to erasure – You have the right to request that we erase your personal data, under certain conditions.

    +

    + The right to restrict processing – You have the right to request that we restrict the processing of your personal + data, under certain conditions. +

    +

    + The right to object to processing – You have the right to object to our processing of your personal data, under + certain conditions. +

    +

    + The right to data portability – You have the right to request that we transfer the data that we have collected to + another organization, or directly to you, under certain conditions. +

    +

    + If you make a request, we have one month to respond to you. If you would like to exercise any of these rights, + please contact us. +

    + +

    Children's Information

    + +

    + Another part of our priority is adding protection for children while using the internet. We encourage parents and + guardians to observe, participate in, and/or monitor and guide their online activity. +

    + +

    + Dauntless Builder does not knowingly collect any Personal Identifiable Information from children under the age of + 13. If you think that your child provided this kind of information on our website, we strongly encourage you to + contact us immediately and we will do our best efforts to promptly remove such information from our records. +

    + +

    Changes to This Privacy Policy

    + +

    + We may update our Privacy Policy from time to time. Thus, we advise you to review this page periodically for any + changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are + effective immediately, after they are posted on this page. +

    + +

    + Our Privacy Policy was created with the help of the + Privacy Policy Generator. +

    + +

    Contact Us

    + +

    If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us.

    diff --git a/vite.config.ts b/vite.config.ts index 10d16fe..8fd7e35 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,6 +5,7 @@ import fs from "fs/promises"; import { loadEnv } from "vite"; export default defineConfig(({ command, mode }) => ({ + envPrefix: "DB_", plugins: [ { name: "fetch-data",