Adityadn commited on
Commit
b094f43
·
verified ·
1 Parent(s): 32a99eb

Upload 8 files

Browse files
Files changed (9) hide show
  1. .gitattributes +1 -0
  2. bg.mp4 +3 -0
  3. data.js +106 -0
  4. index.html +74 -19
  5. list.json +7 -0
  6. manage.html +122 -0
  7. script.js +1167 -0
  8. style.css +141 -28
  9. templates.json +0 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ bg.mp4 filter=lfs diff=lfs merge=lfs -text
bg.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f5f0eb90cec141d5f9213d5fd10316361108f6350b63f3b31d7365e46327981b
3
+ size 691778
data.js ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const GITHUB_TOKEN = atob(
2
+ "Z2l0aHViX3BhdF8xMUFYNEtVTlkwMGFoclFZdjNBRzdLX1MwOW1aOFVDM2VRaTlMNW1mWDk2akdDSWFUaXRuaHJhbEkwSmR4TmRPc2k3Q1RPRUJKTXg4M3NQeExv"
3
+ );
4
+
5
+ const GITHUB_OWNER = "Adityadn64";
6
+ const GITHUB_REPO = "KARTU-UCAPAN-EID-1446H";
7
+ const URLS_DATAS_FILE_PATH = "d/urlsdatas.json";
8
+
9
+ async function getURLSDATAs() {
10
+ const res = await fetch(
11
+ `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${URLS_DATAS_FILE_PATH}`,
12
+ {
13
+ headers: {
14
+ Accept: "application/vnd.github+json",
15
+ Authorization: `Bearer ${GITHUB_TOKEN}`,
16
+ },
17
+ }
18
+ );
19
+
20
+ const fileData = await res.json();
21
+ let currentURLSDATAs = {};
22
+
23
+ try {
24
+ currentURLSDATAs = JSON.parse(
25
+ decodeURIComponent(escape(window.atob(fileData.content)))
26
+ );
27
+ } catch (e) {
28
+ console.error("Error parsing current urlsdatas; using empty object", e);
29
+ }
30
+
31
+ return [currentURLSDATAs, fileData];
32
+ }
33
+
34
+ async function getURLSDATA(urlsdata) {
35
+ return (await getURLSDATAs())[0][urlsdata];
36
+ }
37
+
38
+ async function setURLSDATAData(urlsdata, data) {
39
+ let [urlsdatasDB, fileData] = await getURLSDATAs();
40
+
41
+ const bata = urlsdatasDB[urlsdata];
42
+
43
+ const rbdY =
44
+ bata &&
45
+ bata.from &&
46
+ bata.target &&
47
+ bata.option &&
48
+ bata.message &&
49
+ bata.from === data.from &&
50
+ bata.target === data.target &&
51
+ bata.option === data.option &&
52
+ bata.message === (data.message || "");
53
+
54
+ const rbdN =
55
+ bata &&
56
+ bata.from &&
57
+ bata.target &&
58
+ bata.option &&
59
+ bata.message &&
60
+ bata.message.trim() !== "" &&
61
+ (bata.from !== data.from ||
62
+ bata.target !== data.target ||
63
+ bata.option !== data.option ||
64
+ bata.message === (data.message || ""));
65
+
66
+ if (bata && rbdN) return [false, urlsdatasDB];
67
+
68
+ if (!rbdY) {
69
+ urlsdatasDB[urlsdata] = data;
70
+ await updateURLSDATADataToGitHub(urlsdatasDB, fileData);
71
+ }
72
+
73
+ return [true, urlsdatasDB];
74
+ }
75
+
76
+ async function updateURLSDATADataToGitHub(urlsdataData, fileData) {
77
+ try {
78
+ if (!fileData) fileData = (await getURLSDATAs())[1];
79
+
80
+ const sha = fileData.sha;
81
+ const newContent = btoa(
82
+ unescape(encodeURIComponent(JSON.stringify(urlsdataData, null, 4)))
83
+ );
84
+
85
+ const updateRes = await fetch(
86
+ `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/contents/${URLS_DATAS_FILE_PATH}`,
87
+ {
88
+ method: "PUT",
89
+ headers: {
90
+ Accept: "application/vnd.github+json",
91
+ Authorization: `Bearer ${GITHUB_TOKEN}`,
92
+ },
93
+ body: JSON.stringify({
94
+ message: "Update urlsdata data",
95
+ content: newContent,
96
+ sha: sha,
97
+ }),
98
+ }
99
+ );
100
+
101
+ const result = await updateRes.json();
102
+ console.log("Update urlsdata data result:", result, urlsdataData);
103
+ } catch (err) {
104
+ console.error("Error updating urlsdata data to GitHub:", err);
105
+ }
106
+ }
index.html CHANGED
@@ -1,19 +1,74 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="id">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Kartu Ucapan Idul Fitri 1446 H</title>
7
+ <link
8
+ href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
9
+ rel="stylesheet"
10
+ />
11
+ <link
12
+ rel="stylesheet"
13
+ href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css"
14
+ />
15
+ <link href="https://unpkg.com/aos@next/dist/aos.css" rel="stylesheet" />
16
+ <link rel="stylesheet" href="style.css" />
17
+ </head>
18
+ <body>
19
+ <!-- Video Background -->
20
+ <video autoplay muted loop playsinline id="background-video">
21
+ <source src="bg.mp4" type="video/mp4" />
22
+ Your browser does not support the video tag.
23
+ </video>
24
+ <div class="container py-5">
25
+ <div
26
+ id="cardSection"
27
+ class="card text-center"
28
+ data-aos="fade-up"
29
+ style="display: none"
30
+ >
31
+ <div class="card-header">
32
+ <h4>Selamat Hari Raya Idul Fitri 1446 H</h4>
33
+ </div>
34
+ <div class="card-body">
35
+ <p class="card-text" id="cardMessage">
36
+ Sedang memuat ucapan...
37
+ </p>
38
+ </div>
39
+ <div class="card-footer text-muted">
40
+ <h5>Mohon maaf lahir dan batin</h5>
41
+ </div>
42
+ </div>
43
+ <div class="areaFooter" style="display: none">
44
+ <button class="tryErrorMessage btn btn-primary d-none m-3">
45
+ Ada yang salah. Coba lagi
46
+ </button>
47
+ <button class="tryOtherMessage btn btn-warning m-3">
48
+ Ganti pesan
49
+ </button>
50
+ <button class="waButton btn btn-success m-3">
51
+ Hubungi developer <i class="bi bi-whatsapp"></i>
52
+ </button>
53
+ <button class="urlButton btn btn-primary m-3">
54
+ Salin alamat halaman ini
55
+ <i class="bi bi-link-45deg"></i>
56
+ </button>
57
+ <button class="manageURL btn btn-danger m-3">
58
+ Buat untuk diri sendiri
59
+ </button>
60
+ </div>
61
+ </div>
62
+
63
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
64
+
65
+ <script src="https://unpkg.com/aos@next/dist/aos.js"></script>
66
+ <script>
67
+ AOS.init();
68
+ </script>
69
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
70
+
71
+ <script src="script.js"></script>
72
+ <script src="data.js"></script>
73
+ </body>
74
+ </html>
list.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [
2
+ "https://media.stickerswiki.app/stickerly_o1nn49_by_stickerly_official_bot/1825567.512.webp",
3
+ "https://i.pinimg.com/236x/db/75/9f/db759f85996381cfc69fc4878f6fa3c6.jpg",
4
+ "https://media.stickerswiki.app/pandagemoi4byofcsaraya/215937.512.webp",
5
+ "https://i.pinimg.com/474x/7d/08/e5/7d08e5de7c11a7356c7ee187f39cbc34.jpg",
6
+ "https://i.pinimg.com/736x/c1/78/ea/c178eae8b11823b36f4d76fc5f8a2a29.jpg"
7
+ ]
manage.html ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="id">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Generate URL</title>
7
+ <link
8
+ href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
9
+ rel="stylesheet"
10
+ />
11
+ <link
12
+ rel="stylesheet"
13
+ href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css"
14
+ />
15
+ <link href="https://unpkg.com/aos@next/dist/aos.css" rel="stylesheet" />
16
+ <link rel="stylesheet" href="style.css" />
17
+ </head>
18
+ <body>
19
+ <!-- Video Background -->
20
+ <video autoplay muted loop playsinline id="background-video">
21
+ <source src="bg.mp4" type="video/mp4" />
22
+ Your browser does not support the video tag.
23
+ </video>
24
+ <div class="container py-5">
25
+ <h2 class="text-center mb-4 text-white" data-aos="fade-down">
26
+ Generate URL Kartu Ucapan
27
+ </h2>
28
+ <div class="card p-4 shadow" data-aos="fade-up">
29
+ <form id="generateForm">
30
+ <div class="mb-3">
31
+ <label for="fromName" class="form-label"
32
+ >Nama Pengirim:</label
33
+ >
34
+ <input
35
+ type="text"
36
+ class="form-control"
37
+ id="fromName"
38
+ placeholder="Masukkan nama pengirim"
39
+ />
40
+ </div>
41
+ <div class="mb-3">
42
+ <label for="targetName" class="form-label"
43
+ >Nama Penerima:</label
44
+ >
45
+ <input
46
+ type="text"
47
+ class="form-control"
48
+ id="targetName"
49
+ placeholder="Masukkan nama penerima"
50
+ />
51
+ </div>
52
+ <div class="mb-3">
53
+ <label for="relationshipOption" class="form-label"
54
+ >Pilih Relasi (Hubungan):</label
55
+ >
56
+ <select class="form-select" id="relationshipOption">
57
+ <option value="0">Anak anda</option>
58
+ <option value="1">Keponakan anda</option>
59
+ <option value="2">Murid anda</option>
60
+ <option value="3">Saudaramu</option>
61
+ <option value="4">Sepupumu</option>
62
+ <option value="5">Sahabatmu</option>
63
+ <option value="6" selected>Temanmu</option>
64
+ <option value="7">Orang lain</option>
65
+ </select>
66
+ </div>
67
+ <div class="mb-3">
68
+ <p>Pilih antara dibuat AI atau Pesan Custom</p>
69
+ <!-- Switch dengan Bootstrap -->
70
+ <div
71
+ class="form-check form-switch d-flex align-items-center"
72
+ >
73
+ <input
74
+ class="form-check-input"
75
+ type="checkbox"
76
+ id="isCustomMessage"
77
+ />
78
+ <label
79
+ class="form-check-label ms-2"
80
+ for="isCustomMessage"
81
+ >Gunakan Pesan Kustom</label
82
+ >
83
+ </div>
84
+
85
+ <!-- Input pesan yang muncul saat switch aktif -->
86
+ <div id="inputMessage" class="mt-3 d-none">
87
+ <label for="message" class="form-label"
88
+ >Masukkan Pesan:</label
89
+ >
90
+ <input
91
+ type="text"
92
+ class="form-control"
93
+ id="message"
94
+ placeholder="Tulis pesan Anda..."
95
+ />
96
+ </div>
97
+ </div>
98
+ <button
99
+ type="button"
100
+ class="btn btn-primary w-100"
101
+ id="btnGU"
102
+ >
103
+ Generate URL
104
+ </button>
105
+ </form>
106
+ <div class="mt-3" id="generatedUrl" data-aos="fade-in"></div>
107
+ </div>
108
+ </div>
109
+
110
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
111
+
112
+ <script src="https://unpkg.com/aos@next/dist/aos.js"></script>
113
+ <script>
114
+ AOS.init();
115
+ </script>
116
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
117
+
118
+ <script src="script.js"></script>
119
+ <script src="animation.js"></script>
120
+ <script src="data.js"></script>
121
+ </body>
122
+ </html>
script.js ADDED
@@ -0,0 +1,1167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function getQueryParam(param) {
2
+ const urlParams = new URLSearchParams(window.location.search);
3
+ return urlParams.get(param);
4
+ }
5
+
6
+ const fN = "Aditya Dwi Nugraha";
7
+ const whatsappNumber = "6289668041554";
8
+
9
+ var fromName = fN;
10
+ let urlsdatasDB = {};
11
+ let urlsdataDB = {};
12
+ let urlDB = "";
13
+ let ucapanGabungan = "";
14
+ let renderedUcapanGabungan = "";
15
+
16
+ var inputConfigs = [
17
+ {
18
+ label: "Nama Anda:",
19
+ type: "text",
20
+ placeholder: "Masukkan nama anda",
21
+ id: "targetName",
22
+ value: "",
23
+ },
24
+ ];
25
+
26
+ var selectConfigs = [
27
+ {
28
+ label: `Pilih relasi (hubungan) antara Anda dan ${fromName}:`,
29
+ options: [
30
+ { value: "0", label: "Anak anda" },
31
+ { value: "1", label: "Keponakan anda" },
32
+ { value: "2", label: "Murid anda" },
33
+ { value: "3", label: "Saudaramu" },
34
+ { value: "4", label: "Sepupumu" },
35
+ { value: "5", label: "Sahabatmu" },
36
+ { value: "6", label: "Temanmu" },
37
+ { value: "7", label: "Orang lain" },
38
+ ],
39
+ default: "6",
40
+ id: "relationshipOption",
41
+ },
42
+ ];
43
+
44
+ const innerHTMLOnTopMessage = `<h2 class="mb-3">Masukkan Nama Penerima & Pilih Relasi</h2>`;
45
+
46
+ try {
47
+ const GEMINI_API_KEY = atob(
48
+ "QUl6YVN5QzUyNGNQREdEcWRZSnZkYmNtaUZ2N1Q2QzRnbE9JQXNR"
49
+ );
50
+ const MODEL_ID = "gemini-1.5-flash";
51
+ const GENERATE_CONTENT_API = "streamGenerateContent";
52
+
53
+ var noUcapan = "Ucapan tidak tersedia. Silakan coba lagi nanti.";
54
+
55
+ const tryErrorMessage = document.querySelectorAll(".tryErrorMessage");
56
+ const tryOtherMessage = document.querySelectorAll(".tryOtherMessage");
57
+
58
+ const relationshipMapping = {
59
+ 0: "Ayah/Ibu",
60
+ 1: "Pakde/Bude",
61
+ 2: "Guru",
62
+ 3: "Saudara",
63
+ 4: "Sepupu",
64
+ 5: "Sahabat",
65
+ 6: "Teman",
66
+ 7: "Tidak dikenal alias orang lain",
67
+ };
68
+
69
+ async function generateUcapan(
70
+ name,
71
+ option,
72
+ regenerate = false,
73
+ isChange = false
74
+ ) {
75
+ const targetName = name;
76
+ const relationship =
77
+ relationshipMapping[option.toString()] || relationshipMapping["6"];
78
+ // const language = [0, 1, 2].includes(parseInt(option))
79
+ // ? "Sopan"
80
+ // : `Gaul tapi tetap Sopan dan tidak berlebihan, karena INGAT! SAYA LAKI LAKI GENTLEMAN DAN PUNYA WIBAWA!. jangan pakai "lo" tapi "kamu"`;
81
+
82
+ const payload = {
83
+ contents: [
84
+ {
85
+ role: "user",
86
+ parts: [{ text: `Nama targetnya: ${targetName}` }],
87
+ },
88
+ ],
89
+ systemInstruction: {
90
+ parts: [
91
+ { text: "Sekarang tahun 1446H." },
92
+ {
93
+ text: 'Langsung mulai dengan "Assalamu\'alaikum Wr. Wb." alias salam lalu "Taqabbalallah wa minna ...." dan "Untuk ..." tanpa basa-basi.',
94
+ },
95
+ {
96
+ text: `Buat kartu ucapan Idul Fitri yang personal untuk ${targetName} berdasarkan jenis kelamin dan hubungan sebagai ${relationship}. Jika hubungan adalah "teman", jangan gunakan kata-kata romantis seperti "sayang", "ku cinta", atau istilah sejenis yang terkesan intim secara romantis.`,
97
+ },
98
+ {
99
+ text: `Sertakan kalimat "Kami sekeluarga ${fromName} mengucapkan..." jika hubungan bukan termasuk keluarga saya (Ayah/Ibu/Saudara). Jika termasuk keluarga saya maka beda lagi kalimatnya! Misal kalau untuk ibu: "Untuk ibuku yang tercinta..." atau kalau saudara: "Untuk ${targetName} yang ku cinta...".`,
100
+ },
101
+ {
102
+ text: "Setelah itu, lanjutkan ucapan dengan salam pembuka, doa, permohonan maaf, dan harapan yang hangat namun tidak berlebihan karena saya laki-laki yang gentleman punya wibawa.",
103
+ },
104
+ {
105
+ text: `Berikan emoji di setiap kalimat sebanyak-banyaknya untuk kesan asik dan santai.`,
106
+ },
107
+ {
108
+ text: "Jadikan bahasa manusia agak kaku agar tidak dikira robot.",
109
+ },
110
+ {
111
+ text: 'Ingat! Langsung mulai dengan "Assalamu\'alaikum Wr. Wb." alias salam lalu "Untuk ..." tanpa basa-basi.',
112
+ },
113
+ {
114
+ text: `INGAT KALAU KELUARGA SENDIRI TIDAK PAKAI KALIMAT "kami sekeluarga ${fromName}"!!!!!`,
115
+ },
116
+ ],
117
+ },
118
+ generationConfig: {
119
+ responseMimeType: "text/plain",
120
+ },
121
+ };
122
+
123
+ ucapanGabungan = "";
124
+ let isFDB = false;
125
+ let isCU = false;
126
+
127
+ urlsdatasDB = (await getURLSDATAs())[0];
128
+
129
+ localStorage.setItem("data", JSON.stringify(urlsdatasDB));
130
+
131
+ for (const [key, data] of Object.entries(urlsdatasDB)) {
132
+ if (
133
+ data.from === fromName &&
134
+ data.target === name &&
135
+ data.option === option &&
136
+ data.message &&
137
+ data.message !== noUcapan
138
+ ) {
139
+ ucapanGabungan = data.message;
140
+ urlDB = `${window.location.origin}?i=` + key;
141
+ isFDB = true;
142
+
143
+ localStorage.setItem("url", key);
144
+ break;
145
+ }
146
+ }
147
+
148
+ const logic =
149
+ (!isFDB && !regenerate && !isChange) ||
150
+ (isFDB && regenerate && !isChange) ||
151
+ (!isFDB && regenerate && isChange);
152
+
153
+ console.log([regenerate, isFDB, isChange], logic);
154
+
155
+ try {
156
+ if (logic) {
157
+ const response = await fetch(
158
+ `https://generativelanguage.googleapis.com/v1beta/models/${MODEL_ID}:${GENERATE_CONTENT_API}?key=${GEMINI_API_KEY}`,
159
+ {
160
+ method: "POST",
161
+ headers: { "Content-Type": "application/json" },
162
+ body: JSON.stringify(payload),
163
+ }
164
+ );
165
+
166
+ const data = await response.json();
167
+
168
+ ucapanGabungan = "";
169
+ isCU = true;
170
+
171
+ if (Array.isArray(data)) {
172
+ data.forEach((item) => {
173
+ if (
174
+ item &&
175
+ item.candidates &&
176
+ item.candidates[0] &&
177
+ item.candidates[0].content &&
178
+ item.candidates[0].content.parts &&
179
+ item.candidates[0].content.parts[0] &&
180
+ item.candidates[0].content.parts[0].text
181
+ ) {
182
+ ucapanGabungan +=
183
+ item.candidates[0].content.parts[0].text;
184
+ }
185
+ });
186
+ ucapanGabungan = ucapanGabungan.trim();
187
+ } else {
188
+ ucapanGabungan = noUcapan;
189
+ }
190
+ }
191
+
192
+ console.log("Ucapan:", ucapanGabungan);
193
+ } catch (error) {
194
+ ucapanGabungan = noUcapan;
195
+
196
+ console.error("Error:", error);
197
+ }
198
+
199
+ if (!ucapanGabungan.trim() || ucapanGabungan === noUcapan) {
200
+ tryErrorMessage.forEach((elm) => {
201
+ do {
202
+ elm.classList.remove("d-none");
203
+ } while (elm.classList.contains("d-none"));
204
+ });
205
+ } else {
206
+ tryOtherMessage.forEach((elm) => {
207
+ do {
208
+ elm.classList.remove("d-none");
209
+ } while (elm.classList.contains("d-none"));
210
+ });
211
+
212
+ const data = {
213
+ from: fromName,
214
+ target: name,
215
+ option: parseInt(option),
216
+ message: ucapanGabungan,
217
+ };
218
+
219
+ if (isCU) {
220
+ [urlDB, urlsdataDB] = await generateUrl(Object.values(data));
221
+
222
+ urlsdatasDB[urlDB] = urlsdataDB;
223
+
224
+ localStorage.setItem(
225
+ "url",
226
+ urlDB
227
+ .replace(window.location.origin, "")
228
+ .replace(urlDB.origin, "")
229
+ .replace("?i=", "")
230
+ );
231
+ function isCircular(obj, seen = new WeakSet()) {
232
+ if (typeof obj !== "object" || obj === null) return false;
233
+ if (seen.has(obj)) return true;
234
+ seen.add(obj);
235
+ return Object.values(obj).some((value) =>
236
+ isCircular(value, seen)
237
+ );
238
+ }
239
+
240
+ if (isCircular(urlsdataDB)) {
241
+ console.error("Data mengandung referensi circular!");
242
+ } else {
243
+ localStorage.setItem(urlDB, JSON.stringify(urlsdataDB));
244
+ }
245
+ }
246
+ }
247
+
248
+ return [ucapanGabungan, urlDB];
249
+ }
250
+
251
+ async function tampilkanKartu(
252
+ name,
253
+ option,
254
+ regenerate = false,
255
+ isChange = false
256
+ ) {
257
+ // document.getElementById("cardTitle").innerText = `Untuk ${name}`;
258
+ // document.getElementById("cardSection").style.display = "block";
259
+
260
+ console.log(name, option, regenerate);
261
+
262
+ [ucapanGabungan, urlDB] = await generateUcapan(
263
+ name,
264
+ option,
265
+ regenerate,
266
+ isChange
267
+ );
268
+
269
+ document.getElementById("cardMessage").innerHTML =
270
+ marked.parse(ucapanGabungan);
271
+
272
+ alert(`Akses halaman ini di: ${urlDB}`, false);
273
+
274
+ if (window.location.href.replace("/?", "?") !== urlDB) {
275
+ await alert(`Kamu akan diarahkan ke halaman ${urlDB}`);
276
+ await new Promise((res) => setTimeout(res, 1000));
277
+ window.location.href = urlDB;
278
+ }
279
+ }
280
+
281
+ async function getUser() {
282
+ let url = localStorage.getItem("url");
283
+ let data = localStorage.getItem("data");
284
+
285
+ if (data) {
286
+ try {
287
+ data = JSON.parse(data);
288
+ } catch (e) {
289
+ data = await getURLSDATAs();
290
+ }
291
+ } else {
292
+ data = await getURLSDATAs();
293
+ }
294
+
295
+ console.log(url, data);
296
+
297
+ return url && data ? data[url] || null : null;
298
+ }
299
+
300
+ async function setConfigs() {
301
+ urlsdataDB = await getUser();
302
+
303
+ console.log(urlsdataDB);
304
+
305
+ if (urlsdataDB) {
306
+ inputConfigs[0].value = urlsdataDB.target;
307
+ selectConfigs[0].label = `Pilih relasi (hubungan) antara Anda dan ${urlsdataDB.from}:`;
308
+ selectConfigs[0].default = urlsdataDB.option;
309
+ }
310
+ }
311
+
312
+ async function handleTryClick(target) {
313
+ target.classList.add("d-none");
314
+
315
+ await setConfigs();
316
+
317
+ const res = await multiPrompt(
318
+ inputConfigs,
319
+ selectConfigs,
320
+ innerHTMLOnTopMessage
321
+ );
322
+
323
+ if (!res.isCancel) {
324
+ userName = res["inputValues"]["targetName"];
325
+ userOption = res["selectValues"]["relationshipOption"];
326
+
327
+ let isC = false;
328
+
329
+ urlsdataDB = await getUser();
330
+
331
+ if (urlsdataDB) {
332
+ if (
333
+ (urlsdataDB.target === userName &&
334
+ urlsdataDB.option !== userOption) ||
335
+ (urlsdataDB.target !== userName &&
336
+ urlsdataDB.option === userOption)
337
+ ) {
338
+ isC = true;
339
+ }
340
+ } else {
341
+ isC = true;
342
+ }
343
+
344
+ await tampilkanKartu(userName, userOption, true, isC);
345
+ }
346
+
347
+ target.classList.remove("d-none");
348
+ }
349
+
350
+ document.addEventListener("click", async function (event) {
351
+ // Jika tombol yang diklik adalah .tryErrorMessage
352
+ if (event.target.classList.contains("tryErrorMessage")) {
353
+ await handleTryClick(event.target);
354
+ }
355
+
356
+ // Jika tombol yang diklik adalah .tryOtherMessage
357
+ if (event.target.classList.contains("tryOtherMessage")) {
358
+ await handleTryClick(event.target);
359
+ }
360
+
361
+ if (event.target.classList.contains("waButton")) {
362
+ window.open(`https://wa.me/${whatsappNumber}`, "_blank");
363
+ }
364
+
365
+ if (event.target.classList.contains("manageURL")) {
366
+ window.open(`manage.html`, "_blank");
367
+ }
368
+
369
+ if (event.target.classList.contains("urlButton")) {
370
+ navigator.clipboard.writeText(window.location.href).then(
371
+ () => alert("URL berhasil disalin", false),
372
+ () => alert("Gagal menyalin URL", false)
373
+ );
374
+ }
375
+ });
376
+
377
+ if (!window.location.href.includes("manage")) {
378
+ document.addEventListener("DOMContentLoaded", async () => {
379
+ const queryId = getQueryParam("i");
380
+ let isId = false;
381
+ let data = {};
382
+
383
+ if (queryId) {
384
+ data = await getURLSDATA(queryId);
385
+ console.log(data);
386
+
387
+ if (data) {
388
+ isId = true;
389
+ } else {
390
+ await alert("Id Kartu Tidak Ditemukan.");
391
+ }
392
+ }
393
+
394
+ urlsdataDB = await getUser();
395
+
396
+ const queryFromName = isId
397
+ ? data.from
398
+ : getQueryParam("f") ||
399
+ (urlsdataDB && urlsdataDB.from
400
+ ? urlsdataDB.from
401
+ : fromName || fN);
402
+ let queryTargetName = isId
403
+ ? data.target
404
+ : getQueryParam("t") ||
405
+ (urlsdataDB && urlsdataDB.target ? urlsdataDB.target : "");
406
+ let queryOption = isId
407
+ ? data.option
408
+ : getQueryParam("o") ||
409
+ (urlsdataDB && urlsdataDB.option ? urlsdataDB.option : "");
410
+
411
+ fromName = queryFromName;
412
+
413
+ console.log(queryFromName, queryTargetName, queryOption);
414
+
415
+ if (
416
+ queryFromName.trim() &&
417
+ queryTargetName.trim() &&
418
+ queryOption.trim()
419
+ ) {
420
+ [urlDB, urlsdatasDB] = await generateUrl([
421
+ queryFromName.trim(),
422
+ queryTargetName.trim(),
423
+ queryOption.trim(),
424
+ ]);
425
+
426
+ urlsdatasDB[urlDB] = urlsdataDB;
427
+
428
+ localStorage.setItem(
429
+ "url",
430
+ urlDB
431
+ .replace(window.location.origin, "")
432
+ .replace(urlDB.origin, "")
433
+ .replace("?i=", "")
434
+ );
435
+ localStorage.setItem(urlDB, JSON.stringify(urlsdataDB));
436
+ localStorage.setItem("data", JSON.stringify(urlsdatasDB));
437
+ }
438
+
439
+ await setConfigs();
440
+
441
+ let res3 = false;
442
+
443
+ do {
444
+ let res2 = false;
445
+
446
+ do {
447
+ let res1 = false;
448
+
449
+ if (!res3 === !res2 || (!res3 && res2)) {
450
+ do {
451
+ let res0 = false;
452
+
453
+ if (!res2 === !res1 || (!res2 && res1)) {
454
+ do {
455
+ // MultiPrompt 1: Konfirmasi awal
456
+ if (!res1 === !res0 || (!res1 && res0)) {
457
+ let res = await multiPrompt(
458
+ inputConfigs,
459
+ selectConfigs,
460
+ `<div class="child-container text-center">
461
+ <img class="img-fluid rounded-circle" src="https://media.stickerswiki.app/stickerly_o1nn49_by_stickerly_official_bot/1825567.512.webp">
462
+ <h2 class="mb-3">Apakah benar ini Anda?</h2></div>`,
463
+ false,
464
+ false,
465
+ isId
466
+ );
467
+
468
+ let isC = false;
469
+
470
+ if (!isId && !res.isCancel) {
471
+ queryTargetName =
472
+ res["inputValues"][
473
+ "targetName"
474
+ ];
475
+ queryOption =
476
+ res["selectValues"][
477
+ "relationshipOption"
478
+ ];
479
+
480
+ let isC = false;
481
+
482
+ urlsdataDB = await getUser();
483
+
484
+ if (urlsdataDB) {
485
+ if (
486
+ (urlsdataDB.target ===
487
+ userName &&
488
+ urlsdataDB.option !==
489
+ userOption) ||
490
+ (urlsdataDB.target !==
491
+ userName &&
492
+ urlsdataDB.option ===
493
+ userOption)
494
+ ) {
495
+ isC = true;
496
+ }
497
+ } else {
498
+ isC = true;
499
+ }
500
+
501
+ // [urlDB, urlsdatasDB] =
502
+ // await generateUrl([
503
+ // queryFromName.trim(),
504
+ // queryTargetName.trim(),
505
+ // queryOption.trim(),
506
+ // ]);
507
+
508
+ // urlsdatasDB[urlDB] = urlsdataDB;
509
+
510
+ localStorage.setItem(
511
+ "url",
512
+ urlDB
513
+ .replace(
514
+ window.location.origin,
515
+ ""
516
+ )
517
+ .replace(urlDB.origin, "")
518
+ .replace("?i=", "")
519
+ );
520
+ localStorage.setItem(
521
+ urlDB,
522
+ JSON.stringify(urlsdataDB)
523
+ );
524
+ localStorage.setItem(
525
+ "data",
526
+ JSON.stringify(urlsdatasDB)
527
+ );
528
+ }
529
+
530
+ alert("Tunggu sebentar...", false);
531
+
532
+ await tampilkanKartu(
533
+ queryTargetName,
534
+ queryOption,
535
+ isC,
536
+ isC
537
+ );
538
+
539
+ alert("Lanjut...", false);
540
+ }
541
+
542
+ // MultiPrompt 2: Konfirmasi lanjutan
543
+ res0 = (
544
+ await multiPrompt(
545
+ [],
546
+ [],
547
+ `<div class="child-container text-center">
548
+ <img class="img-fluid rounded-circle" src="https://i.pinimg.com/236x/db/75/9f/db759f85996381cfc69fc4878f6fa3c6.jpg">
549
+ <h2 class="mb-3">
550
+ "${queryTargetName}", apakah benar ini kamu?<br>
551
+ Kalau iya, yuk lanjut ada yang spesial buat kamu! 🎉✨
552
+ </h2>
553
+ </div>`.trim(),
554
+ true,
555
+ false,
556
+ true,
557
+ "Kembali"
558
+ )
559
+ ).isCancel;
560
+ } while (res0);
561
+ }
562
+
563
+ // MultiPrompt 3: Menampilkan nama penerima
564
+ res1 = (
565
+ await multiPrompt(
566
+ [],
567
+ [],
568
+ `<div class="child-container text-center">
569
+ <img class="img-fluid rounded-circle" src="https://media.stickerswiki.app/pandagemoi4byofcsaraya/215937.512.webp">
570
+ <h2 class="mb-3">
571
+ Klik Lanjut
572
+ </h2>
573
+ </div>`.trim(),
574
+ true,
575
+ false,
576
+ true,
577
+ "Kembali"
578
+ )
579
+ ).isCancel;
580
+ } while (res1);
581
+ }
582
+
583
+ // MultiPrompt 4: Pesan tambahan
584
+ res2 = (
585
+ await multiPrompt(
586
+ [],
587
+ [],
588
+ `<div class="child-container text-center">
589
+ <img class="img-fluid rounded-circle" src="https://i.pinimg.com/474x/7d/08/e5/7d08e5de7c11a7356c7ee187f39cbc34.jpg">
590
+ <div class="text-center">${
591
+ document.getElementById("cardSection").innerHTML
592
+ }</div></div>`,
593
+ true,
594
+ false,
595
+ true,
596
+ "Kembali",
597
+ true,
598
+ true,
599
+ document.getElementById("cardMessage").innerHTML ||
600
+ ucapanGabungan
601
+ )
602
+ ).isCancel;
603
+ } while (res2);
604
+
605
+ res3 = (
606
+ await multiPrompt(
607
+ [],
608
+ [],
609
+ `<div class="child-container text-center">
610
+ <img class="img-fluid rounded-circle" src="https://i.pinimg.com/736x/c1/78/ea/c178eae8b11823b36f4d76fc5f8a2a29.jpg">
611
+ <div class="text-center">${
612
+ document.querySelector(".areaFooter").innerHTML
613
+ }</div></div>`,
614
+ true,
615
+ false,
616
+ true,
617
+ "Kembali",
618
+ false
619
+ )
620
+ ).isCancel;
621
+ } while (res3);
622
+ });
623
+ }
624
+ } catch (e) {
625
+ console.error(e);
626
+ }
627
+
628
+ let counterAlert = 0;
629
+
630
+ async function alert(
631
+ message = "",
632
+ isPopUp = true,
633
+ isTime = false,
634
+ timeOut = 5,
635
+ messagesAfterTimeOut = [],
636
+ awaitResolve = 0
637
+ ) {
638
+ counterAlert++;
639
+
640
+ return new Promise((resolve) => {
641
+ try {
642
+ let modal;
643
+ let messageElem;
644
+ let timeOutElm;
645
+ let okBtn;
646
+ let intervalId;
647
+
648
+ if (isPopUp) {
649
+ modal = document.createElement("div");
650
+ modal.className = "modal";
651
+ modal.style.position = "fixed";
652
+ modal.style.top = "0";
653
+ modal.style.left = "0";
654
+ modal.style.width = "100%";
655
+ modal.style.height = "100%";
656
+ modal.style.backgroundColor = "rgba(0,0,0,0.5)";
657
+ modal.style.display = "flex";
658
+ modal.style.alignItems = "center";
659
+ modal.style.justifyContent = "center";
660
+ } else {
661
+ modal = document.createElement("div");
662
+ modal.className = "notification";
663
+ modal.style.position = "fixed";
664
+ modal.style.top = "5%";
665
+ modal.style.right = "2.5%";
666
+ modal.style.padding = "10px 20px";
667
+ modal.style.borderRadius = "5px";
668
+ modal.style.zIndex = "1000000000";
669
+ modal.setAttribute("data-aos", "fade-left");
670
+ }
671
+
672
+ const modalContent = document.createElement("div");
673
+ modalContent.className = `modal-content d-flex align-items-center ${
674
+ isPopUp
675
+ ? "bg-light"
676
+ : counterAlert % 2 === 0
677
+ ? "bg-success"
678
+ : "bg-primary"
679
+ } p-3 ${isPopUp ? "" : "text-white"}`;
680
+ modalContent.style.width = isPopUp ? "75%" : "100%";
681
+ modalContent.style.height = isPopUp ? "" : "100%";
682
+ modalContent.style.borderRadius = "5px";
683
+ modalContent.style.boxShadow = isPopUp
684
+ ? "0 2px 10px rgba(0,0,0,0.1)"
685
+ : "";
686
+
687
+ messageElem = document.createElement("p");
688
+ messageElem.innerHTML =
689
+ (!isPopUp ? `<i class="bi bi-bell-fill m-2"></i>` : ``) +
690
+ message;
691
+
692
+ timeOutElm = document.createElement("p");
693
+
694
+ okBtn = document.createElement("button");
695
+ okBtn.className = `btn ${
696
+ counterAlert % 2 === 0 ? "btn-primary" : "btn-warning"
697
+ } btn-lg`;
698
+ okBtn.textContent = "OK";
699
+ okBtn.style.minWidth = "80px";
700
+ okBtn.style.display = isTime ? "none" : "block";
701
+ okBtn.style.marginTop = "10px";
702
+
703
+ modalContent.appendChild(messageElem);
704
+
705
+ if (isTime) {
706
+ modalContent.appendChild(timeOutElm);
707
+ }
708
+
709
+ if (isPopUp) {
710
+ const btnContainer = document.createElement("div");
711
+ btnContainer.style.marginTop = "20px";
712
+ btnContainer.appendChild(okBtn);
713
+ modalContent.appendChild(btnContainer);
714
+ }
715
+
716
+ modal.appendChild(modalContent);
717
+ document.body.appendChild(modal);
718
+
719
+ okBtn.addEventListener("click", function () {
720
+ if (intervalId) clearInterval(intervalId);
721
+ if (document.body.contains(modal)) {
722
+ document.body.removeChild(modal);
723
+ }
724
+ resolve();
725
+ });
726
+
727
+ if (!isPopUp) {
728
+ intervalId = setInterval(async () => {
729
+ timeOut--;
730
+ console.log(timeOut);
731
+ if (messagesAfterTimeOut.length === 0)
732
+ timeOutElm.textContent = timeOut;
733
+ if (messagesAfterTimeOut.length > 0) {
734
+ messagesAfterTimeOut.forEach((mes) => {
735
+ if (mes.timeOut >= timeOut) {
736
+ modalContent.className =
737
+ "modal-content d-flex align-items-center bg-warning p-3";
738
+ messageElem.textContent = mes.message;
739
+ timeOutElm.textContent = timeOut;
740
+ }
741
+ });
742
+ }
743
+
744
+ if (timeOut <= 0) {
745
+ await new Promise((res) =>
746
+ setTimeout(res, awaitResolve)
747
+ );
748
+ if (document.body.contains(modal)) {
749
+ document.body.removeChild(modal);
750
+ }
751
+ clearInterval(intervalId);
752
+ resolve();
753
+ }
754
+ }, 1000);
755
+
756
+ setTimeout(() => {
757
+ if (document.body.contains(modal)) {
758
+ document.body.removeChild(modal);
759
+ }
760
+ resolve();
761
+ }, timeOut * 1000);
762
+ }
763
+ } catch (e) {
764
+ console.error(e);
765
+ }
766
+ });
767
+ }
768
+
769
+ async function multiPrompt(
770
+ inputConfigs = [
771
+ {
772
+ label: "Nama:",
773
+ type: "text",
774
+ placeholder: "Masukkan nama Anda",
775
+ id: "name",
776
+ value: "",
777
+ },
778
+ ],
779
+ selectConfigs = [
780
+ {
781
+ label: "Pilih Gender:",
782
+ options: [
783
+ { value: "L", label: "Laki-laki" },
784
+ { value: "P", label: "Perempuan" },
785
+ ],
786
+ default: "L",
787
+ id: "gender",
788
+ },
789
+ ],
790
+ innerHTMLOnTopMessage = "",
791
+ withCancelButton = true,
792
+ isDOM = false,
793
+ isDisabledAll = false,
794
+ cancelText = "",
795
+ withNextButton = true,
796
+ runFunc = false,
797
+ originalText = ""
798
+ ) {
799
+ console.log(ucapanGabungan, originalText, "AAAA");
800
+ return new Promise((resolve) => {
801
+ const modal = document.createElement("div");
802
+ modal.className = "modal";
803
+ Object.assign(modal.style, {
804
+ position: "fixed",
805
+ top: "0",
806
+ left: "0",
807
+ width: "100%",
808
+ height: "100%",
809
+ backgroundColor: "rgba(0,0,0,0.5)",
810
+ display: "flex",
811
+ alignItems: "center",
812
+ justifyContent: "center",
813
+ });
814
+
815
+ const modalContent = document.createElement("div");
816
+ modalContent.className = "modal-content";
817
+ Object.assign(modalContent.style, {
818
+ width: "75%",
819
+ background: "#fff",
820
+ padding: "20px",
821
+ borderRadius: "5px",
822
+ boxShadow: "0 2px 10px rgba(0,0,0,0.1)",
823
+ });
824
+
825
+ const okBtn = document.createElement("button");
826
+ const okBtnClassName = "btn btn-success btn-lg";
827
+ const okBtnTextContent = "Cari";
828
+
829
+ okBtn.className = isDOM
830
+ ? okBtnClassName.replace("success", "warning")
831
+ : okBtnClassName;
832
+ okBtn.textContent = isDisabledAll
833
+ ? "Lanjut"
834
+ : isDOM
835
+ ? okBtnTextContent
836
+ : "Ganti pesan";
837
+ okBtn.style.marginRight = "10px";
838
+ okBtn.style.display = withNextButton ? "" : "none";
839
+
840
+ const cancelBtn = document.createElement("button");
841
+ cancelBtn.className =
842
+ "btn btn-danger btn-lg" + (withCancelButton ? "" : " d-none");
843
+ cancelBtn.textContent = cancelText || "Batal";
844
+
845
+ const innerHTMLOnTopMessageContent = document.createElement("div");
846
+ innerHTMLOnTopMessageContent.innerHTML = innerHTMLOnTopMessage;
847
+
848
+ const form = document.createElement("form");
849
+
850
+ const inputElements = {};
851
+ const selectElements = {};
852
+
853
+ function changeOKBTN(isChange) {
854
+ okBtn.textContent = isDisabledAll
855
+ ? "Lanjut"
856
+ : isDOM
857
+ ? okBtnTextContent
858
+ : isChange === false
859
+ ? "Ganti pesan"
860
+ : "Ganti data";
861
+ okBtn.className = isDOM
862
+ ? okBtnClassName.replace("success", "warning")
863
+ : isChange === false
864
+ ? okBtnClassName
865
+ : okBtnClassName.replace("success", "primary");
866
+ }
867
+
868
+ inputConfigs.forEach((config) => {
869
+ const labelElem = document.createElement("label");
870
+ labelElem.textContent = config.label;
871
+ Object.assign(labelElem.style, {
872
+ display: "block",
873
+ marginTop: "10px",
874
+ });
875
+ form.appendChild(labelElem);
876
+
877
+ const input = document.createElement("input");
878
+ Object.assign(input, {
879
+ type: config.type || "text",
880
+ placeholder: config.placeholder || "",
881
+ required: true,
882
+ id: config.id,
883
+ });
884
+ Object.assign(input.style, {
885
+ width: "100%",
886
+ marginTop: "5px",
887
+ });
888
+ input.className = "form-control form-control-lg";
889
+ input.value = config.value;
890
+ inputElements[config.id] = input;
891
+ form.appendChild(input);
892
+
893
+ if (isDisabledAll) input.disabled = true;
894
+
895
+ input.addEventListener("change", () => {
896
+ changeOKBTN(inputElements[config.id].value !== config.value);
897
+ });
898
+ });
899
+
900
+ selectConfigs.forEach((config) => {
901
+ const labelElem = document.createElement("label");
902
+ labelElem.textContent = config.label;
903
+ Object.assign(labelElem.style, {
904
+ display: "block",
905
+ marginTop: "10px",
906
+ });
907
+ form.appendChild(labelElem);
908
+
909
+ const selectElem = document.createElement("select");
910
+ Object.assign(selectElem, {
911
+ required: true,
912
+ id: config.id,
913
+ });
914
+ Object.assign(selectElem.style, {
915
+ width: "100%",
916
+ marginTop: "5px",
917
+ });
918
+ selectElem.className = "form-select form-select-lg";
919
+
920
+ config.options.forEach((opt) => {
921
+ const optionElem = document.createElement("option");
922
+ optionElem.value = opt.value;
923
+ optionElem.textContent = opt.label;
924
+ if (config.default === opt.value) optionElem.selected = true;
925
+ selectElem.appendChild(optionElem);
926
+ });
927
+
928
+ selectElements[config.id] = selectElem;
929
+ form.appendChild(selectElem);
930
+
931
+ if (isDisabledAll) selectElem.disabled = true;
932
+
933
+ selectElem.addEventListener("change", () => {
934
+ changeOKBTN(selectElements[config.id].value !== config.default);
935
+ });
936
+ });
937
+
938
+ const btnContainer = document.createElement("div");
939
+ Object.assign(btnContainer.style, {
940
+ marginTop: "20px",
941
+ textAlign: "right",
942
+ });
943
+
944
+ btnContainer.appendChild(okBtn);
945
+ btnContainer.appendChild(cancelBtn);
946
+ form.appendChild(btnContainer);
947
+
948
+ modalContent.appendChild(innerHTMLOnTopMessageContent);
949
+ modalContent.appendChild(form);
950
+ modal.appendChild(modalContent);
951
+ document.body.appendChild(modal);
952
+
953
+ console.log(runFunc);
954
+
955
+ function initTypewriter() {
956
+ async function typeWriterHTML(element, html, speed = 50) {
957
+ let currentLength = renderedUcapanGabungan.length;
958
+ for (let i = currentLength; i < html.length; i++) {
959
+ renderedUcapanGabungan += html.charAt(i);
960
+ element.innerHTML = renderedUcapanGabungan;
961
+ await new Promise((resolve) => setTimeout(resolve, speed));
962
+
963
+ okBtn.disabled = true;
964
+ cancelBtn.disabled = true;
965
+ }
966
+
967
+ okBtn.disabled = false;
968
+ cancelBtn.disabled = false;
969
+ }
970
+
971
+ const cardMessagess = document.querySelectorAll(".card-body");
972
+ cardMessagess.forEach((cardMessages, index) => {
973
+ if (index !== 0) {
974
+ typeWriterHTML(
975
+ cardMessages,
976
+ marked.parse(originalText),
977
+ 25
978
+ );
979
+ }
980
+ });
981
+ }
982
+
983
+ if (document.readyState === "loading") {
984
+ document.addEventListener("DOMContentLoaded", initTypewriter);
985
+ } else {
986
+ initTypewriter();
987
+ }
988
+
989
+ form.addEventListener("submit", function (e) {
990
+ e.preventDefault();
991
+
992
+ let isValid = true;
993
+ const inputValues = {};
994
+ const selectValues = {};
995
+
996
+ Object.entries(inputElements).forEach(([id, elem]) => {
997
+ const value = elem.value.trim();
998
+ inputValues[id] = value;
999
+ if (value.length === 0) {
1000
+ elem.style.border = "1px solid red";
1001
+ isValid = false;
1002
+ } else {
1003
+ elem.style.border = "";
1004
+ }
1005
+ });
1006
+
1007
+ Object.entries(selectElements).forEach(([id, elem]) => {
1008
+ const value = elem.value;
1009
+ selectValues[id] = value;
1010
+ if (!value) {
1011
+ elem.style.border = "1px solid red";
1012
+ isValid = false;
1013
+ } else {
1014
+ elem.style.border = "";
1015
+ }
1016
+ });
1017
+
1018
+ if (isValid) {
1019
+ document.body.removeChild(modal);
1020
+ console.log(inputValues, selectValues);
1021
+ resolve({ inputValues, selectValues, isCancel: false });
1022
+ }
1023
+ });
1024
+
1025
+ okBtn.addEventListener("click", () => {
1026
+ form.dispatchEvent(new Event("submit", { cancelable: true }));
1027
+ });
1028
+
1029
+ cancelBtn.addEventListener("click", () => {
1030
+ document.body.removeChild(modal);
1031
+ resolve({
1032
+ inputValues: null,
1033
+ selectValues: null,
1034
+ isCancel: true,
1035
+ });
1036
+ });
1037
+ });
1038
+ }
1039
+
1040
+ let isCustomMessage = false;
1041
+
1042
+ try {
1043
+ document
1044
+ .getElementById("btnGU")
1045
+ .addEventListener("click", async function () {
1046
+ const fromName = document.getElementById("fromName").value.trim();
1047
+ const targetName = document
1048
+ .getElementById("targetName")
1049
+ .value.trim();
1050
+ const option = parseInt(
1051
+ document.getElementById("relationshipOption").value.trim()
1052
+ );
1053
+ const message = document.getElementById("message").value.trim();
1054
+
1055
+ const generatedUrl = (
1056
+ await generateUrl([
1057
+ fromName,
1058
+ targetName,
1059
+ option,
1060
+ isCustomMessage ? message : "",
1061
+ ])
1062
+ )[0];
1063
+
1064
+ document.getElementById(
1065
+ "generatedUrl"
1066
+ ).innerHTML = `<div class='alert alert-success'>
1067
+ <strong>URL Generated:</strong> <a href="${generatedUrl}" target="_blank">${generatedUrl}</a>
1068
+ </div>`;
1069
+ });
1070
+
1071
+ document
1072
+ .getElementById("isCustomMessage")
1073
+ .addEventListener("change", function () {
1074
+ const inputMessage = document.getElementById("inputMessage");
1075
+ if (this.checked) {
1076
+ inputMessage.setAttribute("class", "mt-3");
1077
+ isCustomMessage = true;
1078
+ } else {
1079
+ inputMessage.setAttribute("class", "mt-3 d-none");
1080
+ isCustomMessage = false;
1081
+ }
1082
+ });
1083
+ } catch (error) {}
1084
+
1085
+ async function generateUrl([fromName, targetName, option, message = ""]) {
1086
+ let i = 0;
1087
+ let generatedUrl = "";
1088
+
1089
+ while (true) {
1090
+ let queryUrl = "";
1091
+
1092
+ if (!fromName || !targetName) {
1093
+ alert("Mohon isi semua field sebelum generate URL", false);
1094
+ return;
1095
+ }
1096
+
1097
+ const fts = [fromName, targetName];
1098
+
1099
+ fts.forEach((ft, indexs) => {
1100
+ let finalFN = "";
1101
+
1102
+ let fNS = ft.split(" ");
1103
+ let fNSJ = fNS.join("");
1104
+
1105
+ fNS.forEach((word, index) => {
1106
+ let wl = Math.round(word.length / (i + 2));
1107
+ finalFN +=
1108
+ (indexs === 0 && index === 0) ||
1109
+ (indexs === 1 && index === fNS.length - 1)
1110
+ ? (word[i] || "x") +
1111
+ (fNSJ[wl] || "y") +
1112
+ (word[word.length - (i + 1)] || "z")
1113
+ : "";
1114
+ });
1115
+
1116
+ queryUrl += finalFN + (indexs === 0 ? "X" : "Y");
1117
+ });
1118
+
1119
+ const char = "abcdefghijklmnopqrstuvwxyz";
1120
+
1121
+ queryUrl += char[option + i] || "Z";
1122
+
1123
+ let data = await getURLSDATA(queryUrl);
1124
+
1125
+ if (!data) {
1126
+ data = {
1127
+ from: fromName,
1128
+ target: targetName,
1129
+ option: option.toString(),
1130
+ message: message,
1131
+ };
1132
+ }
1133
+
1134
+ console.log(queryUrl, data);
1135
+
1136
+ let isSuccess = false;
1137
+
1138
+ [isSuccess, urlsdatasDB] = await setURLSDATAData(queryUrl, data);
1139
+
1140
+ i++;
1141
+
1142
+ if (isSuccess) {
1143
+ generatedUrl = `${window.location.origin}?i=` + queryUrl;
1144
+ break;
1145
+ }
1146
+ }
1147
+
1148
+ return [generatedUrl, urlsdatasDB];
1149
+ }
1150
+
1151
+ try {
1152
+ function addStars(count) {
1153
+ for (let i = 0; i < count; i++) {
1154
+ const star = document.createElement("div");
1155
+ star.className = "star";
1156
+ // Atur posisi acak
1157
+ star.style.top = Math.random() * 100 + "%";
1158
+ star.style.left = Math.random() * 100 + "%";
1159
+ // Atur durasi animasi antara 2s hingga 5s
1160
+ star.style.animationDuration = 2 + Math.random() * 3 + "s";
1161
+ // Atur delay animasi antara 0s hingga 3s
1162
+ star.style.animationDelay = Math.random() * 3 + "s";
1163
+ document.body.appendChild(star);
1164
+ }
1165
+ }
1166
+ addStars(100);
1167
+ } catch {}
style.css CHANGED
@@ -1,28 +1,141 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
- }
5
-
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
- }
10
-
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
- }
17
-
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
- }
25
-
26
- .card p:last-child {
27
- margin-bottom: 0;
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Global Styles */
2
+ html,
3
+ body {
4
+ margin: 0;
5
+ padding: 0;
6
+ width: 100%;
7
+ height: 100%;
8
+ overflow-x: hidden;
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ body {
13
+ /* Background gradient hijau ketupat */
14
+ background: linear-gradient(135deg, #228b22, #32cd32);
15
+ font-family: "Arial", sans-serif;
16
+ font-size: 1rem;
17
+ }
18
+
19
+ /* Styling untuk kartu ucapan yang sudah ada */
20
+ .card {
21
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
22
+ border: none;
23
+ }
24
+
25
+ /* --- Animasi Bintang --- */
26
+ @keyframes twinkle {
27
+ 0%,
28
+ 100% {
29
+ opacity: 0.8;
30
+ transform: scale(1);
31
+ }
32
+ 50% {
33
+ opacity: 1;
34
+ transform: scale(1.2);
35
+ }
36
+ }
37
+
38
+ /* Style untuk bintang */
39
+ .star {
40
+ position: absolute;
41
+ background: #fff;
42
+ border-radius: 50%;
43
+ width: 2px;
44
+ height: 2px;
45
+ animation: twinkle 2s infinite ease-in-out;
46
+ }
47
+
48
+ /* --- Elemen Ketupat --- */
49
+ .eid-ketupat {
50
+ position: absolute;
51
+ z-index: 2;
52
+ width: 80px;
53
+ height: 80px;
54
+ background: #32cd32; /* Warna hijau */
55
+ /* Bentuk diamond menggunakan clip-path */
56
+ clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
57
+ border: 2px solid #006400; /* Warna dark green */
58
+ border-radius: 5px;
59
+ animation: swing 3s ease-in-out infinite;
60
+ }
61
+
62
+ /* --- Elemen Lentera --- */
63
+ .eid-lantern {
64
+ position: absolute;
65
+ z-index: 2;
66
+ width: 50px;
67
+ height: 70px;
68
+ background: #ffcc00;
69
+ border: 2px solid #ff9900;
70
+ border-radius: 10px;
71
+ box-shadow: 0 0 10px rgba(255, 204, 0, 0.9);
72
+ animation: swing 2.5s ease-in-out infinite, blink 1.5s ease-in-out infinite;
73
+ }
74
+
75
+ /* Keyframes untuk efek ayunan (swing) */
76
+ @keyframes swing {
77
+ 0% {
78
+ transform: translateY(0) rotate(0deg);
79
+ }
80
+ 25% {
81
+ transform: translateY(-5px) rotate(5deg);
82
+ }
83
+ 50% {
84
+ transform: translateY(0) rotate(0deg);
85
+ }
86
+ 75% {
87
+ transform: translateY(5px) rotate(-5deg);
88
+ }
89
+ 100% {
90
+ transform: translateY(0) rotate(0deg);
91
+ }
92
+ }
93
+
94
+ /* Keyframes untuk efek kedip (blink) pada lentera */
95
+ @keyframes blink {
96
+ 0%,
97
+ 100% {
98
+ opacity: 1;
99
+ }
100
+ 50% {
101
+ opacity: 0.5;
102
+ }
103
+ }
104
+
105
+ /* Style untuk Three.js canvas (jika ada) */
106
+ #threeCanvas,
107
+ #tunnelCanvas {
108
+ position: fixed;
109
+ top: 0;
110
+ left: 0;
111
+ width: 100vw;
112
+ height: 100vh;
113
+ z-index: -1;
114
+ display: block;
115
+ }
116
+
117
+ /* Video Background */
118
+ #background-video {
119
+ position: fixed;
120
+ right: 0;
121
+ bottom: 0;
122
+ min-width: 100%;
123
+ min-height: 100%;
124
+ width: auto;
125
+ height: auto;
126
+ z-index: -1;
127
+ object-fit: cover;
128
+ filter: opacity(0.99);
129
+ }
130
+
131
+ .child-container {
132
+ text-align: center;
133
+ margin: 0 auto;
134
+ }
135
+
136
+ .img-fluid {
137
+ margin: 5px;
138
+ width: 250px;
139
+ height: auto;
140
+ object-fit: cover;
141
+ }
templates.json ADDED
The diff for this file is too large to render. See raw diff