Custom Arka Plan Yöneticisi

Web siteleri için arka plan değiştirme [öncelikli manga-manhwa siteleri]

当前为 2025-01-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Custom Arka Plan Yöneticisi
  3. // @namespace http://Vebascans.net/
  4. // @version 2.3.1.2
  5. // @description Web siteleri için arka plan değiştirme [öncelikli manga-manhwa siteleri]
  6. // @author www.vebascans.net
  7. // @match https://*/*
  8. // @grant none
  9. // @icon https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0QDJZNeXWcaD9lXWMN2yenYt5XGrqfPavkCFpWLe01CpSEsMn7IGpbOLqxEfjx4QUUi4wgTw0Kc7vP7FrKjPKpcaaCu1N6QRJzlZvS_Wwr2r3kA4l0-E5wl7xObsZchd8YNSxySFZATPAr2bnrkANBUrmy8Rpdexe-mxG8N6QDojEj0onaNNXF_6g-s/w800/logo.png
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // 1) SweetAlert2 kütüphanesini otomatik yükle:
  16. const script = document.createElement('script');
  17. script.src = 'https://cdn.jsdelivr.net/npm/sweetalert2@11';
  18. script.onload = main; // Kütüphane yüklendikten sonra main() fonksiyonunu çalıştır
  19. document.head.appendChild(script);
  20.  
  21. // 2) Tüm kodu main() içine alıyoruz:
  22. function main() {
  23.  
  24. /**************************************************************************
  25. * SweetAlert Tanımlaması
  26. **************************************************************************/
  27. const Toast = Swal.mixin({
  28. toast: true,
  29. position: "top",
  30. showConfirmButton: false,
  31. timer: 3000,
  32. timerProgressBar: true,
  33. didOpen: (toast) => {
  34. toast.onmouseenter = Swal.stopTimer;
  35. toast.onmouseleave = Swal.resumeTimer;
  36. }
  37. });
  38.  
  39. /**************************************************************************
  40. * 0) Sabitler
  41. **************************************************************************/
  42. const ACTIVE_KEY = 'VebaScans.net_custom_wp_active'; // Son seçilen veri (URL/Color)
  43. const HISTORY_KEY = 'VebaScans.net_custom_wp_history'; // Tüm geçmiş
  44. const SETTINGS_KEY = 'vebascans.net_custom_wp_settings'; // Arka plan ayarları
  45.  
  46. /**************************************************************************
  47. * 1) Local Storage Yardımcı Fonksiyonları
  48. **************************************************************************/
  49. function getActiveData() {
  50. try {
  51. const str = localStorage.getItem(ACTIVE_KEY);
  52. return str ? JSON.parse(str) : null;
  53. } catch (e) {
  54. return null;
  55. }
  56. }
  57.  
  58. function setActiveData(obj) {
  59. localStorage.setItem(ACTIVE_KEY, JSON.stringify(obj));
  60. applyActiveDataToBody(); // Aktif veri her değiştiğinde body'yi güncelle
  61. }
  62.  
  63. function removeActiveData() {
  64. localStorage.removeItem(ACTIVE_KEY);
  65. applyActiveDataToBody();
  66. }
  67.  
  68. function getHistoryData() {
  69. try {
  70. const str = localStorage.getItem(HISTORY_KEY);
  71. return str ? JSON.parse(str) : [];
  72. } catch (e) {
  73. return [];
  74. }
  75. }
  76.  
  77. function addToHistory(obj) {
  78. let history = getHistoryData();
  79.  
  80. // 1) Eğer geçmişte aynı öğe zaten varsa ekleme yapma
  81. const exists = history.some(item => item.type === obj.type && item.value === obj.value);
  82. if (exists) return; // Aynısı varsa, ekleme yapmadan çık
  83.  
  84. // 2) Yeni öğeyi ekle
  85. history.push(obj);
  86.  
  87. // 3) Aynı öğelerin tekrarını önlemek için filtrele (sadece bir tane kalacak)
  88. history = history.filter((item, index, self) =>
  89. index === self.findIndex(t => t.type === item.type && t.value === item.value)
  90. );
  91.  
  92. // 4) Güncellenmiş geçmişi kaydet
  93. localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
  94. }
  95.  
  96. // Geçmişten silme
  97. function removeFromHistory(obj) {
  98. let history = getHistoryData();
  99. history = history.filter(x => !(x.type === obj.type && x.value === obj.value));
  100. localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
  101. }
  102.  
  103. // Ayarlar
  104. function getSettings() {
  105. try {
  106. const str = localStorage.getItem(SETTINGS_KEY);
  107. return str ? JSON.parse(str) : {};
  108. } catch (e) {
  109. return {};
  110. }
  111. }
  112.  
  113. function setSettings(newSettings) {
  114. localStorage.setItem(SETTINGS_KEY, JSON.stringify(newSettings));
  115. }
  116.  
  117. /**************************************************************************
  118. * 2) BODY Arkaplanını Aktif Veriye (URL/Color) ve Ayarlara Göre Uygulama
  119. **************************************************************************/
  120. function applyActiveDataToBody() {
  121. const activeData = getActiveData();
  122. const settings = getSettings();
  123.  
  124. // Arkaplan tekrar ayarı (varsayılan = 'no-repeat')
  125. const bgRepeat = settings.bgRepeat || 'no-repeat';
  126. // Arkaplan sabit ayarı (varsayılan = 'scroll')
  127. const bgAttachment = settings.bgAttachment || 'scroll';
  128.  
  129. if (!activeData) {
  130. // Aktif bir şey yoksa varsayılan temize çek
  131. document.body.style.backgroundImage = '';
  132. document.body.style.backgroundColor = '';
  133. document.body.style.backgroundRepeat = '';
  134. document.body.style.backgroundAttachment = '';
  135. return;
  136. }
  137.  
  138. if (activeData.type === 'url') {
  139. // Body için arkaplan resmi
  140. document.body.style.backgroundImage = `url(${activeData.value})`;
  141. document.body.style.backgroundRepeat = bgRepeat;
  142. document.body.style.backgroundSize = 'cover';
  143. document.body.style.backgroundAttachment = bgAttachment;
  144. document.body.style.backgroundColor = '';
  145.  
  146. // .body-wrap için
  147. try {
  148. const bodyWrap = document.querySelector('body.text-ui-light .body-wrap');
  149. bodyWrap.style.backgroundImage = `url(${activeData.value})`;
  150. bodyWrap.style.backgroundRepeat = bgRepeat;
  151. bodyWrap.style.backgroundSize = 'cover';
  152. bodyWrap.style.backgroundAttachment = bgAttachment;
  153. bodyWrap.style.backgroundColor = '';
  154. } catch (error) { /* .body-wrap yoksa hata görmezden gel */ }
  155.  
  156. // .site-content için
  157. try {
  158. const sitecontent = document.querySelector('.site-content');
  159. sitecontent.style.backgroundImage = `url(${activeData.value})`;
  160. sitecontent.style.backgroundRepeat = bgRepeat;
  161. sitecontent.style.backgroundSize = 'cover';
  162. sitecontent.style.backgroundAttachment = bgAttachment;
  163. sitecontent.style.backgroundColor = '';
  164. } catch (error) { /* .site-content yoksa hata görmezden gel */ }
  165.  
  166. } else if (activeData.type === 'color') {
  167. // Body için arkaplan rengi
  168. document.body.style.backgroundImage = 'none';
  169. document.body.style.backgroundColor = activeData.value;
  170. document.body.style.backgroundRepeat = bgRepeat;
  171. document.body.style.backgroundAttachment = bgAttachment;
  172.  
  173. // .body-wrap için
  174. try {
  175. const bodyWrap = document.querySelector('body.text-ui-light .body-wrap');
  176. bodyWrap.style.backgroundImage = 'none';
  177. bodyWrap.style.backgroundColor = activeData.value;
  178. bodyWrap.style.backgroundRepeat = bgRepeat;
  179. bodyWrap.style.backgroundAttachment = bgAttachment;
  180. } catch (error) { /* .body-wrap yoksa hata görmezden gel */ }
  181.  
  182. // .site-content için
  183. try {
  184. const sitecontent = document.querySelector('.site-content');
  185. sitecontent.style.backgroundImage = 'none';
  186. sitecontent.style.backgroundColor = activeData.value;
  187. sitecontent.style.backgroundRepeat = bgRepeat;
  188. sitecontent.style.backgroundAttachment = bgAttachment;
  189. } catch (error) { /* .site-content yoksa hata görmezden gel */ }
  190. }
  191. }
  192.  
  193. /**************************************************************************
  194. * 3) MODAL Arayüzü Oluşturma
  195. **************************************************************************/
  196. let modalOverlay, modalContent;
  197.  
  198. window.addEventListener('load', () => {
  199. createModal();
  200. createToggleShortcut(); // F7 ile aç/kapa
  201. applyActiveDataToBody(); // Sayfa açıldığında kaydedilmiş aktif veriyi uygula
  202. });
  203.  
  204. // F7 ile modal aç/kapa
  205. function createToggleShortcut() {
  206. window.addEventListener('keydown', (e) => {
  207. if (e.key === 'F7') {
  208. toggleModal();
  209. }
  210. });
  211. }
  212.  
  213. function toggleModal(forceOpen) {
  214. const isHidden = (modalOverlay.style.display === 'none');
  215. if (forceOpen === true) {
  216. showModal();
  217. } else if (forceOpen === false) {
  218. hideModal();
  219. } else {
  220. if (isHidden) showModal(); else hideModal();
  221. }
  222. }
  223.  
  224. function showModal() {
  225. modalOverlay.style.display = 'block';
  226. refreshHistoryList();
  227. refreshActiveLabel();
  228. refreshSettingsUI();
  229. applyModalTheme(); // Tema ayarını modal açıldığında uygula
  230. }
  231.  
  232. function hideModal() {
  233. modalOverlay.style.display = 'none';
  234. }
  235.  
  236. function createModal() {
  237. // (1) Overlay
  238. modalOverlay = document.createElement('div');
  239. Object.assign(modalOverlay.style, {
  240. display: 'none',
  241. position: 'fixed',
  242. top: '0',
  243. left: '0',
  244. width: '100%',
  245. height: '100%',
  246. backgroundColor: 'rgba(0,0,0,0.5)',
  247. zIndex: '99999',
  248. color: '#000'
  249. });
  250. document.body.appendChild(modalOverlay);
  251.  
  252. // (2) İçerik
  253. modalContent = document.createElement('div');
  254. Object.assign(modalContent.style, {
  255. position: 'absolute',
  256. top: '50%',
  257. left: '50%',
  258. transform: 'translate(-50%, -50%)',
  259. width: '400px',
  260. backgroundColor: '#fff',
  261. padding: '20px',
  262. borderTopLeftRadius: '15px',
  263. borderBottomRightRadius: '15px',
  264. border: '3px solid black',
  265. minHeight: '450px',
  266. fontFamily: 'Arial, sans-serif',
  267. fontSize: '14px',
  268. fontWeight: 'normal',
  269. color: '#000',
  270. });
  271. modalOverlay.appendChild(modalContent);
  272.  
  273. // (3) Logo
  274. const img = document.createElement('img');
  275. img.src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0QDJZNeXWcaD9lXWMN2yenYt5XGrqfPavkCFpWLe01CpSEsMn7IGpbOLqxEfjx4QUUi4wgTw0Kc7vP7FrKjPKpcaaCu1N6QRJzlZvS_Wwr2r3kA4l0-E5wl7xObsZchd8YNSxySFZATPAr2bnrkANBUrmy8Rpdexe-mxG8N6QDojEj0onaNNXF_6g-s/w800/logo.png';
  276. img.alt = 'Logo';
  277. Object.assign(img.style, {
  278. width: '130px',
  279. position: 'absolute',
  280. top: '0',
  281. right: '50%',
  282. transform: 'translate(50%, -50%)'
  283. });
  284. modalContent.appendChild(img);
  285.  
  286. // (4) Başlık
  287. const header = document.createElement('h3');
  288. header.innerHTML = '<a href="https://www.vebascans.net/" style="color: #b83eae;font-weight: 500;text-decoration: none;font-family: fantasy;text-shadow: 0 0 3px #b83eae;letter-spacing: 1px;">Vebascans</a> - Custom Background';
  289. header.style.margin = '0 0 10px 0';
  290. header.style.color = 'black';
  291. header.style.marginTop = '45px';
  292. modalContent.appendChild(header);
  293.  
  294. // (5) Kapat butonu
  295. const closeBtn = document.createElement('button');
  296. closeBtn.innerHTML = `
  297. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  298. <g fill="none" fill-rule="evenodd">
  299. <path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/>
  300. <path fill="currentColor" d="m12 14.122l5.303 5.303a1.5 1.5 0 0 0 2.122-2.122L14.12 12l5.304-5.303a1.5 1.5 0 1 0-2.122-2.121L12 9.879L6.697 4.576a1.5 1.5 0 1 0-2.122 2.12L9.88 12l-5.304 5.304a1.5 1.5 0 1 0 2.122 2.12z"/>
  301. </g>
  302. </svg>`;
  303. Object.assign(closeBtn.style, {
  304. position: 'absolute',
  305. top: '10px',
  306. right: '10px',
  307. border: 'none',
  308. background: 'transparent',
  309. cursor: 'pointer',
  310. color: 'black'
  311. });
  312. closeBtn.onclick = () => hideModal();
  313. modalContent.appendChild(closeBtn);
  314.  
  315. // (6) Seçim Menüsü (URL mi Renk mi)
  316. const selectDiv = document.createElement('div');
  317. Object.assign(selectDiv.style, {
  318. display: 'flex',
  319. flexDirection: 'row',
  320. gap: '5px',
  321. marginBottom: '10px'
  322. });
  323. modalContent.appendChild(selectDiv);
  324.  
  325. const selectLabel = document.createElement('label');
  326. selectLabel.textContent = 'Seçim: ';
  327. selectLabel.style.display = 'flex';
  328. selectLabel.style.alignItems = 'center';
  329. selectDiv.appendChild(selectLabel);
  330.  
  331. const selectInput = document.createElement('select');
  332. selectInput.id = 'typeSelect';
  333. selectInput.style.background ='white';
  334. selectInput.style.border ='2px solid black';
  335. selectInput.style.borderRadius ='3px';
  336. selectInput.style.color = 'black';
  337. const optUrl = new Option('URL', 'url');
  338. const optColor = new Option('Renk', 'color');
  339. selectInput.add(optUrl);
  340. selectInput.add(optColor);
  341. selectDiv.appendChild(selectInput);
  342.  
  343. // (7) URL input
  344. const urlInput = document.createElement('input');
  345. urlInput.type = 'text';
  346. urlInput.id = 'urlInput';
  347. urlInput.placeholder = 'Görsel URL giriniz...';
  348. urlInput.style.background ='transparent';
  349. urlInput.style.border ='2px solid black';
  350. urlInput.style.borderRadius ='3px';
  351. selectDiv.appendChild(urlInput);
  352.  
  353. // (8) Color input
  354. const colorInput = document.createElement('input');
  355. colorInput.type = 'color';
  356. colorInput.id = 'colorInput';
  357. colorInput.value = '#000000';
  358. colorInput.style.width = '50px';
  359. colorInput.style.height = '30px';
  360. colorInput.style.display = 'none';
  361. selectDiv.appendChild(colorInput);
  362.  
  363. // Seçim değişince hangi input görünsün?
  364. selectInput.addEventListener('change', () => {
  365. if (selectInput.value === 'url') {
  366. urlInput.style.display = 'inline-block';
  367. colorInput.style.display = 'none';
  368. } else {
  369. urlInput.style.display = 'none';
  370. colorInput.style.display = 'inline-block';
  371. }
  372. });
  373.  
  374. // (9) Aktar butonu
  375. const aktarBtn = document.createElement('button');
  376. aktarBtn.textContent = 'Aktar';
  377. aktarBtn.style.marginLeft = '5px';
  378. aktarBtn.style.padding = '5px 10px';
  379. aktarBtn.style.cursor = 'pointer';
  380. aktarBtn.style.color = 'black';
  381. aktarBtn.style.border ='2px solid black';
  382. aktarBtn.style.borderRadius ='3px';
  383. aktarBtn.style.background = 'transparent';
  384. selectDiv.appendChild(aktarBtn);
  385.  
  386. aktarBtn.onclick = () => {
  387. const currentType = selectInput.value; // 'url' | 'color'
  388. let currentValue = '';
  389. if (currentType === 'url') {
  390. currentValue = urlInput.value.trim();
  391. if (!currentValue) {
  392. Toast.fire({ icon: 'error', title: 'Lütfen bir URL girin.' });
  393. return;
  394. }
  395. } else {
  396. currentValue = colorInput.value; // #rrggbb
  397. if (!currentValue) {
  398. Toast.fire({ icon: 'error', title: 'Lütfen bir renk seçin.' });
  399. return;
  400. }
  401. }
  402.  
  403. // Yeni aktif obje
  404. const newActiveObj = { type: currentType, value: currentValue };
  405. setActiveData(newActiveObj);
  406. addToHistory(newActiveObj);
  407.  
  408. refreshHistoryList();
  409. refreshActiveLabel();
  410.  
  411. // URL tipini kullandıysa inputu temizleyelim
  412. if (currentType === 'url') {
  413. urlInput.value = '';
  414. }
  415. Toast.fire({ icon: 'success', title: 'Yeni aktif değer atandı ve body arkaplanı güncellendi!' });
  416. };
  417.  
  418. // (10) Tekrar / Tek Sefer AYARI
  419. const repeatDiv = document.createElement('div');
  420. repeatDiv.style.margin = '10px 0';
  421. repeatDiv.style.display = 'flex';
  422. repeatDiv.style.flexDirection = 'row';
  423. repeatDiv.style.gap = '10px';
  424. modalContent.appendChild(repeatDiv);
  425.  
  426. const repeatLabel = document.createElement('span');
  427. repeatLabel.textContent = 'Arkaplan Tekrarı:';
  428. repeatLabel.style.alignSelf = 'center';
  429. repeatDiv.appendChild(repeatLabel);
  430.  
  431. const labelRepeat = document.createElement('label');
  432. const radioRepeat = document.createElement('input');
  433. radioRepeat.type = 'radio';
  434. radioRepeat.name = 'bgRepeat';
  435. radioRepeat.value = 'repeat';
  436. radioRepeat.style.marginRight = '5px';
  437. labelRepeat.appendChild(radioRepeat);
  438. labelRepeat.appendChild(document.createTextNode('Tekrarlı'));
  439. repeatDiv.appendChild(labelRepeat);
  440.  
  441. const labelNoRepeat = document.createElement('label');
  442. const radioNoRepeat = document.createElement('input');
  443. radioNoRepeat.type = 'radio';
  444. radioNoRepeat.name = 'bgRepeat';
  445. radioNoRepeat.value = 'no-repeat';
  446. radioNoRepeat.style.marginRight = '5px';
  447. labelNoRepeat.appendChild(radioNoRepeat);
  448. labelNoRepeat.appendChild(document.createTextNode('Tek Sefer'));
  449. repeatDiv.appendChild(labelNoRepeat);
  450.  
  451. [radioRepeat, radioNoRepeat].forEach(radio => {
  452. radio.addEventListener('change', () => {
  453. const newVal = radio.value; // 'repeat' | 'no-repeat'
  454. const s = getSettings();
  455. s.bgRepeat = newVal;
  456. setSettings(s);
  457. applyActiveDataToBody();
  458. });
  459. });
  460.  
  461. // (10b) Arkaplan Sabit AYARI
  462. const attachDiv = document.createElement('div');
  463. attachDiv.style.margin = '10px 0';
  464. attachDiv.style.display = 'flex';
  465. attachDiv.style.flexDirection = 'row';
  466. attachDiv.style.gap = '10px';
  467. modalContent.appendChild(attachDiv);
  468.  
  469. const attachLabel = document.createElement('span');
  470. attachLabel.textContent = 'Arkaplan Sabitliği:';
  471. attachLabel.style.alignSelf = 'center';
  472. attachDiv.appendChild(attachLabel);
  473.  
  474. const labelFixed = document.createElement('label');
  475. const radioFixed = document.createElement('input');
  476. radioFixed.type = 'radio';
  477. radioFixed.name = 'bgAttach';
  478. radioFixed.value = 'fixed';
  479. radioFixed.style.marginRight = '5px';
  480. labelFixed.appendChild(radioFixed);
  481. labelFixed.appendChild(document.createTextNode('Sabit (Fixed)'));
  482. attachDiv.appendChild(labelFixed);
  483.  
  484. const labelScroll = document.createElement('label');
  485. const radioScroll = document.createElement('input');
  486. radioScroll.type = 'radio';
  487. radioScroll.name = 'bgAttach';
  488. radioScroll.value = 'scroll';
  489. radioScroll.style.marginRight = '5px';
  490. labelScroll.appendChild(radioScroll);
  491. labelScroll.appendChild(document.createTextNode('Kaydır (Scroll)'));
  492. attachDiv.appendChild(labelScroll);
  493.  
  494. [radioFixed, radioScroll].forEach(radio => {
  495. radio.addEventListener('change', () => {
  496. const newVal = radio.value; // 'fixed' | 'scroll'
  497. const s = getSettings();
  498. s.bgAttachment = newVal;
  499. setSettings(s);
  500. applyActiveDataToBody();
  501. });
  502. });
  503.  
  504. // (11) Aktif Veriyi Sil
  505. const removeActiveBtn = document.createElement('button');
  506. removeActiveBtn.textContent = 'Devre dışı bırak';
  507. removeActiveBtn.style.marginBottom = '10px';
  508. removeActiveBtn.style.padding = '5px 10px';
  509. removeActiveBtn.style.cursor = 'pointer';
  510. removeActiveBtn.style.color = 'black';
  511. removeActiveBtn.style.background = 'transparent';
  512. removeActiveBtn.style.border ='2px solid black';
  513. removeActiveBtn.style.borderRadius ='3px';
  514. modalContent.appendChild(removeActiveBtn);
  515.  
  516. removeActiveBtn.onclick = () => {
  517. removeActiveData();
  518. refreshHistoryList();
  519. refreshActiveLabel();
  520. Toast.fire({ icon: 'info', title: 'Aktif veri silindi. Arkaplan temizlendi.' });
  521. };
  522.  
  523. // (12) Şu anda aktif veriyi gösteren label
  524. const activeDiv = document.createElement('div');
  525. activeDiv.id = 'activeDiv';
  526. activeDiv.style.marginTop = '10px';
  527. modalContent.appendChild(activeDiv);
  528.  
  529. // (13) Geçmiş Başlık
  530. const historyTitle = document.createElement('h4');
  531. historyTitle.textContent = 'Geçmiş';
  532. historyTitle.style.margin = '10px 0 5px 0';
  533. modalContent.appendChild(historyTitle);
  534.  
  535. // (14) Geçmiş Container
  536. const historyContainer = document.createElement('div');
  537. historyContainer.id = 'historyContainer';
  538. historyContainer.style.maxHeight = '200px';
  539. historyContainer.style.overflowY = 'auto';
  540. historyContainer.style.border = '1px solid #ccc';
  541. historyContainer.style.padding = '5px';
  542. modalContent.appendChild(historyContainer);
  543.  
  544. // Yedekleme (Dışa/İçe Aktar)
  545. const importExportTitle = document.createElement('h4');
  546. importExportTitle.textContent = 'Yedekleme';
  547. importExportTitle.style.margin = '10px 0 5px 0';
  548. modalContent.appendChild(importExportTitle);
  549.  
  550. const exportBtn = document.createElement('button');
  551. exportBtn.textContent = 'Dışa Aktar (JSON)';
  552. exportBtn.style.padding = '5px 10px';
  553. exportBtn.style.cursor = 'pointer';
  554. exportBtn.style.color = 'black';
  555. exportBtn.style.background = 'transparent';
  556. exportBtn.style.border = '2px solid black';
  557. exportBtn.style.borderRadius = '3px';
  558. exportBtn.style.marginRight = '10px';
  559. modalContent.appendChild(exportBtn);
  560.  
  561. exportBtn.onclick = () => {
  562. exportDataAsJson();
  563. };
  564.  
  565. const importBtn = document.createElement('button');
  566. importBtn.textContent = 'İçe Aktar (JSON)';
  567. importBtn.style.padding = '5px 10px';
  568. importBtn.style.cursor = 'pointer';
  569. importBtn.style.color = 'black';
  570. importBtn.style.background = 'transparent';
  571. importBtn.style.border = '2px solid black';
  572. importBtn.style.borderRadius = '3px';
  573. modalContent.appendChild(importBtn);
  574.  
  575. const importInput = document.createElement('input');
  576. importInput.type = 'file';
  577. importInput.accept = 'application/json';
  578. importInput.style.display = 'none';
  579. modalContent.appendChild(importInput);
  580.  
  581. importBtn.addEventListener('click', () => {
  582. importInput.click(); // Dosya seçme penceresini aç
  583. });
  584.  
  585. importInput.addEventListener('change', () => {
  586. if (importInput.files && importInput.files[0]) {
  587. importDataFromJson(importInput.files[0]);
  588. }
  589. });
  590.  
  591. /**************************************************************************
  592. * _Eklenen Kod Başlangıcı_ (Tema Ayarı)
  593. **************************************************************************/
  594. // Tema AYARI için radyo seçenekleri
  595. const themeDiv = document.createElement('div');
  596. themeDiv.style.marginTop = '15px';
  597. themeDiv.style.display = 'flex';
  598. themeDiv.style.flexDirection = 'row';
  599. themeDiv.style.gap = '10px';
  600. modalContent.appendChild(themeDiv);
  601.  
  602. const themeLabel = document.createElement('span');
  603. themeLabel.textContent = 'Modal Tema:';
  604. themeLabel.style.alignSelf = 'center';
  605. themeDiv.appendChild(themeLabel);
  606.  
  607. const labelLight = document.createElement('label');
  608. const radioLight = document.createElement('input');
  609. radioLight.type = 'radio';
  610. radioLight.name = 'modalTheme';
  611. radioLight.value = 'light';
  612. radioLight.style.marginRight = '5px';
  613. labelLight.appendChild(radioLight);
  614. labelLight.appendChild(document.createTextNode('Aydınlık'));
  615. themeDiv.appendChild(labelLight);
  616.  
  617. const labelDark = document.createElement('label');
  618. const radioDark = document.createElement('input');
  619. radioDark.type = 'radio';
  620. radioDark.name = 'modalTheme';
  621. radioDark.value = 'dark';
  622. radioDark.style.marginRight = '5px';
  623. labelDark.appendChild(radioDark);
  624. labelDark.appendChild(document.createTextNode('Karanlık'));
  625. themeDiv.appendChild(labelDark);
  626.  
  627. // Radyo değişimiyle tema ayarını kaydetme
  628. [radioLight, radioDark].forEach(radio => {
  629. radio.addEventListener('change', () => {
  630. const newVal = radio.value; // 'light' | 'dark'
  631. const s = getSettings();
  632. s.theme = newVal;
  633. setSettings(s);
  634. applyModalTheme(); // Tema uygulansın
  635. });
  636. });
  637.  
  638. const support = document.createElement('div');
  639. support.innerHTML = `
  640. <h3 style="color: black; margin: 4px 0;">Destek;</h3>
  641. <a href="https://www.vebascans.net/discord" style="color: black;align-items: center; display: flex; text-decoration: none;">
  642. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  643. <g fill="currentColor" fill-opacity="0">
  644. <circle cx="9" cy="12" r="1.5">
  645. <animate fill="freeze" attributeName="fill-opacity" begin="1.3s" dur="0.15s" values="0;1"/>
  646. </circle>
  647. <circle cx="15" cy="12" r="1.5">
  648. <animate fill="freeze" attributeName="fill-opacity" begin="1.45s" dur="0.15s" values="0;1"/>
  649. </circle>
  650. <path d="M5 5l7 0.2l7 -0.2l3 10l-3 3.4h-14l-3.5 -3.4l3.5 -10Z">
  651. <animate fill="freeze" attributeName="fill-opacity" begin="1.7s" dur="0.15s" values="0;0.3"/>
  652. </path>
  653. </g>
  654. <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
  655. <path stroke-dasharray="32" stroke-dashoffset="32" d="M12 6h2l1 -2c0 0 2.5 0.5 4 1.5c3.53 2.35 3 9.5 3 10.5c-1.33 2.17 -5.5 3.5 -5.5 3.5l-1 -2M12 6h-2l-0.97 -2c0 0 -2.5 0.5 -4 1.5c-3.53 2.35 -3 9.5 -3 10.5c1.33 2.17 5.5 3.5 5.5 3.5l1 -2">
  656. <animate fill="freeze" attributeName="stroke-dashoffset" dur="0.7s" values="32;0"/>
  657. </path>
  658. <path stroke-dasharray="16" stroke-dashoffset="16" d="M5.5 16c5 2.5 8 2.5 13 0">
  659. <animate fill="freeze" attributeName="stroke-dashoffset" begin="0.8s" dur="0.4s" values="16;0"/>
  660. </path>
  661. </g>
  662. </svg>
  663. </a>`;
  664. support.style.marginTop = '15px';
  665. support.style.display = 'flex';
  666. support.style.flexDirection = 'row';
  667. support.style.gap = '10px';
  668. modalContent.appendChild(support);
  669. }
  670.  
  671. /**************************************************************************
  672. * 4) Geçmiş & Aktif Listeyi Güncelleme
  673. **************************************************************************/
  674. function refreshHistoryList() {
  675. const historyContainer = document.getElementById('historyContainer');
  676. if (!historyContainer) return;
  677.  
  678. historyContainer.innerHTML = '';
  679.  
  680. const historyData = getHistoryData();
  681. const activeData = getActiveData(); // {type:'...', value:'...'}
  682.  
  683. historyData.forEach((item) => {
  684. const row = document.createElement('div');
  685. row.style.display = 'flex';
  686. row.style.alignItems = 'center';
  687. row.style.marginBottom = '8px';
  688. row.style.cursor = 'pointer';
  689. row.style.justifyContent = 'space-between';
  690.  
  691. const leftPart = document.createElement('div');
  692. leftPart.style.display = 'flex';
  693. leftPart.style.alignItems = 'center';
  694. leftPart.style.gap = '8px';
  695.  
  696. // URL ise küçük görsel
  697. if (item.type === 'url') {
  698. const imgThumb = document.createElement('img');
  699. imgThumb.src = item.value;
  700. imgThumb.alt = 'Görsel';
  701. imgThumb.style.width = '30px';
  702. imgThumb.style.height = '30px';
  703. imgThumb.style.objectFit = 'cover';
  704. leftPart.appendChild(imgThumb);
  705.  
  706. const label = document.createElement('span');
  707. label.textContent = 'URL';
  708. leftPart.appendChild(label);
  709.  
  710. } else if (item.type === 'color') {
  711. // Renk ise kutu
  712. const colorBox = document.createElement('span');
  713. colorBox.style.display = 'inline-block';
  714. colorBox.style.width = '30px';
  715. colorBox.style.height = '30px';
  716. colorBox.style.backgroundColor = item.value;
  717. colorBox.style.border = '1px solid #000';
  718. leftPart.appendChild(colorBox);
  719.  
  720. const label = document.createElement('span');
  721. label.textContent = item.value;
  722. leftPart.appendChild(label);
  723. }
  724.  
  725. // Aktif mi?
  726. if (activeData && activeData.type === item.type && activeData.value === item.value) {
  727. const activeSpan = document.createElement('span');
  728. activeSpan.textContent = ' (Aktif)';
  729. activeSpan.style.color = 'green';
  730. leftPart.appendChild(activeSpan);
  731. }
  732.  
  733. // Tıklayınca bu itemi aktif yap
  734. leftPart.addEventListener('click', () => {
  735. setActiveData(item);
  736. refreshHistoryList();
  737. refreshActiveLabel();
  738. Toast.fire({ icon: 'success', title: 'Aktif değer güncellendi!' });
  739. });
  740.  
  741. // Sağ kısma "Geçmişten Sil" butonu
  742. const rightPart = document.createElement('button');
  743. rightPart.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m20 9l-1.995 11.346A2 2 0 0 1 16.035 22h-8.07a2 2 0 0 1-1.97-1.654L4 9m17-3h-5.625M3 6h5.625m0 0V4a2 2 0 0 1 2-2h2.75a2 2 0 0 1 2 2v2m-6.75 0h6.75"/></svg>';
  744. rightPart.style.border ='2px solid black';
  745. rightPart.style.color= 'black'
  746. rightPart.style.borderRadius ='3px';
  747. rightPart.style.background = 'transparent';
  748. rightPart.style.padding = '3px 5px';
  749. rightPart.style.cursor = 'pointer';
  750.  
  751. rightPart.addEventListener('click', (e) => {
  752. e.stopPropagation(); // Aktif yapma tıklamasını engelle
  753.  
  754. // Aktif veriyi al
  755. const activeData = getActiveData();
  756.  
  757. // Eğer silinmek istenen veri aktif veriyle eşleşiyorsa, işlemi durdur
  758. if (activeData && activeData.type === item.type && activeData.value === item.value) {
  759. Toast.fire({ icon: 'warning', title: 'Aktif olan bir veriyi silemezsiniz!' });
  760. return; // İşlemi durdur
  761. }
  762.  
  763. // Eğer aktif veri değilse, geçmişten sil
  764. removeFromHistory(item);
  765. refreshHistoryList();
  766. Toast.fire({ icon: 'info', title: 'Geçmişten silindi.' });
  767. });
  768.  
  769. row.appendChild(leftPart);
  770. row.appendChild(rightPart);
  771. historyContainer.appendChild(row);
  772. });
  773. }
  774.  
  775. function refreshActiveLabel() {
  776. const activeDiv = document.getElementById('activeDiv');
  777. if (!activeDiv) return;
  778.  
  779. const activeData = getActiveData();
  780. if (!activeData) {
  781. activeDiv.textContent = 'Şu anda aktif bir değer yok.';
  782. } else {
  783. if (activeData.type === 'url') {
  784. activeDiv.innerHTML = `
  785. Aktif: URL
  786. <img src="${activeData.value}"
  787. alt="Aktif Görsel"
  788. style="width: 100px; height: auto; object-fit: cover; margin-left:5px;"/>
  789. `;
  790. } else {
  791. activeDiv.innerHTML = `
  792. Aktif: Renk
  793. <span style="display:inline-block; width:20px; height:20px;
  794. background-color:${activeData.value};
  795. border:1px solid #000; vertical-align:middle;">
  796. </span>
  797. ${activeData.value}
  798. `;
  799. }
  800. }
  801. }
  802.  
  803. /**************************************************************************
  804. * 5) Arkaplan Ayarı (Tekrar / Tek Sefer / Sabit) Radyo Butonlarını Güncelleme
  805. **************************************************************************/
  806. function refreshSettingsUI() {
  807. const settings = getSettings();
  808. const bgRepeat = settings.bgRepeat || 'no-repeat'; // Varsayılan no-repeat
  809. const bgAttach = settings.bgAttachment || 'scroll'; // Varsayılan scroll
  810.  
  811. // Tekrar radyo
  812. const radiosRepeat = document.getElementsByName('bgRepeat');
  813. radiosRepeat.forEach(radio => {
  814. radio.checked = (radio.value === bgRepeat);
  815. });
  816.  
  817. // Sabit/Kaydır radyo
  818. const radiosAttach = document.getElementsByName('bgAttach');
  819. radiosAttach.forEach(radio => {
  820. radio.checked = (radio.value === bgAttach);
  821. });
  822.  
  823. // _Eklenen Kod: Modal Tema radyo
  824. const theme = settings.theme || 'light'; // Varsayılan 'light'
  825. const radiosTheme = document.getElementsByName('modalTheme');
  826. radiosTheme.forEach(radio => {
  827. radio.checked = (radio.value === theme);
  828. });
  829. }
  830.  
  831. // Tema uygulama fonksiyonu
  832. function applyModalTheme() {
  833. const settings = getSettings();
  834. const theme = settings.theme || 'light';
  835.  
  836. if (theme === 'dark') {
  837. // Modal ana gövde
  838. modalContent.style.backgroundColor = '#070707';
  839. modalContent.style.color = 'white';
  840. modalContent.style.border = '2px solid white';
  841.  
  842. // Tüm alt öğeleri tarayalım:
  843. const allElements = modalContent.querySelectorAll('*');
  844. allElements.forEach(el => {
  845. // Eğer siyah sınır varsa beyaza çevir
  846. if (el.style.border === '2px solid black') {
  847. el.style.border = '2px solid white';
  848. }
  849. // Yazı rengi siyahsa beyaza çevir
  850. if (el.style.color === 'black') {
  851. el.style.color = 'white';
  852. }
  853. // Arka plan beyaz veya 'transparent' ise #070707 yap
  854. const bg = el.style.backgroundColor || el.style.background;
  855. if (bg === 'white' || bg === 'transparent') {
  856. el.style.backgroundColor = '#070707';
  857. }
  858. });
  859.  
  860. } else {
  861. // Light (aydınlık) tema için varsayılanlar
  862. modalContent.style.backgroundColor = '#fff';
  863. modalContent.style.color = 'black';
  864. modalContent.style.border = '2px solid black';
  865.  
  866. // Tekrar tüm alt öğeleri dolaşıp varsayılan değerlere çekebilirsiniz
  867. const allElements = modalContent.querySelectorAll('*');
  868. allElements.forEach(el => {
  869. // Siyah kenarlık
  870. if (el.style.border === '2px solid white') {
  871. el.style.border = '2px solid black';
  872. }
  873. // Yazı rengi beyaz ise siyaha çevir
  874. if (el.style.color === 'white') {
  875. el.style.color = 'black';
  876. }
  877. // Arka plan koyu ise beyaza veya transparent’e döndürebilirsiniz
  878. const bg = el.style.backgroundColor || el.style.background;
  879. if (bg === 'rgb(7, 7, 7)' || bg === '#070707') {
  880. el.style.backgroundColor = 'white';
  881. }
  882. });
  883. }
  884. }
  885.  
  886. // Dışa Aktar (JSON olarak)
  887. function exportDataAsJson() {
  888. // Tek bir obje içine aktif, geçmiş ve ayarları al
  889. const data = {
  890. active: getActiveData(),
  891. history: getHistoryData(),
  892. settings: getSettings()
  893. };
  894. const jsonStr = JSON.stringify(data, null, 2);
  895.  
  896. // Dosya oluşturup otomatik indirme linki
  897. const blob = new Blob([jsonStr], { type: 'application/json' });
  898. const url = URL.createObjectURL(blob);
  899. const a = document.createElement('a');
  900. a.href = url;
  901. a.download = 'Vebascans_CustomBackground.json';
  902. document.body.appendChild(a);
  903. a.click();
  904. a.remove();
  905. URL.revokeObjectURL(url);
  906.  
  907. Toast.fire({ icon: 'success', title: 'Veriler JSON formatında indirildi!' });
  908. }
  909.  
  910. // İçe Aktar (JSON dosyasından)
  911. function importDataFromJson(file) {
  912. const reader = new FileReader();
  913. reader.onload = (e) => {
  914. try {
  915. const imported = JSON.parse(e.target.result);
  916.  
  917. // Dosyada hangi veriler varsa alıp localStorage'a yazalım
  918. if (imported.active) {
  919. localStorage.setItem(ACTIVE_KEY, JSON.stringify(imported.active));
  920. }
  921. if (imported.history) {
  922. localStorage.setItem(HISTORY_KEY, JSON.stringify(imported.history));
  923. }
  924. if (imported.settings) {
  925. localStorage.setItem(SETTINGS_KEY, JSON.stringify(imported.settings));
  926. }
  927.  
  928. // Yeniden uygula ve arayüzü tazele
  929. applyActiveDataToBody();
  930. refreshHistoryList();
  931. refreshActiveLabel();
  932. refreshSettingsUI();
  933. applyModalTheme();
  934.  
  935. Toast.fire({ icon: 'success', title: 'JSON verileri başarıyla içe aktarıldı!' });
  936. } catch (error) {
  937. Toast.fire({ icon: 'error', title: 'Geçersiz JSON dosyası veya okuma hatası!' });
  938. }
  939. };
  940. reader.readAsText(file);
  941. }
  942.  
  943. } // main() sonu
  944.  
  945. })(); // IIFE sonu