Skip to content

Commit bec0d50

Browse files
ZeKapiTrooz
andauthored
Minecraft and loaders version selection (#35)
* feat: Auto detect mods from drag&drop * use ts types from cf-fingerprint package directly * update dep to point to upstream * loaders togglebuttons group fix toggle groups (took like too much time but now it works) added a loaders selector * fixed auto width played with width, flex, alignment to make main UI adapt easier * added slider to select min and max mc versions plus changed MinecraftVersions to use the already existing MCVersion type and error handling versions numbers are from the API double slider working perfectly on firefox, chrome in juste usable * style mc version selection input boxes fix modsearchlist width * use $effect.pre instead of onMount --------- Co-authored-by: iTrooz <hey@itrooz.fr>
1 parent 6d040e3 commit bec0d50

File tree

12 files changed

+280
-41
lines changed

12 files changed

+280
-41
lines changed

mclib/src/MinecraftVersions.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
export type MinecraftVersion = string;
1+
import { MCVersion } from "./ModpackCreator";
22

33
export class MinecraftVersions {
4-
private fetchClient: typeof fetch;
5-
6-
constructor(fetchClient: typeof fetch) {
7-
this.fetchClient = fetchClient;
8-
}
9-
10-
public async getReleases(): Promise<MinecraftVersion[]> {
11-
const response = await this.fetchClient('https://mc-versions-api.net/api/java');
12-
const data = await response.json();
13-
return data.result;
4+
public static async getReleases(): Promise<MCVersion[]> {
5+
try {
6+
const response = await fetch("https://mc-versions-api.net/api/java");
7+
const data = await response.json();
8+
return data.result.reverse();
9+
} catch (error) {
10+
console.error("Failed to fetch Minecraft versions:", error);
11+
return ["error"];
12+
}
1413
}
1514
}

web/messages/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"loading_mod_search": "Please wait, we're searching your mod",
77
"downloads_count": "downloads",
88
"open_mod_repo_link": "See on {repo_name}",
9+
"reset_toggle_group": "Reset",
10+
"min_mc_version": "Min version",
11+
"max_mc_version": "Max version",
912
"add_mod": "Add",
1013
"remove_mod": "Remove",
1114
"run_modpack_creator": "Run Modpack Creator",

web/messages/fr.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"loading_mod_search": "Veuillez patienter, nous recherchons votre mod",
77
"downloads_count": "téléchargements",
88
"open_mod_repo_link": "Voir sur {repo_name}",
9+
"reset_toggle_group": "Effacer",
10+
"min_mc_version": "Version min",
11+
"max_mc_version": "Version max",
912
"add_mod": "Ajouter",
1013
"remove_mod": "Enlever",
1114
"run_modpack_creator": "Exécuter le créateur de modpack",

web/src/components.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export { default as ModSearchList } from './components/ModSearchList.svelte';
33
export { default as ModsList } from './components/ModsList.svelte';
44
export { default as ToggleButtons } from './components/ToggleButtons.svelte';
55
export { default as FileDropZone } from './components/FileDropZone.svelte';
6+
export { default as MCVersionSelection } from './components/MCVersionSelection.svelte';

web/src/components/FileDropZone.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
}
4444
4545
isProcessing = true;
46-
46+
4747
try {
4848
for (const file of Array.from(e.dataTransfer.files)) {
4949
// Only process .jar files (mod files)
@@ -88,7 +88,7 @@
8888
}
8989
</script>
9090

91-
<div
91+
<div
9292
class="dropzone {isDragging ? 'dragging' : ''} {isProcessing ? 'processing' : ''}"
9393
ondragenter={handleDragEnter}
9494
ondragleave={handleDragLeave}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<script lang="ts">
2+
import type { MCVersion } from 'mclib';
3+
4+
import * as m from '$msg';
5+
let {
6+
min_mc_version = $bindable(),
7+
max_mc_version = $bindable(),
8+
mc_versions
9+
}: {
10+
min_mc_version: MCVersion;
11+
max_mc_version: MCVersion;
12+
mc_versions: MCVersion[];
13+
} = $props();
14+
</script>
15+
16+
<form
17+
class="mc_version_selection"
18+
onsubmit={(e: Event) => {
19+
e.preventDefault();
20+
}}
21+
>
22+
<datalist id="mc_version_selection_list">
23+
{#each mc_versions.toReversed() as mc_version (mc_version)}
24+
<option value={mc_version}></option>
25+
{/each}
26+
</datalist>
27+
<input
28+
type="text"
29+
placeholder={m.min_mc_version()}
30+
bind:value={min_mc_version}
31+
list="mc_version_selection_list"
32+
size="8"
33+
/>
34+
<div class="sliders">
35+
<input
36+
type="range"
37+
bind:value={
38+
() =>
39+
mc_versions.findIndex((value) => {
40+
return value == min_mc_version;
41+
}),
42+
(v: number) => {
43+
if (
44+
v <=
45+
mc_versions.findIndex((value) => {
46+
return value == max_mc_version;
47+
})
48+
) {
49+
min_mc_version = mc_versions[v];
50+
}
51+
}
52+
}
53+
min="0"
54+
max={mc_versions.length - 1}
55+
/>
56+
<input
57+
type="range"
58+
bind:value={
59+
() =>
60+
mc_versions.findIndex((value) => {
61+
return value == max_mc_version;
62+
}),
63+
(v: number) => {
64+
if (
65+
v >=
66+
mc_versions.findIndex((value) => {
67+
return value == min_mc_version;
68+
})
69+
) {
70+
max_mc_version = mc_versions[v];
71+
}
72+
}
73+
}
74+
min="0"
75+
max={mc_versions.length - 1}
76+
/>
77+
</div>
78+
<input
79+
type="text"
80+
placeholder={m.max_mc_version()}
81+
bind:value={max_mc_version}
82+
list="mc_version_selection_list"
83+
size="8"
84+
/>
85+
</form>
86+
87+
<style>
88+
form.mc_version_selection {
89+
display: flex;
90+
flex-direction: row;
91+
justify-content: space-between;
92+
align-items: center;
93+
gap: 1rem;
94+
& .sliders {
95+
flex: 1;
96+
position: relative;
97+
height: 20px;
98+
display: flex;
99+
align-items: center;
100+
101+
&::before {
102+
content: '';
103+
position: absolute;
104+
height: 50%;
105+
width: 100%;
106+
outline: solid 2px var(--green);
107+
z-index: 1;
108+
}
109+
110+
& input[type='range'] {
111+
position: absolute;
112+
inset: 0;
113+
margin: 0;
114+
width: 100%;
115+
z-index: 2;
116+
-webkit-appearance: none;
117+
appearance: none;
118+
background: transparent;
119+
pointer-events: none;
120+
121+
&::-webkit-slider-thumb {
122+
-webkit-appearance: none;
123+
appearance: none;
124+
height: 20px;
125+
width: 12px;
126+
border-radius: 0;
127+
background: var(--grey-dark-2);
128+
border: solid 2px var(--green);
129+
cursor: pointer;
130+
pointer-events: auto;
131+
}
132+
&::-moz-range-thumb {
133+
-webkit-appearance: none;
134+
appearance: none;
135+
height: 20px;
136+
width: 12px;
137+
border-radius: 0;
138+
background: var(--grey-dark-2);
139+
border: solid 2px var(--green);
140+
cursor: pointer;
141+
pointer-events: auto;
142+
}
143+
144+
&::-webkit-slider-thumb:hover {
145+
background: var(--grey-dark-1);
146+
border-color: var(--green-light-1);
147+
}
148+
&::-moz-range-thumb:hover {
149+
background: var(--grey-dark-1);
150+
border-color: var(--green-light-1);
151+
}
152+
153+
&::-webkit-slider-thumb:active {
154+
background: var(--green);
155+
cursor: pointer;
156+
}
157+
&::-moz-range-thumb:active {
158+
background: var(--green);
159+
cursor: pointer;
160+
}
161+
}
162+
163+
/* 5. The MASKING trick: We use the bottom slider (min_mc_version)
164+
to "cover up" the green fill from the left. */
165+
& input[type='range']:first-of-type {
166+
z-index: 3;
167+
&::-moz-range-progress {
168+
background: var(--grey-dark-2);
169+
height: 50%;
170+
}
171+
}
172+
& input[type='range']:not(:first-of-type) {
173+
&::-moz-range-progress {
174+
background: var(--green-dark-1);
175+
height: 50%;
176+
}
177+
}
178+
}
179+
& input[type='text'] {
180+
background: var(--grey-dark-1);
181+
outline: solid 2px var(--green);
182+
border: none;
183+
color: var(--grey-light-2);
184+
padding: 0.4rem 0.6rem;
185+
&:is(:active, :focus, :focus-visible, :hover) {
186+
outline-color: var(--green-light-1);
187+
}
188+
}
189+
}
190+
</style>

web/src/components/ModSearch.svelte

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
entries_list={repositories.map((repo) => {
6868
return repo.getRepositoryName();
6969
})}
70+
name="mod-repo-names-selection"
7071
onchange={search_for_mods}
7172
reset
7273
/>
@@ -95,13 +96,8 @@
9596

9697
<style>
9798
section {
98-
width: 42rem;
99-
max-width: 42rem;
10099
display: flex;
101100
flex-direction: column;
102-
justify-content: stretch;
103-
width: -moz-available;
104-
width: -webkit-fill-available;
105101
}
106102
form.search {
107103
display: flex;
@@ -112,9 +108,8 @@
112108
flex-direction: row;
113109
gap: 0.5rem;
114110
flex-wrap: wrap;
115-
justify-content: center;
116111
& input[type='text'] {
117-
flex: 1;
112+
flex: 7;
118113
background: var(--grey-dark-1);
119114
border: solid 2px var(--green);
120115
outline: none;
@@ -125,6 +120,7 @@
125120
}
126121
}
127122
& input[type='submit'] {
123+
flex: 1;
128124
background: var(--green);
129125
border: none;
130126
border: solid 2px var(--green);

web/src/components/ModSearchList.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@
7575

7676
<style>
7777
table#mod_search_list {
78-
width: 100%;
7978
border-spacing: 0 0.5rem;
8079
padding: 0 0.5rem;
8180
background: var(--grey-dark-1);
8281
font-size: 0.9rem;
82+
width: 100%;
8383
& tbody tr {
8484
&:is(:focus, :focus-visible, :active, :hover) td {
8585
background: var(--grey);

web/src/components/ModsList.svelte

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
padding: 0.5rem;
4242
border: solid 2px var(--green);
4343
background: var(--grey-dark-1);
44-
width: 42rem;
45-
max-width: 42rem;
4644
& li {
4745
display: flex;
4846
flex-direction: row;

web/src/components/ToggleButtons.svelte

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import type { ChangeEventHandler } from 'svelte/elements';
3+
import * as m from '$msg';
34
45
function toggle_selection(key: string) {
56
if (!selection.includes(key)) {
@@ -12,18 +13,16 @@
1213
}
1314
}
1415
15-
function reset_selection() {
16-
selection = [];
17-
}
18-
1916
let {
2017
selection = $bindable(),
2118
entries_list,
19+
name: composant_name,
2220
reset = false,
2321
onchange
2422
}: {
2523
selection: string[];
2624
entries_list: string[];
25+
name: string;
2726
reset?: boolean;
2827
onchange?: ChangeEventHandler<HTMLInputElement>;
2928
} = $props();
@@ -34,19 +33,26 @@
3433
<li class="toggle_button {selection.includes(name) ? 'on' : 'off'}">
3534
<input
3635
type="checkbox"
37-
id={name}
36+
id={composant_name + '-' + name}
3837
onclick={() => {
3938
toggle_selection(name);
4039
}}
4140
{onchange}
4241
/>
43-
<label for={name}>{name.toUpperCase()}</label>
42+
<label for={composant_name + '-' + name}>{name.toUpperCase()}</label>
4443
</li>
4544
{/each}
4645
{#if reset}
4746
<li class="toggle_button reset {selection.length < 1 ? 'disabled' : ''}">
48-
<input type="checkbox" id="reset" onclick={reset_selection} disabled={selection.length < 1} />
49-
<label for="reset">RESET</label>
47+
<input
48+
type="checkbox"
49+
id="{composant_name}-reset"
50+
onclick={() => {
51+
selection = [];
52+
}}
53+
disabled={selection.length < 1}
54+
/>
55+
<label for="{composant_name}-reset">{m.reset_toggle_group().toUpperCase()}</label>
5056
</li>
5157
{/if}
5258
</ul>

0 commit comments

Comments
 (0)