diff --git a/assets/js/gallery-pro.js b/assets/js/gallery-pro.js
new file mode 100644
index 0000000..ae1624d
--- /dev/null
+++ b/assets/js/gallery-pro.js
@@ -0,0 +1,620 @@
+(function ($) {
+ 'use strict';
+
+ if (typeof mcGalleryPro === 'undefined') {
+ console.error('MC Gallery Pro: Configuration not found.');
+ return;
+ }
+
+ const api = mcGalleryPro.restBase.replace(/\/?$/, '');
+ const ajaxUrl = mcGalleryPro.uploadUrl;
+ const maxUploads = mcGalleryPro.maxUploads || 5;
+
+ let originalBodyPadding = '';
+ let scrollbarWidth = 0;
+
+ let sessionData = {
+ token: null,
+ username: null,
+ serverId: null,
+ verified: false
+ };
+
+ let selectedFiles = [];
+
+ function getScrollbarWidth() {
+ if (scrollbarWidth > 0) return scrollbarWidth;
+ const outer = document.createElement('div');
+ outer.style.visibility = 'hidden';
+ outer.style.width = '100px';
+ outer.style.msOverflowStyle = 'scrollbar';
+ document.body.appendChild(outer);
+
+ const widthNoScroll = outer.offsetWidth;
+ outer.style.overflow = 'scroll';
+
+ const inner = document.createElement('div');
+ inner.style.width = '100%';
+ outer.appendChild(inner);
+
+ const widthWithScroll = inner.offsetWidth;
+ outer.parentNode.removeChild(outer);
+
+ scrollbarWidth = widthNoScroll - widthWithScroll;
+ return scrollbarWidth;
+ }
+
+ function showFeedback(msg, type = 'info') {
+ const $fb = $('#mc-feedback-msg');
+ $fb.removeClass('mc-msg-success mc-msg-error');
+
+ if (type === 'success') {
+ $fb.addClass('mc-msg-success');
+ } else if (type === 'error') {
+ $fb.addClass('mc-msg-error');
+ }
+
+ $fb.html(msg).fadeIn(300);
+ }
+
+ function switchStep(stepNum) {
+ $('.mc-step').removeClass('active');
+ $(`.mc-step[data-step="${stepNum}"]`).addClass('active');
+ }
+
+ function resetModal() {
+ $('#mc-upload-username').val('');
+ $('#mc-token-text').text('Waiting...');
+ $('#mc-upload-file').val('');
+ $('#mc-file-name').text('Keine Bilder gewählt').css('color', '');
+ $('.mc-file-drop').css('border-color', '').css('background', '');
+ $('#mc-feedback-msg').hide().empty();
+ $('#mc-file-preview').empty();
+ $('#mc-upload-progress').hide();
+ $('#mc-btn-upload-more').hide();
+ $('#mc-btn-final-upload').show();
+ selectedFiles = [];
+ sessionData = {
+ token: null,
+ username: null,
+ serverId: null,
+ verified: false
+ };
+ switchStep(1);
+ }
+
+ function loadServers() {
+ const $select = $('#mc-upload-server');
+ if (!$select.length) return;
+
+ $select.html('').prop('disabled', true);
+
+ fetch(api + '/servers')
+ .then(response => {
+ if (!response.ok) throw new Error('Server response not OK');
+ return response.json();
+ })
+ .then(data => {
+ if (data.success && Array.isArray(data.data) && data.data.length > 0) {
+ $select.empty().prop('disabled', false);
+ data.data.forEach(server => {
+ const displayText = server.host
+ ? `${server.title} (${server.host})`
+ : server.title;
+ $select.append($('');
+ }
+ })
+ .catch(error => {
+ console.error('Failed to load servers:', error);
+ $select.html('');
+ });
+ }
+
+ function loadAlbums() {
+ const $select = $('#mc-upload-album');
+ $select.html('').prop('disabled', true);
+
+ if (!sessionData.token || !sessionData.verified) return;
+
+ fetch(api + '/albums', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ token: sessionData.token,
+ username: sessionData.username,
+ server_id: sessionData.serverId
+ })
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success && data.data.albums) {
+ $select.prop('disabled', false);
+ data.data.albums.forEach(album => {
+ $select.append($('