Skip to content

Commit

Permalink
implement thumbnail customization
Browse files Browse the repository at this point in the history
  • Loading branch information
pukmajster committed Oct 19, 2024
1 parent 5141713 commit 1560386
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 37 deletions.
4 changes: 3 additions & 1 deletion shared/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export interface User {
libraryDisplayMode?: 'grid' | 'list'
hideDescriptions?: boolean
enableExperimentalManifestParser?: boolean
enableAdaptiveThumbnails?: boolean
enableWorkshopMetadataFetching?: boolean

thumbnailsPreferredAspectRatio?: 'wide' | 'square'
thumbnailsWastedSpace: 'stretch' | 'fill-black' | 'fill-blur' | 'disabled'
}
2 changes: 2 additions & 0 deletions src/main/fkv/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { json2vdf } from './json2vdf'
export { json2vdf }
81 changes: 81 additions & 0 deletions src/main/fkv/json2vdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*************************************************************
*
* FUNKY KEY VALUES
*
* json2vdf()
* Takes a JSON object and spits out a VDF string
*
************************************************************/

type VdfFormattingOptions = {
indentValues: boolean
watermark: boolean
arrayIndexingName?: string
}

const defaultVdfFormattingOptions: VdfFormattingOptions = {
indentValues: false,
watermark: false,
arrayIndexingName: 'file'
}

export function json2vdf(json: Object, rootName: string, options?: Partial<VdfFormattingOptions>) {
const opts = { ...defaultVdfFormattingOptions, ...options } as VdfFormattingOptions

let output = '// File generated by funky\n\n'

function vdfIndent(level: number) {
return '\t'.repeat(level)
}

function print(level: number, str: string) {
output += vdfIndent(level) + str + '\n'
}

output += `"${rootName}"\n{\n`

function recursivelySerialize(obj: Object, depth: number = 1) {
for (const key in obj) {
const value = obj[key]

if (typeof value === 'object') {
output += vdfIndent(depth) + `"${key}"` + '\n'
output += vdfIndent(depth) + '{\n'
recursivelySerialize(value, depth + 1)
output += vdfIndent(depth) + '}\n'

// TODO: Add support for array indexing
} else {
let formattedValue = value

switch (typeof value) {
case 'string':
break

case 'number':
formattedValue = value.toString()
break

case 'boolean':
formattedValue = value ? 'true' : 'false'
break

default:
console.error(`[FKV json2vdf] Unsupported value type: ${typeof value}`)
formattedValue = 'undefined'
break
}

let spacingMethod = opts.indentValues ? '\t' : ' '
output += `${vdfIndent(depth)}"${key}"${spacingMethod}"${formattedValue}"\n`
}
}
}

recursivelySerialize(json)

// Close the root object
output += '}\n'

return output
}
5 changes: 3 additions & 2 deletions src/renderer/src/Config.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
activeProfileId: 1,
hideDescriptions: true,
enableExperimentalManifestParser: false,
enableAdaptiveThumbnails: false,
enableWorkshopMetadataFetching: true
enableWorkshopMetadataFetching: true,
thumbnailsPreferredAspectRatio: 'wide',
thumbnailsWastedSpace: 'stretch'
}
let hasSetupUserProfile = false
Expand Down
45 changes: 26 additions & 19 deletions src/renderer/src/components/addons/AddonCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
<img
alt="mod"
on:error={handleMissingThumbnail}
class="shadow-md rounded-md w-[64px] aspect-[5/3]"
class="shadow-md rounded-md w-[64px] aspect-[16/9]"
src={thumbnail}
/>

Expand All @@ -160,39 +160,46 @@
on:contextmenu={openOverview}
class:selected
class:unselected={otherModsSelectedButNotThisOne && !selected}
class="relative shadow-md transition-transform"
class="relative -shadow-md transition-transform group"
class:enabled={isEnabled}
class:asShuffle
class:unsubscribed={wasUnsubscribed}
on:click={handleClick}
>
<!-- -->

