Compare commits
22 Commits
chore/migr
...
d76182b2c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d76182b2c2 | ||
|
|
ed1a6b7fba | ||
|
|
d5b251c4a0 | ||
|
|
19b77810ec | ||
|
|
c8b0a78973 | ||
|
|
087d1a355e | ||
|
|
5d90da8ab5 | ||
|
|
72d065975d | ||
|
|
8b3df48791 | ||
|
|
cd8e173e05 | ||
|
|
8767f7c430 | ||
|
|
369a200a42 | ||
|
|
06eaa3c9a7 | ||
|
|
4cbcf42e3d | ||
|
|
a0be25c0dd | ||
|
|
dcee26100f | ||
|
|
ac68c68f8a | ||
|
|
982f3070a1 | ||
|
|
20e9538983 | ||
|
|
10c3e1ca60 | ||
| 6dc98c80ca | |||
|
|
1aef212a36 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,7 +2,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ RUN pnpm run build
|
|||||||
FROM nginx:alpine AS runner
|
FROM nginx:alpine AS runner
|
||||||
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s \
|
|
||||||
CMD wget -qO- http://localhost:80/ || exit 1
|
|
||||||
|
|||||||
9
nginx.conf
Normal file
9
nginx.conf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ const { isATProtoReady } = useATProtoLogin()
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#main-app {
|
#main-app {
|
||||||
height: 100vh;
|
height: 100dvh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
defineAsyncComponent,
|
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
onUnmounted,
|
onUnmounted,
|
||||||
@@ -9,6 +8,7 @@ import {
|
|||||||
watch
|
watch
|
||||||
} from "vue"
|
} from "vue"
|
||||||
|
|
||||||
|
import HeaderNote from "@/components/HeaderNote.vue"
|
||||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||||
import StackedNote from "@/components/StackedNote.vue"
|
import StackedNote from "@/components/StackedNote.vue"
|
||||||
import { useLinks } from "@/hooks/useLinks.hook"
|
import { useLinks } from "@/hooks/useLinks.hook"
|
||||||
@@ -21,10 +21,6 @@ import CacheAllNotes from "@/modules/note/components/CacheAllNote.vue"
|
|||||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||||
import { useUserSettings } from "@/modules/user/hooks/useUserSettings.hook"
|
import { useUserSettings } from "@/modules/user/hooks/useUserSettings.hook"
|
||||||
|
|
||||||
const HeaderNote = defineAsyncComponent(
|
|
||||||
() => import("@/components/HeaderNote.vue")
|
|
||||||
)
|
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
user: string
|
user: string
|
||||||
|
|||||||
@@ -16,41 +16,68 @@ const fontSizes = Array.from({ length: 7 }, (_, i) => `${9 + i * 2}pt`)
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="font-change" v-if="sortedFontFamilies.length > 0">
|
<div class="font-change" v-if="sortedFontFamilies.length > 0">
|
||||||
<theme-swap />
|
<div>
|
||||||
|
<label for="title-font" class="font-label">t</label>
|
||||||
|
<select
|
||||||
|
id="title-font"
|
||||||
|
class="select"
|
||||||
|
:value="store.userSettings?.chosenTitleFont"
|
||||||
|
@change="store.setTitleFont(($event.target as HTMLSelectElement).value)"
|
||||||
|
>
|
||||||
|
<option v-for="font in sortedFontFamilies" :key="font" :value="font">
|
||||||
|
{{ font }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select
|
<label for="body-font" class="font-label">p</label>
|
||||||
class="select"
|
<select
|
||||||
:value="store.userSettings?.chosenFontFamily"
|
id="body-font"
|
||||||
@change="store.setFontFamily(($event.target as HTMLSelectElement).value)"
|
class="select"
|
||||||
>
|
:value="store.userSettings?.chosenBodyFont"
|
||||||
<option v-for="font in sortedFontFamilies" :key="font" :value="font">
|
@change="store.setBodyFont(($event.target as HTMLSelectElement).value)"
|
||||||
{{ font }}
|
>
|
||||||
</option>
|
<option v-for="font in sortedFontFamilies" :key="font" :value="font">
|
||||||
</select>
|
{{ font }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<theme-swap />
|
||||||
|
|
||||||
<select
|
<label for="font-size" class="font-label">s</label>
|
||||||
class="select"
|
<select
|
||||||
:value="store.userSettings?.chosenFontSize"
|
id="font-size"
|
||||||
@change="store.setFontSize(($event.target as HTMLSelectElement).value)"
|
class="select"
|
||||||
>
|
:value="store.userSettings?.chosenFontSize"
|
||||||
<option v-for="size in fontSizes" :key="size" :value="size">
|
@change="store.setFontSize(($event.target as HTMLSelectElement).value)"
|
||||||
{{ size }}
|
>
|
||||||
</option>
|
<option v-for="size in fontSizes" :key="size" :value="size">
|
||||||
</select>
|
{{ size }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.font-change {
|
.font-change {
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-label {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,32 +1,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import FontChange from "@/components/FontChange.vue"
|
import FontChange from "@/components/FontChange.vue"
|
||||||
|
import HomeButton from "@/components/HomeButton.vue"
|
||||||
|
|
||||||
defineProps<{ user: string; repo: string }>()
|
defineProps<{ user: string; repo: string }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="header-note">
|
<header class="header-note">
|
||||||
<router-link
|
<home-button />
|
||||||
:to="{ name: 'Home' }"
|
|
||||||
class="button is-small is-white back-button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="icon icon-tabler icon-tabler-arrow-narrow-left"
|
|
||||||
width="28"
|
|
||||||
height="28"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
>
|
|
||||||
<line x1="5" y1="12" x2="19" y2="12" />
|
|
||||||
<line x1="5" y1="12" x2="9" y2="16" />
|
|
||||||
<line x1="5" y1="12" x2="9" y2="8" />
|
|
||||||
</svg>
|
|
||||||
</router-link>
|
|
||||||
<!-- <router-link
|
<!-- <router-link
|
||||||
:to="{ name: 'SpacedRepetitionCard', params: { user, repo } }"
|
:to="{ name: 'SpacedRepetitionCard', params: { user, repo } }"
|
||||||
>
|
>
|
||||||
@@ -51,12 +32,12 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
</svg>
|
</svg>
|
||||||
</router-link> -->
|
</router-link> -->
|
||||||
|
|
||||||
<button onclick="font_modal.showModal()">
|
<a class="btn btn-ghost btn-circle" onclick="font_modal.showModal()">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="icon icon-tabler icons-tabler-outline icon-tabler-typography"
|
class="icon icon-tabler icons-tabler-outline icon-tabler-typography"
|
||||||
width="36"
|
width="30"
|
||||||
height="36"
|
height="30"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -70,12 +51,15 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
<path d="M10.2 6.3l5.8 13.7" />
|
<path d="M10.2 6.3l5.8 13.7" />
|
||||||
<path d="M5 20l6 -16l2 0l7 16" />
|
<path d="M5 20l6 -16l2 0l7 16" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</a>
|
||||||
<router-link :to="{ name: 'FluxNoteView', params: { user, repo } }">
|
<router-link
|
||||||
|
class="btn btn-ghost btn-circle"
|
||||||
|
:to="{ name: 'FluxNoteView', params: { user, repo } }"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="36"
|
width="30"
|
||||||
height="36"
|
height="30"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -88,12 +72,15 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
<path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" />
|
<path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" />
|
||||||
</svg>
|
</svg>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link :to="{ name: 'DraftNotes', params: { user, repo } }">
|
<router-link
|
||||||
|
class="btn btn-ghost btn-circle"
|
||||||
|
:to="{ name: 'DraftNotes', params: { user, repo } }"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="icon icon-tabler icon-tabler-notes"
|
class="icon icon-tabler icon-tabler-notes"
|
||||||
width="36"
|
width="30"
|
||||||
height="36"
|
height="30"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -107,11 +94,14 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
<line x1="9" y1="15" x2="13" y2="15" />
|
<line x1="9" y1="15" x2="13" y2="15" />
|
||||||
</svg>
|
</svg>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link :to="{ name: 'TodoNotes', params: { user, repo } }">
|
<router-link
|
||||||
|
class="btn btn-ghost btn-circle"
|
||||||
|
:to="{ name: 'TodoNotes', params: { user, repo } }"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="36"
|
width="30"
|
||||||
height="36"
|
height="30"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -129,12 +119,15 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
<path d="M11 18l9 0" />
|
<path d="M11 18l9 0" />
|
||||||
</svg>
|
</svg>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link :to="{ name: 'FleetingNotes', params: { user, repo } }">
|
<router-link
|
||||||
|
class="btn btn-ghost btn-circle"
|
||||||
|
:to="{ name: 'FleetingNotes', params: { user, repo } }"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="icon icon-tabler icon-tabler-mailbox"
|
class="icon icon-tabler icon-tabler-mailbox"
|
||||||
width="36"
|
width="30"
|
||||||
height="36"
|
height="30"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -150,7 +143,7 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
</svg>
|
</svg>
|
||||||
</router-link>
|
</router-link>
|
||||||
<dialog id="font_modal" class="modal">
|
<dialog id="font_modal" class="modal">
|
||||||
<div class="modal-box">
|
<div class="modal-box w-11/12 max-w-5xl">
|
||||||
<h3 class="text-lg font-bold">Style settings</h3>
|
<h3 class="text-lg font-bold">Style settings</h3>
|
||||||
<font-change />
|
<font-change />
|
||||||
</div>
|
</div>
|
||||||
@@ -167,15 +160,5 @@ defineProps<{ user: string; repo: string }>()
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
img {
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
color: var(--color-accent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const getStyle = (seed: string) => {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.repo-list {
|
.repo-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
|||||||
@@ -3,53 +3,52 @@ import RepoList from "@/components/RepoList.vue"
|
|||||||
import SignInAtproto from "@/components/SignInAtproto.vue"
|
import SignInAtproto from "@/components/SignInAtproto.vue"
|
||||||
import SignInGithub from "@/components/SignInGithub.vue"
|
import SignInGithub from "@/components/SignInGithub.vue"
|
||||||
import ThemeSwap from "@/components/ThemeSwap.vue"
|
import ThemeSwap from "@/components/ThemeSwap.vue"
|
||||||
|
import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook"
|
||||||
import { useForm } from "@/hooks/useForm.hook"
|
import { useForm } from "@/hooks/useForm.hook"
|
||||||
import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook"
|
import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook"
|
||||||
import LastVisited from "@/modules/history/components/LastVisited.vue"
|
import LastVisited from "@/modules/history/components/LastVisited.vue"
|
||||||
|
|
||||||
const { isLogged } = useGitHubLogin()
|
const { isLogged } = useGitHubLogin()
|
||||||
|
const { isLoggedIn: isATProtoLoggedIn, avatarUrl } = useATProtoLogin()
|
||||||
const { userInput, repoInput, submit } = useForm()
|
const { userInput, repoInput, submit } = useForm()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="welcome-world">
|
<div class="welcome-world">
|
||||||
<h1 class="title is-1">
|
<div class="welcome-content">
|
||||||
<img src="/favicon.png" alt="Remanso icon" class="remanso-logo" />
|
<h1 class="title is-1">
|
||||||
Remanso
|
<img src="/favicon.png" alt="Remanso icon" class="remanso-logo" />
|
||||||
</h1>
|
Remanso
|
||||||
|
</h1>
|
||||||
|
|
||||||
<repo-list />
|
<repo-list />
|
||||||
|
|
||||||
<last-visited />
|
<last-visited />
|
||||||
|
|
||||||
<div class="get-started">
|
<form class="github-form" @submit.prevent>
|
||||||
<sign-in-github />
|
<div>github/</div>
|
||||||
<router-link v-if="isLogged" :to="{ name: 'RepoList' }" class="btn btn-sm"
|
<input
|
||||||
>Manage your repos</router-link
|
v-model="userInput"
|
||||||
>
|
class="input input-ghost"
|
||||||
|
type="text"
|
||||||
|
placeholder="user"
|
||||||
|
/>
|
||||||
|
/
|
||||||
|
<input
|
||||||
|
v-model="repoInput"
|
||||||
|
class="input input-ghost"
|
||||||
|
type="text"
|
||||||
|
placeholder="repo"
|
||||||
|
/>
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary" @click="submit">
|
||||||
|
go
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="github-form" @submit.prevent>
|
|
||||||
<div>github/</div>
|
|
||||||
<input
|
|
||||||
v-model="userInput"
|
|
||||||
class="input input-ghost"
|
|
||||||
type="text"
|
|
||||||
placeholder="user"
|
|
||||||
/>
|
|
||||||
/
|
|
||||||
<input
|
|
||||||
v-model="repoInput"
|
|
||||||
class="input input-ghost"
|
|
||||||
type="text"
|
|
||||||
placeholder="repo"
|
|
||||||
/>
|
|
||||||
<button type="submit" class="btn btn-primary" @click="submit">go</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<theme-swap />
|
<theme-swap />
|
||||||
Made with
|
made with
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="icon icon-tabler icon-tabler-heart"
|
class="icon icon-tabler icon-tabler-heart"
|
||||||
@@ -71,7 +70,32 @@ const { userInput, repoInput, submit } = useForm()
|
|||||||
<a href="https://apoena.dev" target="_blank" rel="noopener noreferrer"
|
<a href="https://apoena.dev" target="_blank" rel="noopener noreferrer"
|
||||||
>apoena</a
|
>apoena</a
|
||||||
>
|
>
|
||||||
<sign-in-atproto :with-sign-out="false" />
|
<button
|
||||||
|
class="btn btn-ghost btn-circle btn-sm profile-btn"
|
||||||
|
onclick="profile_modal.showModal()"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="isATProtoLoggedIn && avatarUrl"
|
||||||
|
:src="avatarUrl"
|
||||||
|
class="profile-avatar"
|
||||||
|
alt="Profile"
|
||||||
|
/>
|
||||||
|
<svg
|
||||||
|
v-else
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" />
|
||||||
|
<path d="M6 20c0 -2.21 2.686 -4 6 -4s6 1.79 6 4" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'FluxNoteView',
|
name: 'FluxNoteView',
|
||||||
@@ -81,6 +105,28 @@ const { userInput, repoInput, submit } = useForm()
|
|||||||
>Get started</router-link
|
>Get started</router-link
|
||||||
>
|
>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<dialog id="profile_modal" class="modal">
|
||||||
|
<div class="modal-box profile-modal-box">
|
||||||
|
<h3 class="text-lg font-bold">Profile</h3>
|
||||||
|
<div class="profile-section">
|
||||||
|
<sign-in-atproto :with-sign-out="true" />
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="profile-section">
|
||||||
|
<sign-in-github />
|
||||||
|
<router-link
|
||||||
|
v-if="isLogged"
|
||||||
|
:to="{ name: 'RepoList' }"
|
||||||
|
class="btn btn-sm"
|
||||||
|
>Manage your repos</router-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" class="modal-backdrop">
|
||||||
|
<button></button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -98,26 +144,26 @@ h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.welcome-world {
|
.welcome-world {
|
||||||
padding: 1rem;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
align-self: stretch;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
gap: 1rem;
|
||||||
|
|
||||||
.get-started {
|
|
||||||
margin: center;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 1rem;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.welcome-content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.github-form {
|
.github-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -127,15 +173,33 @@ h1 {
|
|||||||
max-width: 140px;
|
max-width: 140px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 0.2rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
.profile-avatar {
|
||||||
vertical-align: middle;
|
max-width: 100%;
|
||||||
margin-top: 0;
|
border-radius: 50%;
|
||||||
}
|
object-fit: cover;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-modal-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-section {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to-user-repo {
|
.to-user-repo {
|
||||||
|
|||||||
@@ -14,14 +14,32 @@ import {
|
|||||||
|
|
||||||
const did = ref<string | null>(null)
|
const did = ref<string | null>(null)
|
||||||
const handle = ref<string | null>(null)
|
const handle = ref<string | null>(null)
|
||||||
|
const avatarUrl = ref<string | null>(null)
|
||||||
|
|
||||||
let init = true
|
let init = true
|
||||||
|
|
||||||
|
const fetchAvatar = async (actorDid: string) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(actorDid)}`
|
||||||
|
)
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
avatarUrl.value = data.avatar ?? null
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
avatarUrl.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const initializeAuth = async () => {
|
const initializeAuth = async () => {
|
||||||
// Load cached session from IndexedDB first (fast, local) so the UI can render immediately
|
// Load cached session from IndexedDB first (fast, local) so the UI can render immediately
|
||||||
const stored = await loadSession()
|
const stored = await loadSession()
|
||||||
did.value = stored?.did ?? ""
|
did.value = stored?.did ?? ""
|
||||||
handle.value = stored?.handle ?? ""
|
handle.value = stored?.handle ?? ""
|
||||||
|
if (stored?.did) {
|
||||||
|
fetchAvatar(stored.did)
|
||||||
|
}
|
||||||
|
|
||||||
// Then restore OAuth session in the background (may involve network)
|
// Then restore OAuth session in the background (may involve network)
|
||||||
const session = await restoreSession()
|
const session = await restoreSession()
|
||||||
@@ -32,6 +50,7 @@ const initializeAuth = async () => {
|
|||||||
did.value = session.did
|
did.value = session.did
|
||||||
handle.value = resolvedHandle
|
handle.value = resolvedHandle
|
||||||
await saveSession(session.did, resolvedHandle)
|
await saveSession(session.did, resolvedHandle)
|
||||||
|
fetchAvatar(session.did)
|
||||||
|
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
null,
|
null,
|
||||||
@@ -61,11 +80,13 @@ export const useATProtoLogin = () => {
|
|||||||
await clearSession()
|
await clearSession()
|
||||||
did.value = ""
|
did.value = ""
|
||||||
handle.value = ""
|
handle.value = ""
|
||||||
|
avatarUrl.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
did,
|
did,
|
||||||
handle,
|
handle,
|
||||||
|
avatarUrl,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isATProtoReady,
|
isATProtoReady,
|
||||||
signIn,
|
signIn,
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ export interface UserSettings extends Model<DataType.UserSettings> {
|
|||||||
fontSize?: string
|
fontSize?: string
|
||||||
chosenFontSize?: string
|
chosenFontSize?: string
|
||||||
backlink?: boolean
|
backlink?: boolean
|
||||||
|
chosenTitleFont?: string
|
||||||
|
chosenBodyFont?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,16 @@ export const getUserSettingsContent = async (
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.parse(atob(content)) as UserSettings
|
const raw = JSON.parse(atob(content)) as UserSettings & {
|
||||||
|
t?: string
|
||||||
|
p?: string
|
||||||
|
}
|
||||||
|
const { t, p, ...rest } = raw
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
chosenTitleFont: t,
|
||||||
|
chosenBodyFont: p
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryFileContent = async (
|
export const queryFileContent = async (
|
||||||
|
|||||||
@@ -81,6 +81,14 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
|||||||
: userSettings?.fontFamily
|
: userSettings?.fontFamily
|
||||||
const chosenFontSize =
|
const chosenFontSize =
|
||||||
this.userSettings?.chosenFontSize ?? userSettings?.fontSize
|
this.userSettings?.chosenFontSize ?? userSettings?.fontSize
|
||||||
|
const chosenTitleFont =
|
||||||
|
this.userSettings?.chosenTitleFont ??
|
||||||
|
userSettings?.chosenTitleFont ??
|
||||||
|
chosenFontFamily
|
||||||
|
const chosenBodyFont =
|
||||||
|
this.userSettings?.chosenBodyFont ??
|
||||||
|
userSettings?.chosenBodyFont ??
|
||||||
|
chosenFontFamily
|
||||||
this.userSettings = userSettings
|
this.userSettings = userSettings
|
||||||
|
|
||||||
if (!this.userSettings) {
|
if (!this.userSettings) {
|
||||||
@@ -91,6 +99,8 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
|||||||
chosenFontFamily ?? this.userSettings.fontFamily
|
chosenFontFamily ?? this.userSettings.fontFamily
|
||||||
this.userSettings.chosenFontSize =
|
this.userSettings.chosenFontSize =
|
||||||
chosenFontSize ?? this.userSettings.fontSize
|
chosenFontSize ?? this.userSettings.fontSize
|
||||||
|
this.userSettings.chosenTitleFont = chosenTitleFont
|
||||||
|
this.userSettings.chosenBodyFont = chosenBodyFont
|
||||||
|
|
||||||
data.update<DataType.UserSettings, UserSettings>({
|
data.update<DataType.UserSettings, UserSettings>({
|
||||||
...this.userSettings,
|
...this.userSettings,
|
||||||
@@ -156,6 +166,30 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
|||||||
}
|
}
|
||||||
this.userSettings.chosenFontSize = fontSize
|
this.userSettings.chosenFontSize = fontSize
|
||||||
|
|
||||||
|
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
||||||
|
data.update<DataType.UserSettings, UserSettings>({
|
||||||
|
...this.userSettings,
|
||||||
|
_id: userSettingsId
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setTitleFont(font: string) {
|
||||||
|
if (!this.userSettings) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.userSettings.chosenTitleFont = font
|
||||||
|
|
||||||
|
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
||||||
|
data.update<DataType.UserSettings, UserSettings>({
|
||||||
|
...this.userSettings,
|
||||||
|
_id: userSettingsId
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setBodyFont(font: string) {
|
||||||
|
if (!this.userSettings) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.userSettings.chosenBodyFont = font
|
||||||
|
|
||||||
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
||||||
data.update<DataType.UserSettings, UserSettings>({
|
data.update<DataType.UserSettings, UserSettings>({
|
||||||
...this.userSettings,
|
...this.userSettings,
|
||||||
|
|||||||
@@ -12,10 +12,15 @@ export const useUserSettings = () => {
|
|||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const root = document.documentElement
|
const root = document.documentElement
|
||||||
|
|
||||||
const fontFamily = store.userSettings?.chosenFontFamily
|
|
||||||
const fontSize = store.userSettings?.chosenFontSize
|
const fontSize = store.userSettings?.chosenFontSize
|
||||||
|
const bodyFont = store.userSettings?.chosenBodyFont
|
||||||
|
const titleFont = store.userSettings?.chosenTitleFont
|
||||||
|
|
||||||
downloadFont(fontFamily || DEFAULT_FONT_POLICY)
|
downloadFont(bodyFont || DEFAULT_FONT_POLICY, "--font-family")
|
||||||
|
downloadFont(
|
||||||
|
titleFont || bodyFont || DEFAULT_FONT_POLICY,
|
||||||
|
"--title-font-family"
|
||||||
|
)
|
||||||
root.style.setProperty("--font-size", fontSize || DEFAULT_FONT_SIZE)
|
root.style.setProperty("--font-size", fontSize || DEFAULT_FONT_SIZE)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,12 @@ router.beforeEach(() => {
|
|||||||
}
|
}
|
||||||
).startViewTransition(async () => {
|
).startViewTransition(async () => {
|
||||||
resolve()
|
resolve()
|
||||||
await nextTick()
|
await new Promise<void>((r) => {
|
||||||
|
const unwatch = router.afterEach(() => {
|
||||||
|
unwatch()
|
||||||
|
nextTick().then(r)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--primary-color: #ffa4c0;
|
--primary-color: #ffa4c0;
|
||||||
--font-family: "Libertinus Serif", serif;
|
--font-family: "Libertinus Serif", serif;
|
||||||
|
--title-font-family: "Libertinus Serif", serif;
|
||||||
--font-size: 13pt;
|
--font-size: 13pt;
|
||||||
--font-color: #4a4a4a;
|
--font-color: #4a4a4a;
|
||||||
--link: #445fb9;
|
--link: #445fb9;
|
||||||
@@ -48,22 +49,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html,
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
height: 100vh;
|
height: 100dvh;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 769px) {
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.columns {
|
.columns {
|
||||||
@@ -77,7 +66,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height: 100vh;
|
height: 100dvh;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ const assembleFontLink = (font: string) => {
|
|||||||
.replaceAll(" ", "+")}`
|
.replaceAll(" ", "+")}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const downloadFont = async (font: string): Promise<void> => {
|
export const downloadFont = async (
|
||||||
|
font: string,
|
||||||
|
cssVar = "--font-family"
|
||||||
|
): Promise<void> => {
|
||||||
const href = assembleFontLink(font)
|
const href = assembleFontLink(font)
|
||||||
|
|
||||||
// check if the href already exists
|
// check if the href already exists
|
||||||
@@ -23,7 +26,7 @@ export const downloadFont = async (font: string): Promise<void> => {
|
|||||||
try {
|
try {
|
||||||
await new FontFaceObserver(font).load()
|
await new FontFaceObserver(font).load()
|
||||||
|
|
||||||
document.documentElement.style.setProperty("--font-family", font)
|
document.documentElement.style.setProperty(cssVar, font)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("error when loading font")
|
console.warn("error when loading font")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import WelcomeWorld from "@/components/WelcomeWorld.vue"
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: 100dvh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorize {
|
.authorize {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTitle } from "@vueuse/core"
|
|||||||
import { computed, nextTick, ref, watch } from "vue"
|
import { computed, nextTick, ref, watch } from "vue"
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router"
|
||||||
|
|
||||||
import BackButton from "@/components/BackButton.vue"
|
import HomeButton from "@/components/HomeButton.vue"
|
||||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||||
import StackedPublicNote from "@/components/StackedPublicNote.vue"
|
import StackedPublicNote from "@/components/StackedPublicNote.vue"
|
||||||
import ThemeSwap from "@/components/ThemeSwap.vue"
|
import ThemeSwap from "@/components/ThemeSwap.vue"
|
||||||
@@ -129,13 +129,7 @@ watch(
|
|||||||
<main class="public-note-view repo-note note-container">
|
<main class="public-note-view repo-note note-container">
|
||||||
<div class="note article">
|
<div class="note article">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<back-button
|
<home-button />
|
||||||
:fallback="{ name: 'PublicNoteListByDidView', params: { shortDid } }"
|
|
||||||
:prefer-fallback="false"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img src="/favicon.png" alt="Remanso" class="remanso-logo" />
|
|
||||||
|
|
||||||
<theme-swap />
|
<theme-swap />
|
||||||
</div>
|
</div>
|
||||||
<div class="subheader">
|
<div class="subheader">
|
||||||
@@ -197,13 +191,6 @@ watch(
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.remanso-logo {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
box-shadow: none;
|
|
||||||
view-transition-name: remanso-logo;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subheader {
|
.subheader {
|
||||||
margin: 1rem auto 0;
|
margin: 1rem auto 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ const defaultTitleStyles = Array.from(
|
|||||||
...acc,
|
...acc,
|
||||||
[heading]: {
|
[heading]: {
|
||||||
"margin-top": "0",
|
"margin-top": "0",
|
||||||
"margin-bottom": "0.5em"
|
"margin-bottom": "0.5em",
|
||||||
|
"font-family": "var(--title-font-family)"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{}
|
{}
|
||||||
|
|||||||
Reference in New Issue
Block a user