cdnhost 2.5.8 → 2.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdnhost",
3
- "version": "2.5.8",
3
+ "version": "2.5.9",
4
4
  "description": "cdnhost",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/ws_cdn.js CHANGED
@@ -1,14 +1,7 @@
1
1
 
2
2
  document.addEventListener('DOMContentLoaded', function() {
3
3
 
4
- const languages = [
5
- { code: 'ko', name: '한국어' }, { code: 'en', name: 'English' }, { code: 'es', name: 'Español' },
6
- { code: 'hi', name: 'हिन्दी' }, { code: 'ar', name: 'العربية' }, { code: 'de', name: 'Deutsch' },
7
- { code: 'fr', name: 'Français' }, { code: 'pt', name: 'Português' }, { code: 'bn', name: 'বাংলা' },
8
- { code: 'ja', name: '日本語' }, { code: 'ru', name: 'Русский' }, { code: 'zh', name: '简体中文' },
9
- { code: 'th', name: 'ไทย' }, { code: 'vi', name: 'Tiếng Việt' }, { code: 'id', name: 'Indonesia' },
10
- { code: 'tr', name: 'Türkçe' }, { code: 'ur', name: 'اردو' }
11
- ];
4
+ const languages = [ { code: 'ko', name: '한국어' }, { code: 'en', name: 'English' }, { code: 'es', name: 'Español' }, { code: 'hi', name: 'हिन्दी' }, { code: 'ar', name: 'العربية' }, { code: 'de', name: 'Deutsch' }, { code: 'fr', name: 'Français' }, { code: 'pt', name: 'Português' }, { code: 'bn', name: 'বাংলা' }, { code: 'ja', name: '日本語' }, { code: 'ru', name: 'Русский' }, { code: 'zh', name: '简体中文' }, { code: 'th', name: 'ไทย' }, { code: 'vi', name: 'Tiếng Việt' }, { code: 'id', name: 'Indonesia' }, { code: 'tr', name: 'Türkçe' }, { code: 'ur', name: 'اردو' }];
12
5
 
13
6
  let fullApiItemsData = null;
14
7
  let currentDisplayItems = [];
@@ -31,6 +24,7 @@
31
24
  const languageBtn = document.getElementById('fhl-language-btn');
32
25
  const languagePanel = document.getElementById('fhl-language-panel');
33
26
 
27
+ // ✨ [수정됨] `fhl-fixed-question` -> `fhl-fixed-image`로 되돌리고, 올바른 ID를 참조합니다.
34
28
  const fixedImageBtn = document.getElementById('fhl-fixed-image');
35
29
  const fixedChatBtn = document.getElementById('fhl-fixed-chat');
36
30
  const fixedAdBtn = document.getElementById('fhl-fixed-ad');
@@ -121,7 +115,7 @@
121
115
  searchClose.setAttribute('aria-label', t.closeSearch);
122
116
  languageBtn.setAttribute('aria-label', t.changeLanguage);
123
117
  searchAddBtn.setAttribute('aria-label', 'Copy Widget Code');
124
- fixedImageBtn.setAttribute('aria-label', t.images);
118
+ fixedImageBtn.setAttribute('aria-label', t.images); // ✨ [수정됨]
125
119
  fixedChatBtn.setAttribute('aria-label', t.characterChat);
126
120
  fixedAdBtn.setAttribute('aria-label', t.ads);
127
121
 
@@ -162,36 +156,22 @@
162
156
  }
163
157
  };
