Skip to content

Commit b597f77

Browse files
feat: add entry
1 parent d4d2d8b commit b597f77

File tree

8 files changed

+175
-14
lines changed

8 files changed

+175
-14
lines changed

templates/vanilla-js-example/index.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ <h1 class="dark:text-white text-5xl md:text-6xl font-bold tracking-tight md:pt-2
2929
<p class="dark:text-white py-4 md:max-w-lg">
3030
Explore this demo app built with vanilla JavaScript, Tailwind, and
3131
<a href="https://juno.build" rel="noopener noreferrer" target="_blank" class="underline">
32-
Juno
33-
</a>
34-
, showcasing a practical application of these technologies.
32+
Juno</a
33+
>, showcasing a practical application of these technologies.
3534
</p>
3635

3736
<div id="app" class="contents"></div>

templates/vanilla-js-example/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"vite": "^5.2.0"
2121
},
2222
"dependencies": {
23-
"@junobuild/core": "^0.0.49"
23+
"@junobuild/core": "^0.0.49",
24+
"nanoid": "^5.0.7"
2425
}
2526
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import {renderLogout} from './logout';
2+
import {renderModal} from './modal';
3+
4+
export const renderContent = (app) => {
5+
app.innerHTML = `<div>
6+
7+
${renderModal(app)}
8+
9+
${renderLogout(app)}
10+
</div>`;
11+
};

templates/vanilla-js-example/src/components/logout.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const renderLogout = (app) => {
88
fn: signOut
99
});
1010