{#if $userStore.enableAdaptiveThumbnails}
{#if $userStore.thumbnailsWastedSpace !== 'stretch'}
<div
class="relative grid aspect-[5/3] w-full [&>*]:[grid-area:1/1] rounded-md overflow-hidden"
data-aspect={$userStore.thumbnailsPreferredAspectRatio}
data-black={$userStore.thumbnailsWastedSpace == 'fill-black'}
class="relative data-[aspect=square]:aspect-[1/1] data-[aspect=wide]:aspect-[16/9] data-[black=true]:bg-black w-full rounded-md overflow-hidden"
>
<img
alt="mod"
on:error={handleMissingThumbnail}
class=" rounded-md blur-2xl aspect-[5/3] mx-auto opacity-60 h-full"
src={thumbnail}
/>

<div class="absolute inset-0 flex items-center justify-center">
{#if $userStore.thumbnailsWastedSpace == 'fill-blur'}
<img
alt="mod"
alt=""
on:error={handleMissingThumbnail}
class="h-full w-full absolute inset-0 blur-lg -z-10 opacity-50 scale-110"
src={thumbnail}
/>
{/if}

<div
data-aspect={$userStore.thumbnailsPreferredAspectRatio}
class="absolute inset-0 flex items-center data-[aspect=square]:flex-col justify-center"
>
<img
data-aspect={$userStore.thumbnailsPreferredAspectRatio}
class="data-[aspect=wide]:max-h-[100%] data-[aspect=wide]:my-auto"
alt=""
on:error={handleMissingThumbnail}
class="opacity-100 h-full"
src={thumbnail}
/>
</div>
</div>
{:else}
<img
alt="mod"
alt=""
data-aspect={$userStore.thumbnailsPreferredAspectRatio}
on:error={handleMissingThumbnail}
class=" rounded-md aspect-[5/3] w-full"
class=" rounded-md data-[aspect=square]:aspect-[1/1] data-[aspect=wide]:aspect-[16/9] w-full"
src={thumbnail}
/>
{/if}
Expand Down Expand Up @@ -248,7 +255,7 @@
<img
alt="mod"
on:error={handleMissingThumbnail}
class=" rounded-md aspect-[5/3] w-[96px]"
class=" rounded-md aspect-[16/9] w-[96px]"
src={thumbnail}
/>

Expand Down
10 changes: 7 additions & 3 deletions src/renderer/src/features/settings/SettingsModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,16 @@
</div>
</div>

<div class="flex flex-col gap-4 px-4 pt-4">
<div class="flex justify-between items-center">
<div class="overflow-y-auto">
<div
class="flex justify-between items-center sticky top-0 backdrop-blur-xl p-4 z-10 bg-surface-800/80"
>
<p class="text-xl font-semibold uppercase">{activeTabData.label}</p>
<button on:click={close} class="ml-auto btn btn-icon btn-sm"> <X size={24} /></button>
</div>

<svelte:component this={activeTabData.component} />
<div class="px-4 pb-4 flex flex-col gap-4">
<svelte:component this={activeTabData.component} />
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
export let value: unknown
export let options: {
label: string
value: string
}[]
</script>

<select bind:value class="select !bg-surface-500 indent-2 w-auto min-w-[186px]">
{#each options as option}
<option value={option.value}>{option.label}</option>
{/each}
</select>
14 changes: 14 additions & 0 deletions src/renderer/src/features/settings/components/SettingsPaper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
export let label: string
</script>

<div class="flex items-center justify-between gap-4 p-3 bg-surface-700 rounded-lg">
<div>
<span class="text-base">{label}</span>
<p class="text-xs opacity-60 mt-1 max-w-[420px]">
<slot name="description" />
</p>
</div>

<slot name="main" />
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,75 @@
import { userStore } from '../../../stores/user'
import SettingsHeader from '../components/SettingsHeader.svelte'
import SettingsSwitch from '../components/SettingsSwitch.svelte'
import SettingsDropdown from '../components/SettingsDropdown.svelte'
import SettingsPaper from '../components/SettingsPaper.svelte'
</script>

<SettingsHeader label="Addons" />

<!-- <SettingsSwitch
label="Fetch missing metadata from the Steam Workshop"
description="A good amount of mods (especially Workshop ones) don't provide metadata. Enabling this will fetch the missing metadata from the Steam Workshop API. Mods outside the Workshop obviously can't utilize this feature."
bind:value={$userStore.enableWorkshopMetadataFetching}
/> -->

<SettingsSwitch
label="Hide descriptions"
description="Mod descriptions are usually formatted in Markdown, which Funky does not support. If disabled, you're likely to see walls of barely-readable text."
bind:value={$userStore.hideDescriptions}
/>

<SettingsSwitch
label="Adaptive thumbnails"
description="Displays thumbnails in their native aspect ratio when enabled."
bind:value={$userStore.enableAdaptiveThumbnails}
/>
<SettingsHeader label="Thumbnails" />

<SettingsPaper label="Preferred thumbnail aspect ratio">
<svelte:fragment slot="description">
<p>
Sadly thumbnails come in a variety of aspect ratios, so you can choose which one you prefer.
Wide is 16:9 and square is 1:1.
</p>
<p />
</svelte:fragment>

<svelte:fragment slot="main">
<SettingsDropdown
bind:value={$userStore.thumbnailsPreferredAspectRatio}
options={[
{
label: 'Wide',
value: 'wide'
},
{
label: 'Square',
value: 'square'
}
]}
/>
</svelte:fragment>
</SettingsPaper>

<SettingsPaper label="Wasted space">
<svelte:fragment slot="description">
<p>Select your preferred method of filling the wasted space around thumbnails.</p>
</svelte:fragment>

<svelte:fragment slot="main">
<SettingsDropdown
bind:value={$userStore.thumbnailsWastedSpace}
options={[
{
label: 'Stretch',
value: 'stretch'
},
{
label: 'Blur',
value: 'fill-blur'
},
{
label: 'Black',
value: 'fill-black'
},
{
label: 'None',
value: 'none'
}
]}
/>
</svelte:fragment>
</SettingsPaper>

<SettingsHeader label="Experimental" />

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
"include": ["electron.vite.config.*", "src/main/*", "src/preload/*"],
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"],
"compilerOptions": {
"composite": true,
"types": ["electron-vite/node"]
Expand Down

0 comments on commit 1560386

Please sign in to comment.