spa.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. var pckry;
  2. document.addEventListener('DOMContentLoaded', (event) => {
  3. // 初始化函數
  4. restoreState();
  5. init();
  6. });
  7. function init() {
  8. // 綁定事件
  9. document.querySelector('.buttonAddImage').addEventListener('click', showAddImageForm);
  10. document.querySelector('.buttonCancelAdd').addEventListener('click', hideAddImageForm);
  11. document.querySelector('.buttonApproveAdd').addEventListener('click', addImage);
  12. document.querySelector('.buttonApproveAddMore').addEventListener('click', addMoreImage);
  13. document.querySelector('.buttonClearCards').addEventListener('click', clearAllCards);
  14. document.querySelector('.buttonAddMeme').addEventListener('click', addMeme);
  15. document.querySelector('.buttonSeedCards').addEventListener('click', seedCards);
  16. var cardholder = document.querySelector('.cardholder');
  17. pckry = new Packery(cardholder, {
  18. // Packery 的選項
  19. itemSelector: '.card',
  20. // percentPosition: true, // 如果你想要使用百分比定位
  21. gutter: 1
  22. });
  23. // makeAllCardsDraggable();
  24. // 綁定卡片點擊事件
  25. cardholder.addEventListener('click', function (event) {
  26. const card = event.target.closest('.card');
  27. if (!card) return; // 如果點擊的不是卡片或卡片內的元素,則不進行任何操作
  28. // 如果點擊的是圖片或圖片的父元素(可能包括一些包裝圖片的容器)
  29. if (event.target === card.querySelector('.mood-image') || event.target.parentNode === card.querySelector('.mood-image')) {
  30. // 如果已經有選中的卡片,則取消選中
  31. const selectedCard = document.querySelector('.card-selected');
  32. if (selectedCard && selectedCard !== card) {
  33. selectedCard.classList.remove('card-selected');
  34. const buttons = selectedCard.querySelector('.card-buttons');
  35. if (buttons) {
  36. buttons.style.display = 'none'; // 隱藏按鈕
  37. }
  38. }
  39. // 切換當前卡片的選中狀態
  40. card.classList.toggle('card-selected');
  41. const currentButtons = card.querySelector('.card-buttons');
  42. if (currentButtons) {
  43. currentButtons.style.display = card.classList.contains('card-selected') ? 'flex' : 'none'; // 顯示或隱藏按鈕
  44. }
  45. }
  46. // 檢查是否點擊了彈出按鈕
  47. if (event.target.closest('.pop-out, .pop-out *')) {
  48. const card = event.target.closest('.card');
  49. card.classList.toggle('popped-out');
  50. if (card.classList.contains('popped-out')) {
  51. // 設置彈出狀態的樣式
  52. card.style.position = 'absolute';
  53. card.style.zIndex = '3'; // 確保彈出卡片在其他卡片上方,但在添加圖片模態窗口下方
  54. card.style.left = '50%'; // 可以調整位置以適應需求
  55. card.style.top = '50%';
  56. card.style.transform = 'translate(-50%, -50%)'; // 居中
  57. } else {
  58. // 復原到正常狀態的樣式
  59. card.style.position = '';
  60. card.style.zIndex = '';
  61. card.style.left = '';
  62. card.style.top = '';
  63. card.style.transform = '';
  64. card.classList.remove('popped-out');
  65. const cardholder = document.querySelector('.cardholder');
  66. cardholder.appendChild(card); // 將卡片移動到容器的最後
  67. pckry.appended(card); // 通知 Packery 新增了卡片並重新佈局
  68. pckry.layout();
  69. }
  70. }
  71. // 根據點擊的是哪個按鈕,執行相應的操作
  72. if (event.target.matches('.delete, .delete *')) { // 匹配刪除按鈕或其內部的元素
  73. pckry.remove(card);
  74. card.remove();
  75. pckry.layout();
  76. } else if (event.target.matches('.zoom-out, .zoom-out *')) { // 匹配縮小按鈕或其內部的元素
  77. // ...縮小操作...
  78. const currentSize = parseInt(card.classList[1].split('-')[2]);
  79. const newSize = Math.max(currentSize - 1, 1); // 確保尺寸不會小於 1
  80. // 更新卡片的尺寸類別
  81. card.className = card.className.replace(`card-size-${currentSize}`, `card-size-${newSize}`);
  82. pckry.layout(); // 通知 Packery 重新佈局
  83. } else if (event.target.matches('.zoom-in, .zoom-in *')) { // 匹配放大按鈕或其內部的元素
  84. // ...放大操作...
  85. const currentSize = parseInt(card.classList[1].split('-')[2]);
  86. const newSize = Math.min(currentSize + 1, 4); // 確保尺寸不會大於 4
  87. // 更新卡片的尺寸類別
  88. card.className = card.className.replace(`card-size-${currentSize}`, `card-size-${newSize}`);
  89. pckry.layout(); // 通知 Packery 重新佈局
  90. } else if (event.target.matches('.move-left, .move-left *')) { // 匹配向左移動按鈕或其內部的元素
  91. // ...向左移動操作...
  92. const previousCard = card.previousElementSibling;
  93. if (previousCard) {
  94. // 將卡片移動到前一個卡片之前
  95. cardholder.insertBefore(card, previousCard);
  96. pckry.reloadItems(); // 重新加載 Packery 的項目
  97. pckry.layout(); // 重新佈局
  98. }
  99. } else if (event.target.matches('.move-right, .move-right *')) { // 匹配向右移動按鈕或其內部的元素
  100. // ...向右移動操作...
  101. const nextCard = card.nextElementSibling;
  102. if (nextCard) {
  103. // 將卡片移動到下一個卡片之後
  104. cardholder.insertBefore(nextCard, card);
  105. pckry.reloadItems(); // 重新加載 Packery 的項目
  106. pckry.layout(); // 重新佈局
  107. }
  108. }
  109. });
  110. }
  111. function showAddImageForm() {
  112. var modal = document.getElementById('addImageModal');
  113. modal.style.display = "block";
  114. var closeButton = document.querySelector('.close');
  115. closeButton.onclick = function () {
  116. modal.style.display = "none";
  117. }
  118. // 當用戶點擊模態視窗以外的地方,關閉它
  119. window.onclick = function (event) {
  120. if (event.target == modal) {
  121. modal.style.display = "none";
  122. }
  123. }
  124. }
  125. function makeAllCardsDraggable() {
  126. // 對現有的每個卡片使用 Draggabilly
  127. var draggableElems = pckry.getItemElements();
  128. for (var i = 0, len = draggableElems.length; i < len; i++) {
  129. var draggableElem = draggableElems[i];
  130. var draggie = new Draggabilly(draggableElem);
  131. pckry.bindDraggabillyEvents(draggie);
  132. }
  133. }
  134. function hideAddImageForm() {
  135. var modal = document.getElementById('addImageModal');
  136. modal.style.display = "none";
  137. }
  138. function addImage(event) {
  139. handleAddImage(event, true);
  140. }
  141. function addMoreImage(event) {
  142. handleAddImage(event, false);
  143. }
  144. function handleAddImage(event, closeModal) {
  145. event.preventDefault();
  146. let imageUrl = document.getElementById('newPicUrl').value.trim();
  147. if (!imageUrl) {
  148. console.log('URL is empty. No action taken.');
  149. return;
  150. }
  151. if (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://')) {
  152. imageUrl = 'https://' + imageUrl;
  153. console.log('URL corrected to: ', imageUrl);
  154. }
  155. addImageWithUrl(imageUrl);
  156. document.getElementById('newPicUrl').value = '';
  157. if (closeModal) {
  158. hideAddImageForm()
  159. }
  160. }
  161. function clearAllCards() {
  162. // 移除所有 .card 元素
  163. var cards = document.querySelectorAll('.card');
  164. cards.forEach(function (card) {
  165. pckry.remove(card); // 通知 Packery 移除元素
  166. card.remove(); // 從 DOM 中移除元素
  167. });
  168. // 通知 Packery 重新佈局剩下的元素
  169. pckry.layout();
  170. }
  171. function addMeme() {
  172. getRandomMemeGif(function (gifUrl) {
  173. // 這裡我們直接調用 addImage 函數,將 Giphy 圖片 URL 作為參數
  174. addImageWithUrl(gifUrl);
  175. });
  176. }
  177. function seedCards() {
  178. imageSeeds.forEach(seed => {
  179. addImageWithUrl(seed.url);
  180. });
  181. }
  182. // 撤銷/重做功能的實現可以根據你的需求設計
  183. // 將 YOUR_API_KEY 替換成你的 Giphy API 密鑰
  184. function getRandomMemeGif(callback) {
  185. const apiKey = 'SHyO3XJY0R71LuTQlx2SlsRuvTrKBjxD';
  186. const apiUrl = `https://api.giphy.com/v1/gifs/random?api_key=${apiKey}&tag=meme`;
  187. fetch(apiUrl)
  188. .then(response => response.json())
  189. .then(data => {
  190. const gifUrl = data.data.images.original.url;
  191. if (callback) callback(gifUrl);
  192. })
  193. .catch(error => {
  194. console.error('Error fetching random meme gif:', error);
  195. });
  196. }
  197. function addImageWithUrl(imageUrl, sizeClass = null) {
  198. const card = document.createElement('div');
  199. card.className = 'card';
  200. if (!sizeClass) {
  201. sizeClass = 'card-size-' + (Math.floor(Math.random() * 4) + 1);
  202. }
  203. card.classList.add(sizeClass);
  204. // 隨機選擇一個大小
  205. // 創建按鈕容器
  206. const buttonsContainer = document.createElement('div');
  207. buttonsContainer.className = 'card-buttons';
  208. // 創建按鈕組
  209. const buttonGroupVertical = document.createElement('div');
  210. buttonGroupVertical.className = 'button-group vertical';
  211. const buttonGroupHorizontal = document.createElement('div');
  212. buttonGroupHorizontal.className = 'button-group horizontal';
  213. // 創建刪除按鈕
  214. const deleteBtn = document.createElement('button');
  215. deleteBtn.className = 'button delete';
  216. deleteBtn.innerHTML = '<i class="ti ti-trash"></i>';
  217. // 創建放大按鈕
  218. const zoomInBtn = document.createElement('button');
  219. zoomInBtn.className = 'button zoom-in';
  220. zoomInBtn.innerHTML = '<i class="ti ti-arrows-maximize"></i>';
  221. // 創建縮小按鈕
  222. const zoomOutBtn = document.createElement('button');
  223. zoomOutBtn.className = 'button zoom-out';
  224. zoomOutBtn.innerHTML = '<i class="ti ti-arrows-minimize"></i>';
  225. // 向按鈕組中添加按鈕
  226. buttonGroupVertical.appendChild(deleteBtn);
  227. buttonGroupVertical.appendChild(zoomInBtn);
  228. buttonGroupVertical.appendChild(zoomOutBtn);
  229. // 創建向左移動按鈕
  230. const moveLeftBtn = document.createElement('button');
  231. moveLeftBtn.className = 'button move-left';
  232. moveLeftBtn.innerHTML = '<i class="ti ti-arrow-left"></i>';
  233. // 創建向右移動按鈕
  234. const moveRightBtn = document.createElement('button');
  235. moveRightBtn.className = 'button move-right';
  236. moveRightBtn.innerHTML = '<i class="ti ti-arrow-right"></i>';
  237. // 向按鈕組中添加按鈕
  238. buttonGroupHorizontal.appendChild(moveLeftBtn);
  239. buttonGroupHorizontal.appendChild(moveRightBtn);
  240. // 向總按鈕容器添加按鈕組
  241. buttonsContainer.appendChild(buttonGroupVertical);
  242. buttonsContainer.appendChild(buttonGroupHorizontal);
  243. // 設置按鈕組的位置
  244. buttonsContainer.style.justifyContent = 'space-between';
  245. buttonsContainer.style.position = 'absolute';
  246. buttonsContainer.style.top = '0';
  247. buttonsContainer.style.left = '0';
  248. buttonsContainer.style.zIndex = '1';
  249. // 創建彈出按鈕
  250. const popOutBtn = document.createElement('button');
  251. popOutBtn.className = 'button pop-out';
  252. popOutBtn.innerHTML = '<i class="ti ti-layers-subtract"></i>'; // 假設這是彈出圖示
  253. buttonGroupVertical.appendChild(popOutBtn); // 添加到垂直按鈕組
  254. // 創建圖片元素
  255. const img = document.createElement('img');
  256. img.src = imageUrl;
  257. img.alt = 'Mood Image';
  258. img.className = 'mood-image';
  259. img.style.position = 'relative';
  260. img.style.zIndex = '2';
  261. // 當圖片加載完成後,將圖片和按鈕容器添加到卡片
  262. img.onload = function () {
  263. card.appendChild(img);
  264. card.appendChild(buttonsContainer);
  265. // 將卡片添加到卡片容器中
  266. const cardholder = document.querySelector('.cardholder');
  267. cardholder.appendChild(card);
  268. // 通知 Packery 新增了卡片並重新布局
  269. pckry.appended(card);
  270. pckry.layout();
  271. // 更新localStorage的狀態
  272. saveState();
  273. };
  274. }
  275. function saveState() {
  276. const cards = document.querySelectorAll('.card');
  277. const state = Array.from(cards).map(card => ({
  278. url: card.querySelector('img').src,
  279. sizeClass: card.classList[1] // 假設大小類別為第二個class
  280. }));
  281. localStorage.setItem('cardsState', JSON.stringify(state));
  282. }
  283. function restoreState() {
  284. const state = JSON.parse(localStorage.getItem('cardsState'));
  285. if (state) {
  286. state.forEach(cardState => {
  287. addImageWithUrl(cardState.url, cardState.sizeClass);
  288. });
  289. }
  290. }