16 |
Link Shortener
17 |
Shorten your links, for free!
18 |
22 |
23 |
24 |
25 |
35 |
36 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/script.js:
--------------------------------------------------------------------------------
1 | /*
2 | (c) @xditya
3 | View the license: https://github.com/xditya/WebShortener/blob/master/LICENSE
4 | */
5 |
6 | const isValidUrl = (urlString) => {
7 | const urlPattern = new RegExp(
8 | "^(https?:\\/\\/)" + // validate protocol
9 | "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // validate domain name
10 | "((\\d{1,3}\\.){3}\\d{1,3}))" + // validate OR ip (v4) address
11 | "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // validate port and path
12 | "(\\?[;&a-z\\d%_.~+=-]*)?" + // validate query string
13 | "(\\#[-a-z\\d_]*)?$",
14 | "i"
15 | ); // validate fragment locator
16 | return !!urlPattern.test(urlString);
17 | };
18 |
19 | document
20 | .getElementById("shortenForm")
21 | .addEventListener("submit", async function (event) {
22 | event.preventDefault(); // Prevent form submission
23 |
24 | const longURL = document.getElementById("longURL").value;
25 |
26 | // Check if the input is empty
27 | if (longURL.trim() === "") {
28 | alert("Please enter a URL");
29 | return;
30 | }
31 | if (!isValidUrl(longURL)) {
32 | alert("Please enter a valid URL");
33 | return;
34 | }
35 | // Get the shortened link
36 | const res = await fetch("/shorten", {
37 | method: "POST",
38 | headers: {
39 | "Content-Type": "application/json",
40 | },
41 | body: JSON.stringify({ url: longURL }),
42 | });
43 | const data = await res.json();
44 | if (data.error) {
45 | alert(data.error);
46 | return;
47 | }
48 | if (data.hash) {
49 | shortenedLink = data.hash;
50 | }
51 |
52 | // Show the custom popup with the shortened link
53 | showPopup(window.location.href + shortenedLink);
54 |
55 | // Clear the input box after showing the popup
56 | document.getElementById("longURL").value = "";
57 | });
58 |
59 | function closePopup() {
60 | const popup = document.getElementById("customPopup");
61 | popup.style.display = "none";
62 | }
63 |
64 | function showPopup(shortenedLink) {
65 | const popup = document.getElementById("customPopup");
66 | const shortLinkElement = document.getElementById("shortLink");
67 | shortLinkElement.textContent = shortenedLink;
68 | shortLinkElement.href = shortenedLink; // Set the "href" attribute to the shortened link
69 | popup.style.display = "block";
70 | }
71 | function copyToClipboard() {
72 | const shortLinkElement = document.getElementById("shortLink");
73 | const shortenedLink = shortLinkElement.href;
74 |
75 | navigator.clipboard
76 | .writeText(shortenedLink)
77 | .then(function () {
78 | alert("Copied: " + shortenedLink);
79 | })
80 | .catch(function (err) {
81 | console.error("Failed to copy: ", err);
82 | });
83 | }
84 |
--------------------------------------------------------------------------------
/public/styles.css:
--------------------------------------------------------------------------------
1 | /*
2 | (c) @xditya
3 | View the license: https://github.com/xditya/WebShortener/blob/master/LICENSE
4 | */
5 |
6 | body {
7 | font-family: Arial, sans-serif;
8 | margin: 0;
9 | padding: 0;
10 | background-color: #000;
11 | /* Black background color */
12 | color: #fff;
13 | /* Light text color */
14 | display: flex;
15 | justify-content: center;
16 | align-items: center;
17 | height: 100vh;
18 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Cpath d='M1 3h2M2 2h1M1 1h1M1 2h1M1 0h1M2 1h1M1 3v1' stroke='%23fff' stroke-opacity='.2'/%3E%3C/svg%3E");
19 | /* Add diagonal crosshatch pattern to the background */
20 | background-repeat: repeat;
21 | }
22 |
23 | .container {
24 | width: 80%;
25 | max-width: 500px;
26 | padding: 20px;
27 | background-color: #222;
28 | /* Darker container background color */
29 | border-radius: 8px;
30 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
31 | }
32 |
33 | .footer {
34 | bottom: 0;
35 | text-align: center;
36 | position: absolute;
37 | }
38 |
39 | .footer a {
40 | color: #007bff;
41 | text-decoration: none;
42 | margin: 5px;
43 | }
44 |
45 | h1 {
46 | text-align: center;
47 | color: #fff;
48 | /* Light text color for headings */
49 | }
50 |
51 | p {
52 | text-align: center;
53 | color: #ccc;
54 | /* Light text color for paragraphs */
55 | }
56 |
57 | form {
58 | display: flex;
59 | flex-direction: column;
60 | }
61 |
62 | input[type="text"] {
63 | padding: 10px;
64 | font-size: 16px;
65 | border: 1px solid #666;
66 | /* Darker border color */
67 | border-radius: 4px;
68 | margin-bottom: 10px;
69 | background-color: #333;
70 | /* Darker input background color */
71 | color: #fff;
72 | /* Light text color for input text */
73 | }
74 |
75 | input[type="submit"] {
76 | padding: 12px 20px;
77 | font-size: 16px;
78 | background-color: #004080;
79 | /* Darker shade of blue */
80 | color: #fff;
81 | border: none;
82 | border-radius: 4px;
83 | cursor: pointer;
84 | }
85 |
86 | input[type="submit"]:hover {
87 | background-color: #00264d;
88 | /* Darker shade of blue on hover */
89 | }
90 |
91 | h2 {
92 | font-size: 20px;
93 | color: #fff;
94 | /* Light text color for headings */
95 | margin-top: 0;
96 | }
97 |
98 | /* Custom Popup Styles */
99 | .popup {
100 | display: none;
101 | position: fixed;
102 | top: 0;
103 | left: 0;
104 | width: 100%;
105 | height: 100%;
106 | background-color: rgba(0, 0, 0, 0.7);
107 | }
108 |
109 | .popup-content {
110 | position: absolute;
111 | top: 50%;
112 | left: 50%;
113 | transform: translate(-50%, -50%);
114 | background-color: #333;
115 | /* Darker popup background color */
116 | padding: 20px;
117 | border-radius: 8px;
118 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
119 | max-width: 80%;
120 | /* Limit the maximum width of the popup */
121 | text-align: center;
122 | /* Center the content within the popup */
123 | }
124 |
125 | #shortenedLink {
126 | color: #007bff;
127 | /* Light blue color for the URL link */
128 | }
129 |
130 | #shortenedLink a {
131 | color: #007bff;
132 | /* Light blue color for the URL link */
133 | text-decoration: none;
134 | }
135 |
136 | #shortenedLink a:hover {
137 | text-decoration: underline;
138 | /* Underline the URL link on hover */
139 | }
140 |
141 | #copyButton {
142 | padding: 10px 20px;
143 | font-size: 16px;
144 | background-color: #004080;
145 | /* Darker shade of blue */
146 | color: #fff;
147 | border: none;
148 | border-radius: 4px;
149 | cursor: pointer;
150 | margin-top: 10px;
151 | }
152 |
153 | #copyButton:hover {
154 | background-color: #00264d;
155 | /* Darker shade of blue on hover */
156 | }
157 |
158 | .close-button {
159 | position: absolute;
160 | top: 10px;
161 | right: 10px;
162 | font-size: 18px;
163 | cursor: pointer;
164 | color: #ccc;
165 | /* Light close button icon color */
166 | }
167 |
168 | .close-button:hover {
169 | color: #fff;
170 | /* Light close button icon color on hover */
171 | }
172 |
173 | /* Media Queries for Mobile */
174 | @media only screen and (max-width: 600px) {
175 | .container {
176 | width: 95%;
177 | }
178 | }
--------------------------------------------------------------------------------