diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 177d231..018e0a7 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -12,13 +12,22 @@
您的专属临时邮箱,无限且私密
输入任何@shenjianl.cn地址,立即在此查看收件箱。
@@ -92,6 +101,7 @@ export default {
const selectedMessage = ref(null);
const loading = ref(false);
const showModal = ref(false);
+ const copyStatus = ref('idle'); // 'idle' | 'copied'
// !!! 生产环境��要提示 !!!
// 请务必将下面的 'yourdomain.com' 替换为您的真实域名
const domain = 'shenjianl.cn';
@@ -128,10 +138,104 @@ export default {
};
const generateRandomEmail = () => {
- const randomPart = Math.random().toString(36).substring(2, 10);
- recipient.value = `${randomPart}@${domain}`;
+ const names = [
+ 'alex', 'casey', 'morgan', 'jordan', 'taylor', 'jamie', 'ryan', 'drew', 'jesse', 'pat',
+ 'chris', 'dylan', 'aaron', 'blake', 'cameron', 'devon', 'elliot', 'finn', 'gray', 'harper',
+ 'kai', 'logan', 'max', 'noah', 'owen', 'quinn', 'riley', 'rowan', 'sage', 'skyler'
+ ];
+ const places = [
+ 'tokyo', 'paris', 'london', 'cairo', 'sydney', 'rio', 'moscow', 'rome', 'nile', 'everest',
+ 'sahara', 'amazon', 'gobi', 'andes', 'pacific', 'kyoto', 'berlin', 'dubai', 'seoul', 'milan',
+ 'vienna', 'prague', 'athens', 'lisbon', 'oslo', 'helsinki', 'zürich', 'geneva', 'brussels', 'amsterdam'
+ ];
+ const concepts = [
+ 'apollo', 'artemis', 'athena', 'zeus', 'thor', 'loki', 'odin', 'freya', 'phoenix', 'dragon',
+ 'griffin', 'sphinx', 'pyramid', 'colossus', 'acropolis', 'obelisk', 'pagoda', 'castle', 'cyberspace', 'matrix',
+ 'protocol', 'algorithm', 'pixel', 'vector', 'photon', 'quark', 'nova', 'pulsar', 'saga', 'voyage',
+ 'enigma', 'oracle', 'cipher', 'vortex', 'helix', 'axiom', 'zenith', 'epoch', 'nexus', 'trinity'
+ ];
+
+ const allLists = [names, places, concepts];
+ const getRandomItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
+
+ // Randomly pick 2 lists to combine words from
+ const listA = getRandomItem(allLists);
+ const listB = getRandomItem(allLists);
+
+ const word1 = getRandomItem(listA);
+ const word2 = getRandomItem(listB);
+
+ const number = Math.floor(Math.random() * 9000) + 1000; // Random 4-digit number
+
+ // Randomly choose a separator
+ const separators = ['.', '-', '_', ''];
+ const separator = getRandomItem(separators);
+
+ let prefix;
+ if (word1 === word2) {
+ // Avoids "alex.alex1234" if the same list and word are picked
+ prefix = `${word1}${number}`;
+ } else {
+ prefix = `${word1}${separator}${word2}${number}`;
+ }
+
+ recipient.value = `${prefix}@${domain}`;
};
+ const copyEmail = () => {
+ if (!recipient.value) return;
+
+ const textToCopy = recipient.value;
+
+ // Modern browsers in secure contexts
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard.writeText(textToCopy).then(() => {
+ showCopySuccess();
+ }).catch(err => {
+ console.error('Modern copy failed: ', err);
+ fallbackCopy(textToCopy); // Try fallback on error
+ });
+ } else {
+ // Fallback for older browsers or insecure contexts
+ fallbackCopy(textToCopy);
+ }
+ };
+
+ const fallbackCopy = (text) => {
+ const textArea = document.createElement('textarea');
+ textArea.value = text;
+
+ // Make the textarea out of sight
+ textArea.style.position = 'fixed';
+ textArea.style.top = '-9999px';
+ textArea.style.left = '-9999px';
+
+ document.body.appendChild(textArea);
+ textArea.focus();
+ textArea.select();
+
+ try {
+ const successful = document.execCommand('copy');
+ if (successful) {
+ showCopySuccess();
+ } else {
+ throw new Error('Fallback copy was unsuccessful');
+ }
+ } catch (err) {
+ console.error('Fallback copy failed: ', err);
+ alert('复制失败!');
+ }
+
+ document.body.removeChild(textArea);
+ };
+
+ const showCopySuccess = () => {
+ copyStatus.value = 'copied';
+ setTimeout(() => {
+ copyStatus.value = 'idle';
+ }, 2000);
+ };
+
const showHowItWorks = () => {
showModal.value = true;
};
@@ -146,10 +250,12 @@ export default {
selectedMessage,
loading,
showModal,
+ copyStatus,
domain,
fetchMessages,
selectMessage,
generateRandomEmail,
+ copyEmail,
showHowItWorks,
closeModal,
};
diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg
new file mode 100644
index 0000000..7ed7559
--- /dev/null
+++ b/frontend/src/assets/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css
index f286a77..ea5e119 100644
--- a/frontend/src/assets/main.css
+++ b/frontend/src/assets/main.css
@@ -1,4 +1,10 @@
/* Global Styles & Resets */
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap');
:root {
@@ -21,6 +27,7 @@ body {
color: var(--text-dark);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
+ overflow-x: hidden; /* Prevent horizontal scrolling */
}
/* App Container */
@@ -30,6 +37,8 @@ body {
align-items: center;
padding: 0 2rem;
min-height: 100vh;
+ width: 100%;
+ box-sizing: border-box;
}
/* Header */
@@ -90,13 +99,46 @@ body {
gap: 0.5rem;
}
-.email-input {
- width: 100%;
+.input-wrapper {
+ position: relative;
+ display: flex;
+ flex: 1;
max-width: 400px;
- padding: 0.75rem 1rem;
+}
+
+.email-input {
+ flex: 1;
+ /* top, right, bottom, left */
+ padding: 0.75rem 3rem 0.75rem 1rem;
border: 1px solid transparent;
border-radius: 8px;
font-size: 1rem;
+ width: 100%;
+}
+
+.btn-copy {
+ position: absolute;
+ top: 50%;
+ right: 0.5rem;
+ transform: translateY(-50%);
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ color: var(--dark-grey);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.5rem;
+ border-radius: 6px;
+}
+
+.btn-copy:hover {
+ background-color: var(--medium-grey);
+}
+
+.btn-copy span {
+ color: var(--primary-purple);
+ font-weight: bold;
}
.email-input:focus {
@@ -299,15 +341,88 @@ body {
/* Responsive */
@media (max-width: 768px) {
+ body {
+ -webkit-text-size-adjust: 100%; /* Prevent iOS font scaling */
+ }
+
+ #app {
+ padding: 0 1rem;
+ }
+
+ .app-header {
+ padding: 1rem 0; /* Adjust padding for mobile */
+ /* Keep flex row layout for alignment */
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .nav-links {
+ margin-left: 0; /* Reset margin for mobile */
+ }
+
+ .nav-links a {
+ margin: 0 0 0 1rem; /* Space out the links */
+ }
+
+ .hero-section {
+ padding: 2rem 1.5rem;
+ margin-bottom: 1.5rem;
+ text-align: center; /* Ensure content is centered on mobile */
+ }
+
+ .hero-section h1 {
+ font-size: 1.8rem;
+ }
+
+ .hero-section p {
+ font-size: 1rem;
+ }
+
+ .input-group {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.75rem;
+ }
+
+ .email-input {
+ max-width: none; /* Remove max-width on mobile */
+ }
+
+ .inbox-section {
+ min-width: 0; /* Reset min-width */
+ padding: 1rem;
+ }
+
.inbox-container {
flex-direction: column;
+ min-height: auto;
+ gap: 1rem;
}
- .message-list, .message-detail {
+
+ .message-list,
+ .message-detail {
width: 100%;
border-right: none;
padding-right: 0;
}
- .input-group {
- flex-direction: column;
+
+ .message-list {
+ border-bottom: 1px solid var(--medium-grey);
+ padding-bottom: 1rem;
+ }
+
+ .message-detail .empty-state {
+ padding: 2rem 0;
+ }
+
+ .message-body {
+ height: auto; /* Adjust height for mobile */
+ max-height: 400px;
+ }
+
+ .modal-content {
+ width: 95%;
+ padding: 1.5rem;
}
}
\ No newline at end of file