11-
app.innerHTML = `<button
11+
return `<button
1212
id="logout"
1313
type="button"
1414
class="dark:text-white flex items-center gap-2 mt-24 hover:text-lavender-blue-500 active:text-lavender-blue-400">
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import {authSubscribe, setDoc, uploadFile} from '@junobuild/core';
2+
import {nanoid} from 'nanoid';
3+
import {addEventClick} from '../utils/render.utils';
4+
5+
let user;
6+
authSubscribe((u) => (user = u));
7+
8+
const submitEntry = async (modal) => {
9+
// Demo purpose therefore edge case not properly handled
10+
if ([null, undefined].includes(user)) {
11+
return;
12+
}
13+
14+
const textarea = modal.querySelector('#entryText');
15+
const input = modal.querySelector('#fileEntry');
16+
17+
const inputText = textarea.value;
18+
const file = input.files[0];
19+
20+
try {
21+
let url;
22+
23+
if (file !== undefined) {
24+
const filename = `${user.key}-${file.name}`;
25+
26+
const {downloadUrl} = await uploadFile({
27+
collection: 'images',
28+
data: file,
29+
filename
30+
});
31+
32+
url = downloadUrl;
33+
}
34+
35+
const key = nanoid();
36+
37+
await setDoc({
38+
collection: 'notes',
39+
doc: {
40+
key,
41+
data: {
42+
text: inputText,
43+
...(url !== undefined && {url})
44+
}
45+
}
46+
});
47+
48+
closeModal(modal);
49+
50+
const reload = () => {
51+
const event = new Event('reload');
52+
window.dispatchEvent(event);
53+
};
54+
55+
reload();
56+
} catch (err) {
57+
console.error(err);
58+
}
59+
};
60+
61+
const closeModal = (modal) => (modal.innerHTML = '');
62+
63+
const showModal = () => {
64+
const modal = document.querySelector('#modal');
65+
66+
addEventClick({
67+
target: modal,
68+
selector: '#closeModal',
69+
fn: () => closeModal(modal)
70+
});
71+
72+
addEventClick({
73+
target: modal,
74+
selector: '#submitEntry',
75+
fn: async () => await submitEntry(modal)
76+
});
77+
78+
modal.innerHTML = `<div class="fixed inset-0 z-50 p-16 md:px-24 md:py-44 animate-fade" role="dialog">
79+
<div class="relative w-full max-w-xl">
80+
<textarea id="entryText"
81+
class="form-control
82+
block
83+
w-full
84+
px-3
85+
py-1.5
86+
text-base
87+
font-normal
88+
m-0
89+
resize-none
90+
border-black border-[3px] rounded-sm bg-white shadow-[5px_5px_0px_rgba(0,0,0,1)]
91+
focus:outline-none"
92+
rows="7"
93+
placeholder="Your diary entry"></textarea>
94+
95+
<div role="toolbar" class="flex justify-between items-center">
96+
<div>
97+
<input
98+
id="fileEntry"
99+
type="file"
100+
/>
101+
</div>
102+
103+
<div class="flex my-4">
104+
<button
105+
id="closeModal"
106+
class="py-1 px-8 hover:text-lavender-blue-600 active:text-lavender-blue-400"
107+
type="button">
108+
Close
109+
</button>
110+
111+
<button id="submitEntry"
112+
class="flex items-center gap-2 border-black dark:border-lavender-blue-500 border-[3px] transition-all rounded-sm py-1 px-8 my-2 font-semibold text-white bg-lavender-blue-500 dark:bg-black shadow-[5px_5px_0px_rgba(0,0,0,1)] dark:shadow-[5px_5px_0px_#7888ff] hover:bg-lavender-blue-600 dark:hover:bg-lavender-blue-300 dark:hover:text-black active:bg-lavender-blue-400 dark:active:bg-lavender-blue-500 active:shadow-none active:translate-x-[5px] active:translate-y-[5px]">
113+
Submit
114+
</button>
115+
116+
</div>
117+
</div>
118+
119+
</div>
120+
</div>
121+
122+
<div class="fixed inset-0 z-40 backdrop-blur-xl bg-white/30 flex items-center justify-center"></div>
123+
`;
124+
};
125+
126+
export const renderModal = (app) => {
127+
addEventClick({
128+
target: app,
129+
selector: '#addEntry',
130+
fn: showModal
131+
});
132+
133+
return `<button
134+
id="addEntry"
135+
type="button"
136+
class="dark:text-white flex items-center gap-2 mt-24 hover:text-lavender-blue-500 active:text-lavender-blue-400">
137+
Add an entry
138+
<svg
139+
xmlns="http://www.w3.org/2000/svg"
140+
height="20"
141+
viewBox="0 -960 960 960"
142+
width="20"
143+
fill="currentColor">
144+
<path d="M417-417H166v-126h251v-251h126v251h251v126H543v251H417v-251Z" />
145+
</svg>
146+
</button>
147+
148+
<div id="modal" class="contents"></div>
149+
`;
150+
};

templates/vanilla-js-example/src/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {authSubscribe, initJuno} from '@junobuild/core';
2+
import {renderContent} from './components/content';
23
import {renderLogin} from './components/login';
3-
import {renderLogout} from './components/logout';
44
import './style.css';
55

66
/**
@@ -14,7 +14,7 @@ authSubscribe((user) => {
1414
return;
1515
}
1616

17-
renderLogout(app);
17+
renderContent(app);
1818
});
1919

2020
/**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
@tailwind base;
22
@tailwind components;
3-
@tailwind utilities;
3+
@tailwind utilities;

templates/vanilla-js-example/src/utils/render.utils.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* @param fn The function to trigger on click.
66
*/
77
export const addEventClick = ({target, selector, fn}) => {
8-
const observer = new MutationObserver(() => {
9-
observer.disconnect();
10-
document.querySelector(selector)?.addEventListener('click', fn, {passive: true});
11-
});
12-
observer.observe(target, {childList: true, subtree: true});
13-
}
8+
const observer = new MutationObserver(() => {
9+
observer.disconnect();
10+
document.querySelector(selector)?.addEventListener('click', fn, {passive: true});
11+
});
12+
observer.observe(target, {childList: true, subtree: true});
13+
};

0 commit comments

Comments
 (0)