+3
-1
app/src/home-page/home.html
+3
-1
app/src/home-page/home.html
+5
app/src/home-page/home.ts
+5
app/src/home-page/home.ts
+116
app/src/settings-page/settings.css
+116
app/src/settings-page/settings.css
···
···
1
+
body {
2
+
font-family: system-ui, sans-serif;
3
+
background: #f9fafb;
4
+
display: flex;
5
+
align-items: center;
6
+
justify-content: center;
7
+
height: 100vh;
8
+
margin: 0;
9
+
}
10
+
11
+
.card {
12
+
max-width: 90%;
13
+
background: white;
14
+
border: 1px solid #d1d5db;
15
+
border-radius: 8px;
16
+
padding: 1.5rem;
17
+
box-sizing: border-box;
18
+
}
19
+
20
+
.header {
21
+
text-align: center;
22
+
margin-bottom: 1.5rem;
23
+
}
24
+
25
+
.icon-circle {
26
+
width: 64px;
27
+
height: 64px;
28
+
background: #dbeafe;
29
+
border-radius: 50%;
30
+
display: flex;
31
+
align-items: center;
32
+
justify-content: center;
33
+
margin: 0 auto 1rem;
34
+
}
35
+
36
+
.icon-circle img {
37
+
width: 32px;
38
+
height: 32px;
39
+
}
40
+
41
+
h1 {
42
+
font-size: 1.5rem;
43
+
}
44
+
45
+
p {
46
+
font-size: 0.9rem;
47
+
color: #6b7280;
48
+
}
49
+
50
+
.actions {
51
+
display: flex;
52
+
flex-direction: column;
53
+
gap: 1rem;
54
+
}
55
+
56
+
label {
57
+
display: block;
58
+
font-size: 0.85rem;
59
+
font-weight: 600;
60
+
margin-bottom: 0.25rem;
61
+
}
62
+
63
+
input {
64
+
width: 100%;
65
+
padding: 0.5rem 0.75rem;
66
+
border: 1px solid #d1d5db;
67
+
border-radius: 4px;
68
+
font-size: 0.95rem;
69
+
box-sizing: border-box;
70
+
}
71
+
72
+
input:focus {
73
+
outline: none;
74
+
border-color: #2563eb;
75
+
}
76
+
77
+
button {
78
+
width: 100%;
79
+
padding: 0.6rem;
80
+
font-size: 0.95rem;
81
+
border-radius: 4px;
82
+
cursor: pointer;
83
+
/*transition: background 0.2s ease;*/
84
+
display: flex;
85
+
align-items: center;
86
+
justify-content: center;
87
+
}
88
+
89
+
.btn-primary {
90
+
background: #2563eb;
91
+
color: white;
92
+
border: none;
93
+
}
94
+
95
+
.btn-primary:hover {
96
+
background: #1d4ed8;
97
+
}
98
+
99
+
.btn-qr {
100
+
background: white;
101
+
gap: 0.5rem;
102
+
border: 1px solid #d1d5db;
103
+
}
104
+
105
+
.btn-qr:hover {
106
+
background: #f3f4f6;
107
+
}
108
+
109
+
.btn-qr img {
110
+
width: 16px;
111
+
height: 16px;
112
+
}
113
+
114
+
.hint {
115
+
font-size: 0.75rem;
116
+
}
+26
app/src/settings-page/settings.html
+26
app/src/settings-page/settings.html
···
···
1
+
<!doctype html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8" />
5
+
<script type="module" src="./settings.ts"></script>
6
+
<link rel="stylesheet" href="./settings.css" />
7
+
</head>
8
+
9
+
<body>
10
+
<div class="card">
11
+
<!-- x-data connects this element to the settingsPageState Alpine component, enabling its data (serverAddress and signupKey) and functions (signup and scanQR) to work within it :) -->
12
+
<!-- TODO: make this a form instead? -->
13
+
<div class="actions" x-data="settingsPageState">
14
+
<h3>Settings</h3>
15
+
16
+
<button class="btn-secondary" @click="goto('home')">
17
+
Back to Home
18
+
</button>
19
+
20
+
<button class="btn-secondary" @click="resetStore()">
21
+
Signout
22
+
</button>
23
+
</div>
24
+
</div>
25
+
</body>
26
+
</html>
+16
app/src/settings-page/settings.ts
+16
app/src/settings-page/settings.ts
···
···
1
+
import Alpine from "alpinejs";
2
+
import { Store } from "../utils/store.ts";
3
+
import { goto } from "../utils/tools.ts";
4
+
5
+
Alpine.data("settingsPageState", () => ({
6
+
resetStore() {
7
+
Store.reset();
8
+
alert("Store reset");
9
+
goto("signup");
10
+
},
11
+
goto(newLocation: string) {
12
+
goto(newLocation);
13
+
},
14
+
}));
15
+
16
+
Alpine.start();
-116
app/src/settings-page/signup.css
-116
app/src/settings-page/signup.css
···
1
-
body {
2
-
font-family: system-ui, sans-serif;
3
-
background: #f9fafb;
4
-
display: flex;
5
-
align-items: center;
6
-
justify-content: center;
7
-
height: 100vh;
8
-
margin: 0;
9
-
}
10
-
11
-
.card {
12
-
max-width: 90%;
13
-
background: white;
14
-
border: 1px solid #d1d5db;
15
-
border-radius: 8px;
16
-
padding: 1.5rem;
17
-
box-sizing: border-box;
18
-
}
19
-
20
-
.header {
21
-
text-align: center;
22
-
margin-bottom: 1.5rem;
23
-
}
24
-
25
-
.icon-circle {
26
-
width: 64px;
27
-
height: 64px;
28
-
background: #dbeafe;
29
-
border-radius: 50%;
30
-
display: flex;
31
-
align-items: center;
32
-
justify-content: center;
33
-
margin: 0 auto 1rem;
34
-
}
35
-
36
-
.icon-circle img {
37
-
width: 32px;
38
-
height: 32px;
39
-
}
40
-
41
-
h1 {
42
-
font-size: 1.5rem;
43
-
}
44
-
45
-
p {
46
-
font-size: 0.9rem;
47
-
color: #6b7280;
48
-
}
49
-
50
-
.actions {
51
-
display: flex;
52
-
flex-direction: column;
53
-
gap: 1rem;
54
-
}
55
-
56
-
label {
57
-
display: block;
58
-
font-size: 0.85rem;
59
-
font-weight: 600;
60
-
margin-bottom: 0.25rem;
61
-
}
62
-
63
-
input {
64
-
width: 100%;
65
-
padding: 0.5rem 0.75rem;
66
-
border: 1px solid #d1d5db;
67
-
border-radius: 4px;
68
-
font-size: 0.95rem;
69
-
box-sizing: border-box;
70
-
}
71
-
72
-
input:focus {
73
-
outline: none;
74
-
border-color: #2563eb;
75
-
}
76
-
77
-
button {
78
-
width: 100%;
79
-
padding: 0.6rem;
80
-
font-size: 0.95rem;
81
-
border-radius: 4px;
82
-
cursor: pointer;
83
-
/*transition: background 0.2s ease;*/
84
-
display: flex;
85
-
align-items: center;
86
-
justify-content: center;
87
-
}
88
-
89
-
.btn-primary {
90
-
background: #2563eb;
91
-
color: white;
92
-
border: none;
93
-
}
94
-
95
-
.btn-primary:hover {
96
-
background: #1d4ed8;
97
-
}
98
-
99
-
.btn-qr {
100
-
background: white;
101
-
gap: 0.5rem;
102
-
border: 1px solid #d1d5db;
103
-
}
104
-
105
-
.btn-qr:hover {
106
-
background: #f3f4f6;
107
-
}
108
-
109
-
.btn-qr img {
110
-
width: 16px;
111
-
height: 16px;
112
-
}
113
-
114
-
.hint {
115
-
font-size: 0.75rem;
116
-
}
···
-42
app/src/settings-page/signup.html
-42
app/src/settings-page/signup.html
···
1
-
<!doctype html>
2
-
<html lang="en">
3
-
<head>
4
-
<meta charset="UTF-8" />
5
-
<script type="module" src="./signup.ts"></script>
6
-
<link rel="stylesheet" href="./signup.css" />
7
-
</head>
8
-
9
-
<body>
10
-
<div class="card">
11
-
<div class="header">
12
-
<div class="icon-circle">
13
-
<img src="/src/assets/pin.svg" alt="Pin Icon" />
14
-
</div>
15
-
<h1>PrivacyPin</h1>
16
-
<p>Connect with a server to start sharing</p>
17
-
</div>
18
-
19
-
<!-- x-data connects this element to the signupPageState Alpine component, enabling its data (serverAddress and signupKey) and functions (signup and scanQR) to work within it :) -->
20
-
<!-- TODO: make this a form instead? -->
21
-
<div class="actions" x-data="signupPageState">
22
-
<div>
23
-
<label for="server">Server Address</label>
24
-
<input id="server" type="url" placeholder="https://your-server.com" x-model="serverAddress" required />
25
-
</div>
26
-
27
-
<div>
28
-
<label for="key">Signup Key</label>
29
-
<input id="key" type="password" placeholder="Enter your signup key" x-model="signupKey" required />
30
-
</div>
31
-
32
-
<p class="hint">Scan a QR code to automatically fill both server address and signup key</p>
33
-
<button type="button" x-bind:disabled="isDoingStuff" class="btn-qr" @click="await scanQR()">
34
-
<img src="/src/assets/qr.svg" alt="QR Icon" />
35
-
Scan QR Code
36
-
</button>
37
-
38
-
<button class="btn-primary" x-bind:disabled="isDoingStuff" @click="await signup()"><span x-show="isDoingStuff">Connecting...</span> <span x-show="!isDoingStuff">Connect</span></button>
39
-
</div>
40
-
</div>
41
-
</body>
42
-
</html>
···
-11
app/src/settings-page/signup.ts
-11
app/src/settings-page/signup.ts
+1
-1
app/src/signup-page/signup.ts
+1
-1
app/src/signup-page/signup.ts
+48
app/src/utils/tools.ts
+48
app/src/utils/tools.ts
···
···
1
+
export function goto(newLocation: string) {
2
+
window.location.href =
3
+
"/src/" + newLocation + "-page/" + newLocation + ".html";
4
+
}
5
+
6
+
/*
7
+
8
+
Use this type of function to toggle dark mode. It CAN be modified to your needs. copy the function, and fix the end comment(be sure to put this in the alpine section)
9
+
10
+
toggleDarkMode() {
11
+
/*
12
+
This toggles darkmode for 'body' in the css file | use for only document types
13
+
document.body.classList.toggle("dark-theme");
14
+
15
+
this toggles darkmode for '.app' in the css file | use if it isn't a document type
16
+
toggleStyle("app", "dark-theme");
17
+
18
+
* /
19
+
20
+
document.body.classList.toggle("dark-theme");
21
+
toggleStyle("header", "dark-theme");
22
+
toggleStyle([".app", ".friend-card", ".content"], "dark-theme");
23
+
},
24
+
*/
25
+
26
+
export function toggleStyle(classNames: string | string[], newClass: string) {
27
+
if (typeof classNames === "string") {
28
+
for (
29
+
let i = 0;
30
+
i < document.getElementsByClassName(classNames).length;
31
+
i++
32
+
) {
33
+
document.getElementsByClassName(classNames)[i].classList.toggle(newClass);
34
+
}
35
+
} else {
36
+
for (let i = 0; i < classNames.length; i++) {
37
+
for (
38
+
let j = 0;
39
+
j < document.getElementsByClassName(classNames[i]).length;
40
+
j++
41
+
) {
42
+
document
43
+
.getElementsByClassName(classNames[i])
44
+
[j].classList.toggle(newClass);
45
+
}
46
+
}
47
+
}
48
+
}