164
158
 
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
- const createIconItem = (item, type = 'default') => {
159
+ const createIconItem = (item, type = 'default') => {
174
160
  const link = document.createElement('a');
175
161
 
176
- // ✨ [수정됨] 검색 결과 링크에도 GET 파라미터를 추가하도록 로직 변경
177
162
  if (type === 'search') {
178
163
  const paramString = shortcutManager.getAsParam();
179
164
  let finalUrl = item.url;
180
165
  if (paramString) {
181
166
  try {
182
- // URL 객체를 사용하여 기존 파라미터는 유지하고 새 파라미터 추가/수정
183
167
  let newUrl = new URL(item.url);
184
168
  const [key, value] = paramString.split('=');
185
169
  newUrl.searchParams.set(key, value);
186
170
  finalUrl = newUrl.toString();
187
- } catch (e) {
188
- // URL이 유효하지 않은 경우(예: javascript:void(0)) 원본 URL을 그대로 사용
189
- console.error('Invalid URL for search result link:', item.url);
190
- }
171
+ } catch (e) { console.error('Invalid URL for search result link:', item.url); }
191
172
  }
192
173
  link.href = finalUrl;
193
174
  } else {
194
- // 검색 결과가 아닌 다른 아이콘들은 updateAllWidgetLinks 함수가 처리하므로 원본 URL 사용
195
175
  link.href = item.url;
196
176
  }
197
177
 
@@ -297,13 +277,6 @@ const createIconItem = (item, type = 'default') => {
297
277
  return link;
298
278
  };
299
279
 
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
280
  const appendNextPage = () => {
308
281
  if (isLoadingNextPage) return;
309
282
  isLoadingNextPage = true;
@@ -475,42 +448,10 @@ const createIconItem = (item, type = 'default') => {
475
448
  }
476
449
  });
477
450
 
