@@ -283,36 +328,56 @@
// Get modal elements
const modal = document.getElementById("loginModal");
const loginForm = document.getElementById("loginForm");
+ const registerForm = document.getElementById("registerForm");
const sendCodeBtn = document.getElementById("sendCodeBtn");
- const emailInput = document.getElementById("email");
let countdownTimer;
-// Get message modal elements
-const messageModal = document.getElementById("messageModal");
-const messageTitle = document.getElementById("messageTitle");
-const messageText = document.getElementById("messageText");
-const messageBtn = document.getElementById("messageBtn");
-const closeMessage = document.getElementsByClassName("close-message")[0];
+ // Get message modal elements
+ const messageModal = document.getElementById("messageModal");
+ const messageTitle = document.getElementById("messageTitle");
+ const messageText = document.getElementById("messageText");
+ const messageBtn = document.getElementById("messageBtn");
+ const closeMessage = document.getElementsByClassName("close-message")[0];
-// Show custom message modal
-function showMessage(title, text, type = 'info') {
- messageTitle.textContent = title;
- messageText.textContent = text;
-
- // Set style based on type
- messageText.className = type === 'success' ? 'success' : (type === 'error' ? 'error' : '');
-
- messageModal.style.display = "block";
-}
+ // Tab switching functionality
+ window.switchTab = function(tabName) {
+ // Hide all tab content
+ const tabContents = document.querySelectorAll('.tab-content');
+ tabContents.forEach(tab => tab.classList.remove('active'));
+
+ // Remove active state from all tab buttons
+ const tabButtons = document.querySelectorAll('.tab-button');
+ tabButtons.forEach(btn => btn.classList.remove('active'));
+
+ // Show corresponding tab content and set button active state
+ if (tabName === 'login') {
+ document.getElementById('loginTab').classList.add('active');
+ document.querySelector('.tab-button').classList.add('active');
+ } else if (tabName === 'register') {
+ document.getElementById('registerTab').classList.add('active');
+ document.querySelectorAll('.tab-button')[1].classList.add('active');
+ }
+ }
-// Close message modal
-function closeMessageModal() {
- messageModal.style.display = "none";
-}
+ // Show custom message modal
+ function showMessage(title, text, type = 'info') {
+ messageTitle.textContent = title;
+ messageText.textContent = text;
+
+ // Set style based on type
+ messageText.className = type === 'success' ? 'success' : (type === 'error' ? 'error' : '');
+
+ messageModal.style.display = "block";
+ }
-// Bind message modal close events
-closeMessage.onclick = closeMessageModal;
-messageBtn.onclick = closeMessageModal;
+ // Close message modal
+ function closeMessageModal() {
+ messageModal.style.display = "none";
+ }
+
+ // Bind message modal close events
+ closeMessage.onclick = closeMessageModal;
+ messageBtn.onclick = closeMessageModal;
// Add login modal close button
function closeLoginModal() {
@@ -346,20 +411,20 @@ messageBtn.onclick = closeMessageModal;
}
});
-// Check if token exists in local storage
-function getLocalToken() {
- return localStorage.getItem('ftyToken');
-}
+ // Check if token exists in local storage
+ function getLocalToken() {
+ return localStorage.getItem('ftyToken');
+ }
-// Save token to local storage
-function saveToken(token) {
- localStorage.setItem('ftyToken', token);
-}
+ // Save token to local storage
+ function saveToken(token) {
+ localStorage.setItem('ftyToken', token);
+ }
-// Clear token
-function clearToken() {
- localStorage.removeItem('ftyToken');
-}
+ // Clear token
+ function clearToken() {
+ localStorage.removeItem('ftyToken');
+ }
// Validate if token is valid
async function validateToken() {
@@ -453,130 +518,243 @@ function clearToken() {
}
}
-
-// Send verification code
-sendCodeBtn.onclick = function() {
- const contactValue = emailInput.value;
-
- if (!validateEmail(contactValue)) {
- showMessage('Input Error', 'Please enter a valid email address!', 'error');
- return;
- }
-
- // Disable button and start countdown
- startCountdown();
-
- // Send AJAX request to get verification code
- fetch(`${baseUrl}/fty/sendCode`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- type: "1", // Fixed as email type
- username: contactValue
- })
- })
- .then(response => response.json())
- .then(data => {
- if (data.success) {
- showMessage('Send Success', 'Verification code has been sent to your email!', 'success');
- } else {
- showMessage('Send Failed', data.msg || 'Failed to send verification code, please try again later!', 'error');
- resetCountdown();
+ // Send verification code
+ sendCodeBtn.onclick = function() {
+ const contactValue = document.getElementById('registerEmail').value;
+
+ if (!validateEmail(contactValue)) {
+ showMessage('Input Error', 'Please enter a valid email address!', 'error');
+ return;
}
- })
- .catch(error => {
- console.error('Error:', error);
- showMessage('Network Error', 'Failed to send verification code request, please try again later!', 'error');
- resetCountdown();
- });
-}
+
+ // Disable button and start countdown
+ startCountdown();
+
+ // Send AJAX request to get verification code
+ fetch(`${baseUrl}/fty/sendCode`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ type: "1", // Fixed as email type
+ username: contactValue
+ })
+ })
+ .then(response => response.json())
+ .then(data => {
+ console.log("Verification code send response", data);
+ if (data.code==2000) {
+ showMessage('Send Success', 'Verification code has been sent to your email!', 'success');
+ } else {
+ showMessage('Send Failed', data.msg || 'Failed to send verification code, please try again later!', 'error');
+ resetCountdown();
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ showMessage('Network Error', 'Failed to send verification code request, please try again later!', 'error');
+ resetCountdown();
+ });
+ }
-// Validate email format
-function validateEmail(email) {
- const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(String(email).toLowerCase());
-}
+ // Validate email format
+ function validateEmail(email) {
+ const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ return re.test(String(email).toLowerCase());
+ }
-// Start countdown
-function startCountdown() {
- let countdown = 60;
- sendCodeBtn.disabled = true;
- sendCodeBtn.textContent = `Retry after ${countdown}s`;
-
- countdownTimer = setInterval(() => {
- countdown--;
+ // Start countdown
+ function startCountdown() {
+ let countdown = 60;
+ sendCodeBtn.disabled = true;
sendCodeBtn.textContent = `Retry after ${countdown}s`;
- if (countdown <= 0) {
- resetCountdown();
+ countdownTimer = setInterval(() => {
+ countdown--;
+ sendCodeBtn.textContent = `Retry after ${countdown}s`;
+
+ if (countdown <= 0) {
+ resetCountdown();
+ }
+ }, 1000);
+ }
+
+ // Reset countdown
+ function resetCountdown() {
+ clearInterval(countdownTimer);
+ sendCodeBtn.disabled = false;
+ sendCodeBtn.textContent = 'Send Code';
+ }
+
+ // Handle login form submission
+ loginForm.onsubmit = function(e) {
+ console.log("Login form submitted");
+ e.preventDefault();
+ const email = document.getElementById("loginEmail").value;
+ const password = document.getElementById("loginPassword").value;
+
+ if (!validateEmail(email)) {
+ showMessage('Input Error', 'Please enter a valid email address!', 'error');
+ return;
}
- }, 1000);
-}
-
-// Reset countdown
-function resetCountdown() {
- clearInterval(countdownTimer);
- sendCodeBtn.disabled = false;
- sendCodeBtn.textContent = 'Send Code';
-}
-
-// Handle login form submission
-loginForm.onsubmit = function(e) {
- console.log("Form submitted");
- e.preventDefault();
- const verificationCode = document.getElementById("verificationCode").value;
- const contactValue = emailInput.value;
-
- // Send AJAX request
- fetch(`${baseUrl}/fty/login`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- type: "1", // Fixed as email type
- username: contactValue,
- code: verificationCode
+
+ if (!password) {
+ showMessage('Input Error', 'Please enter your password!', 'error');
+ return;
+ }
+
+ // Show loading state
+ const submitBtn = loginForm.querySelector('button[type="submit"]');
+ const originalText = submitBtn.textContent;
+ submitBtn.textContent = 'Logging in...';
+ submitBtn.disabled = true;
+
+ // Send AJAX request
+ fetch(`${baseUrl}/fty/userLogin`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ username: email,
+ type: 1,
+ password: password
+ })
})
- })
- .then(response => response.json())
- .then(data => {
- console.log("Login response", data);
- if (data.code==2000) {
- // Save token to local storage
- if (data.data.token) {
- saveToken(data.data.token);
- }
-
- showMessage('Login Success', 'Login successful!', 'success');
- // Close modal after successful login
- modal.style.display = "none";
- resetCountdown();
-
- // Check if there's a pending download link
- const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl');
- if (pendingDownloadUrl) {
- sessionStorage.removeItem('pendingDownloadUrl');
+ .then(response => response.json())
+ .then(data => {
+ console.log("Login response", data);
+ if (data.code==2000) {
+ // Save token to local storage
+ if (data.data.token) {
+ saveToken(data.data.token);
+ }
- // Delay a bit before redirect to let user see success message
- setTimeout(() => {
- if (downloadBtn) {
- downloadBtn.innerHTML = 'Downloading...';
- }
- window.location.href = pendingDownloadUrl;
- }, 1500);
+ showMessage('Login Success', 'Login successful!', 'success');
+ // Close modal after successful login
+ modal.style.display = "none";
+
+ // Check if there's a pending download link
+ const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl');
+ if (pendingDownloadUrl) {
+ sessionStorage.removeItem('pendingDownloadUrl');
+
+ // Delay a bit before redirect to let user see success message
+ setTimeout(() => {
+ const downloadBtn = document.getElementById('designDownloadBtn');
+ if (downloadBtn) {
+ downloadBtn.innerHTML = 'Downloading...';
+ }
+ window.location.href = pendingDownloadUrl;
+ }, 1500);
+ }
+ } else {
+ showMessage('Login Failed', data.msg || 'Login failed, please check your email and password!', 'error');
}
- } else {
- showMessage('Login Failed', data.msg || 'Login failed, please check email and verification code!', 'error');
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ showMessage('Network Error', 'Login request failed, please try again later!', 'error');
+ })
+ .finally(() => {
+ // Restore button state
+ submitBtn.textContent = originalText;
+ submitBtn.disabled = false;
+ });
+ }
+
+ // Handle register form submission
+ registerForm.onsubmit = function(e) {
+ console.log("Register form submitted");
+ e.preventDefault();
+ const email = document.getElementById("registerEmail").value;
+ const verificationCode = document.getElementById("verificationCode").value;
+ const password = document.getElementById("registerPassword").value;
+ const confirmPassword = document.getElementById("confirmPassword").value;
+
+ if (!validateEmail(email)) {
+ showMessage('Input Error', 'Please enter a valid email address!', 'error');
+ return;
}
- })
- .catch(error => {
- console.error('Error:', error);
- showMessage('Network Error', 'Login request failed, please try again later!', 'error');
- });
-}
+
+ if (!verificationCode) {
+ showMessage('Input Error', 'Please enter verification code!', 'error');
+ return;
+ }
+
+ if (!password) {
+ showMessage('Input Error', 'Please enter your password!', 'error');
+ return;
+ }
+
+ if (password !== confirmPassword) {
+ showMessage('Input Error', 'The two passwords entered are inconsistent!', 'error');
+ return;
+ }
+
+ // Show loading state
+ const submitBtn = registerForm.querySelector('button[type="submit"]');
+ const originalText = submitBtn.textContent;
+ submitBtn.textContent = 'Registering...';
+ submitBtn.disabled = true;
+
+ // Send AJAX request
+ fetch(`${baseUrl}/fty/userRegister`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ type: 1, // Fixed as email type
+ username: email,
+ code: verificationCode,
+ password: password,
+ confirm_password: confirmPassword
+ })
+ })
+ .then(response => response.json())
+ .then(data => {
+ console.log("Register response", data);
+ if (data.code==2000) {
+ // Save token to local storage
+ if (data.data.token) {
+ saveToken(data.data.token);
+ }
+
+ showMessage('Register Success', 'Registration successful!', 'success');
+ // Close modal after successful registration
+ modal.style.display = "none";
+ resetCountdown();
+
+ // Check if there's a pending download link
+ const pendingDownloadUrl = sessionStorage.getItem('pendingDownloadUrl');
+ if (pendingDownloadUrl) {
+ sessionStorage.removeItem('pendingDownloadUrl');
+
+ // Delay a bit before redirect to let user see success message
+ setTimeout(() => {
+ const downloadBtn = document.getElementById('designDownloadBtn');
+ if (downloadBtn) {
+ downloadBtn.innerHTML = 'Downloading...';
+ }
+ window.location.href = pendingDownloadUrl;
+ }, 1500);
+ }
+ } else {
+ showMessage('Register Failed', data.msg || 'Registration failed, please check your input!', 'error');
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ showMessage('Network Error', 'Registration request failed, please try again later!', 'error');
+ })
+ .finally(() => {
+ // Restore button state
+ submitBtn.textContent = originalText;
+ submitBtn.disabled = false;
+ });
+ }
// ESC key to close login modal
document.addEventListener('keydown', function(event) {
diff --git a/en/docs/login/index.md b/en/docs/login/index.md
new file mode 100644
index 0000000..f6963a5
--- /dev/null
+++ b/en/docs/login/index.md
@@ -0,0 +1,548 @@
+---
+title: Login & Register
+---
+
+# Login & Register
+
+
+
+
+
Phaten Cloud Login/Register
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/en/material/templates/404.html b/en/material/templates/404.html
new file mode 100644
index 0000000..ae765c4
--- /dev/null
+++ b/en/material/templates/404.html
@@ -0,0 +1,7 @@
+{#-
+ This file was automatically generated - do not edit
+-#}
+{% extends "main.html" %}
+{% block content %}
+