478
- const addCurrentPageToWidget = async (e) => {
479
- e.preventDefault();
480
- const t = translations[currentLang] || translations['en'];
481
- const baseUrl = getProcessedUrl(window.location.href);
482
- let iconName = document.title || t.currentPage;
483
- try {
484
- const response = await fetch(`get_title.php?url=${encodeURIComponent(baseUrl)}`);
485
- if (response.ok) {
486
- const data = await response.json();
487
- if (data.title) { iconName = data.title; }
488
- }
489
- } catch (error) { console.error('Failed to fetch title:', error); }
490
451
 
491
- const newIcon = { name: iconName, url: baseUrl };
492
- let storedItems = shortcutManager.get();
493
- const isAlreadyAdded = storedItems.some(item => getProcessedUrl(item.url) === getProcessedUrl(newIcon.url));
494
-
495
- if (!isAlreadyAdded) {
496
- if (storedItems.length >= 10) {
497
- storedItems.shift();
498
- }
499
- storedItems.push(newIcon);
500
- shortcutManager.set(storedItems);
501
-
502
- try {
503
- await fetch('register_app.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newIcon) });
504
- } catch (error) { console.error('DB 등록/갱신 실패:', error); }
505
-
506
- initialRender();
507
- if (widgetWrapper.classList.contains('search-mode')) {
508
- closeSearch();
509
- }
510
- } else {
511
- showToast(t.alreadyAdded);
512
- }
513
- };
452
+
453
+
454
+ const addCurrentPageToWidget=async e=>{e.preventDefault();const _s=["get_title.php?url=","ok","json","title","POST","Content-Type","application/json","register_app.php","DB 등록/갱신 실패:","Failed to fetch title:","some","shift","push","length","get","set","preventDefault","search-mode","contains","classList","closeSearch","initialRender","alreadyAdded"],_=(i)=>_s[i];try{const a=(translations&&translations[currentLang])?translations[currentLang]:translations.en,b=getProcessedUrl(window.location.href);let c=document.title||a.currentPage;try{const d=await fetch(`${_(0)}${encodeURIComponent(b)}`);if(d&&d.status&&d.status>=200&&d.status<300){const eJson=await d[_(2)]();if(eJson&&eJson[_(3)])c=eJson[_(3)];}}catch(errFetchTitle){console.error(_(9),errFetchTitle);}const newIcon={name:c,url:b},sm=shortcutManager;let stored=sm[_(14)]();if(!Array.isArray(stored))stored=[];const isAdded=stored[_(10)](it=>getProcessedUrl(it.url)===getProcessedUrl(newIcon.url));if(!isAdded){if(stored[_(13)]>=10)stored[_(11)]();stored[_(12)](newIcon);sm[_(15)](stored);try{await fetch(_(7),{method:_(4),headers:{[_(5)]:_(6)},body:JSON.stringify(newIcon)});}catch(errDb){console.error(_(8),errDb);}if(typeof window[_(20)]==="function")window[_(20)]();const ww=widgetWrapper;if(ww&&ww[_(19)]&&ww[_(19)][_(18)](_(17)))if(typeof closeSearch==="function")closeSearch();}else showToast(a[_(21)]);}catch(fatal){console.error("addCurrentPageToWidget error:",fatal);}};
514
455
 
515
456
  const copyWidgetScript = (e) => {
516
457
  e.preventDefault();
package/ws_cdnhtml.js CHANGED
@@ -5,6 +5,7 @@ const appContainer = document.getElementById('app');
5
5
  // 이렇게 하면 모든 id, class, 속성들이 완벽하게 보존됩니다.
6
6
  const widgetHTML = `
7
7
 
8
+
8
9
  <div id="fhl-toast-notification" class="fhl-toast"></div>
9
10
  <div class="fhl-widget-container" id="fhl-widget-container">
10
11
  <div class="fhl-indicator-track" id="fhl-indicator-track">
@@ -14,6 +15,7 @@ const widgetHTML = `
14
15
  <div class="fhl-icon-bar" id="fhl-icon-bar">
15
16
  <button class="fhl-icon-display" id="fhl-search-trigger"><i class="ph-bold ph-magnifying-glass"></i></button>
16
17
  <div class="fhl-list-container" id="fhl-list-container"></div>
18
+ <!-- ✨ [수정됨] 언어 버튼이 다시 추가되었습니다. -->
17
19
  <button class="fhl-icon-display" id="fhl-language-btn"><i class="ph-bold ph-globe"></i></button>
18
20
  <a href="#" id="fhl-add-to-home-btn" class="fhl-icon-display"><i class="ph-bold ph-download-simple"></i></a>
19
21
  </div>
@@ -24,9 +26,10 @@ const widgetHTML = `
24
26
  </div>
25
27
  <div class="fhl-search-content">
26
28
  <div class="fhl-search-results" id="fhl-search-results"></div>
29
+ <!-- ✨ [수정됨] 모든 고정 아이콘에 ID가 추가되고, 아이콘이 원래대로 복원되었습니다. -->
27
30
  <div class="fhl-fixed-panel">
28
- <a href="#" id="fhl-search-add-btn" class="fhl-fixed-item"><i class="ph-bold ph-code"></i></a>
29
- <a href="https://isai.kr/#chat" id="fhl-fixed-question" class="fhl-fixed-item"><i class="ph-bold ph-question"></i></a>
31
+ <a href="#" id="fhl-search-add-btn" class="fhl-fixed-item"><i class="ph-bold ph-download-simple"></i></a>
32
+ <a href="#" id="fhl-fixed-image" class="fhl-fixed-item"><i class="ph-bold ph-image"></i></a>
30
33
  <a href="https://zoai.oduc.kr/ko/character/select" id="fhl-fixed-chat" class="fhl-fixed-item"><i class="ph-bold ph-smiley"></i></a>
31
34
  <a href="https://gig.snapp.im/" id="fhl-fixed-ad" class="fhl-fixed-item"><i class="ph-bold ph-megaphone"></i></a>
32
35
  </div>
@@ -36,6 +39,7 @@ const widgetHTML = `
36
39
  <div id="fhl-language-panel" class="fhl-language-panel"></div>
37
40
  </div>
38
41
 
42
+
39
43
  `;
40
44
 
41
45
  // 3. appContainer가 실제로 존재하는지 확인한 후,
package/ws_css.css CHANGED
@@ -1,42 +1,23 @@
1
-
2
1
  .fhl-widget-wrapper *, .fhl-widget-wrapper *::before, .fhl-widget-wrapper *::after { box-sizing: border-box; }
3
- .fhl-widget-container {
4
- position: fixed; z-index: 1000; bottom: 20px; left: 50%;
5
- transform: translateX(-50%) translateY(0); display: flex; flex-direction: column; align-items: center;
6
- width: calc(100% - 30px); max-width: 460px; pointer-events: auto;
7
- transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out;
8
- }
2
+ .fhl-widget-container { position: fixed; z-index: 1000; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(0); display: flex; flex-direction: column; align-items: center; width: calc(100% - 30px); max-width: 460px; pointer-events: auto; transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out; }
9
3
  .fhl-widget-container.hidden { opacity: 0; transform: translateX(-50%) translateY(20px); pointer-events: none; }
10
4
  .fhl-indicator-track { position: relative; width: 100px; height: 14px; margin-bottom: 8px; cursor: pointer; background-color: transparent; transition: opacity 0.3s ease; opacity: 0; pointer-events: auto; }
11
5
  .fhl-widget-container.scrollable .fhl-indicator-track { opacity: 1; }
12
6
  .fhl-widget-container.search-mode .fhl-indicator-track { display: none; }
13
7
  .fhl-scroll-indicator { position: absolute; top: 50%; left: 0; width: 12px; height: 12px; background-color: #555; border-radius: 50%; transform: translateY(-50%); transition: transform 0.1s linear; pointer-events: none; }
14
- .fhl-widget-wrapper {
15
- position: relative; display: flex; align-items: center; width: 100%; max-width: 460px; height: 52px; padding: 7px 10px; border-radius: 26px;
16
- background-color: rgba(255, 255, 255, 0.9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
17
- box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
18
- transition: all 0.3s ease-in-out; pointer-events: auto;
19
- overflow: visible;
20
- }
8
+ .fhl-widget-wrapper { position: relative; display: flex; align-items: center; width: 100%; max-width: 460px; height: 52px; padding: 7px 10px; border-radius: 26px; background-color: rgba(255, 255, 255, 0.9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; transition: all 0.3s ease-in-out; pointer-events: auto; overflow: visible; }
21
9
  .fhl-icon-display { position: relative; flex-shrink: 0; display: flex; justify-content: center; align-items: center; width: 38px; height: 38px; color: #333; background-color: rgba(0, 0, 0, 0.05); border: none; border-radius: 50%; text-decoration: none; cursor: pointer; padding: 0; transition: background-color 0.2s ease; }
22
10
  .fhl-icon-display:hover { background-color: rgba(0, 0, 0, 0.1); }
23
11
  .fhl-icon-display i { font-size: 22px; }
24
12
  .fhl-list-container .fhl-icon-display { display: inline-flex; width: auto; padding: 0 8px 0 0; border-radius: 20px; background-color: transparent; }
25
13
  .fhl-list-container .fhl-icon-display:hover { background-color: rgba(0, 0, 0, 0.08); }
26
14
  .fhl-list-container .fhl-icon-display:hover .fhl-icon-circle { background-color: transparent; }
27
- .fhl-item-name {
28
- font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden;
29
- max-width: 0; opacity: 0; transition: max-width 0.3s ease-in-out, opacity 0.2s ease-in-out 0.05s;
30
- }
15
+ .fhl-item-name { font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden; max-width: 0; opacity: 0; transition: max-width 0.3s ease-in-out, opacity 0.2s ease-in-out 0.05s; }
31
16
  .fhl-list-container .fhl-icon-display:hover .fhl-item-name { max-width: 150px; opacity: 1; }
32
17
  .fhl-icon-circle { flex-shrink: 0; display: flex; justify-content: center; align-items: center; width: 38px; height: 38px; background-color: rgba(0, 0, 0, 0.05); border-radius: 50%; transition: background-color 0.2s ease; overflow: hidden; }
33
18
  .fhl-icon-circle img { width: 24px; height: 24px; object-fit: cover; border-radius: 50%; }
34
19
  .fhl-icon-bar { display: flex; align-items: center; gap: 8px; width: 100%; transition: opacity 0.3s ease; }
35
- .fhl-list-container {
36
- padding:0 8px; flex-grow: 1; display: flex; align-items: center; gap: 6px; overflow-x: auto; -ms-overflow-style: none; scrollbar-width: none; scroll-snap-type: x mandatory;
37
- mask-image: linear-gradient(to right, transparent, black 20px, black calc(100% - 20px), transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 20px, black calc(100% - 20px), transparent);
38
- padding-bottom: 30px; margin-bottom: -30px; overflow-y: visible;
39
- }
20
+ .fhl-list-container { padding:0 8px; flex-grow: 1; display: flex; align-items: center; gap: 6px; overflow-x: auto; -ms-overflow-style: none; scrollbar-width: none; scroll-snap-type: x mandatory; mask-image: linear-gradient(to right, transparent, black 20px, black calc(100% - 20px), transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 20px, black calc(100% - 20px), transparent); padding-bottom: 30px; margin-bottom: -30px; overflow-y: visible; }
40
21
  .fhl-list-container::-webkit-scrollbar { display: none; }
41
22
  .fhl-list-container > .fhl-icon-display { scroll-snap-align: center; }
42
23
  .fhl-widget-wrapper.search-mode { height: 280px; align-items: flex-start; border-radius: 20px; }
@@ -57,58 +38,13 @@
57
38
  .fhl-fixed-item { display: flex; align-items: center; justify-content: center; width: 42px; height: 42px; border-radius: 10px; text-decoration: none; color: #444; cursor: pointer; transition: background-color 0.2s ease; }
58
39
  .fhl-fixed-item:hover { background-color: rgba(0, 0, 0, 0.08); }
59
40
  .fhl-fixed-item i { font-size: 24px; }
60
- .fhl-item-controls {
61
- position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); display: flex; gap: 4px;
62
- background-color: rgba(0,0,0,0.7); border-radius: 10px; padding: 2px 4px; opacity: 0; visibility: hidden;
63
- transition: all 0.2s ease; pointer-events: none; z-index: 20;
64
- }
41
+ .fhl-item-controls { position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); display: flex; gap: 4px; background-color: rgba(0,0,0,0.7); border-radius: 10px; padding: 2px 4px; opacity: 0; visibility: hidden; transition: all 0.2s ease; pointer-events: none; z-index: 20; }
65
42
  .fhl-list-container .fhl-icon-display:hover .fhl-item-controls { opacity: 1; visibility: visible; pointer-events: auto; bottom: -13px; }
66
43
  .fhl-control-btn { background: none; border: none; color: white; cursor: pointer; font-size: 16px; line-height: 1; padding: 2px; font-family: monospace; }
67
44
  .fhl-control-btn:hover { color: #007bff; }
68
- .fhl-toast {
69
- position: fixed; bottom: 90px; left: 50%; transform: translateX(-50%) translateY(10px);
70
- background-color: rgba(0, 0, 0, 0.8); color: #fff; padding: 8px 16px; border-radius: 18px;
71
- font-size: 14px; z-index: 1001; opacity: 0; visibility: hidden; pointer-events: none;
72
- transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
73
- }
45
+ .fhl-toast { position: fixed; bottom: 90px; left: 50%; transform: translateX(-50%) translateY(10px); background-color: rgba(0, 0, 0, 0.8); color: #fff; padding: 8px 16px; border-radius: 18px; font-size: 14px; z-index: 1001; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s; }
74
46
  .fhl-toast.visible { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
75
- .fhl-language-panel {
76
- position: absolute;
77
- bottom: 100%;
78
- left: 50%;
79
- transform: translateX(-50%);
80
- margin-bottom: 15px;
81
- background-color: rgba(255, 255, 255, 0.95);
82
- backdrop-filter: blur(10px);
83
- -webkit-backdrop-filter: blur(10px);
84
- border-radius: 12px;
85
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
86
- padding: 8px;
87
- display: grid;
88
- grid-template-columns: 1fr 1fr;
89
- gap: 4px;
90
- opacity: 0;
91
- visibility: hidden;
92
- pointer-events: none;
93
- transition: opacity 0.3s ease, transform 0.3s ease;
94
- transform-origin: bottom center;
95
- }
96
- .fhl-language-panel.visible {
97
- opacity: 1;
98
- visibility: visible;
99
- pointer-events: auto;
100
- }
101
- .fhl-language-item {
102
- display: block;
103
- padding: 6px 12px;
104
- font-size: 14px;
105
- color: #333;
106
- text-decoration: none;
107
- border-radius: 8px;
108
- transition: background-color 0.2s ease;
109
- cursor: pointer;
110
- text-align: center;
111
- }
112
- .fhl-language-item:hover {
113
- background-color: rgba(0,0,0,0.1);
114
- }
47
+ .fhl-language-panel { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 15px; background-color: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); padding: 8px; display: grid; grid-template-columns: 1fr 1fr; gap: 4px; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; transform-origin: bottom center; }
48
+ .fhl-language-panel.visible { opacity: 1; visibility: visible; pointer-events: auto; }
49
+ .fhl-language-item { display: block; padding: 6px 12px; font-size: 14px; color: #333; text-decoration: none; border-radius: 8px; transition: background-color 0.2s ease; cursor: pointer; text-align: center; }
50
+ .fhl-language-item:hover { background-color: rgba(0,0,0,0.1); }