Merge branch 'main' of github.com:jcalixte/lite-note
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
env: {
|
env: {
|
||||||
@@ -9,7 +11,8 @@ module.exports = {
|
|||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:vue/recommended',
|
'plugin:vue/recommended',
|
||||||
'@vue/typescript/recommended',
|
'@vue/typescript/recommended',
|
||||||
'@vue/prettier/@typescript-eslint',
|
'@vue/prettier',
|
||||||
|
'@vue/eslint-config-typescript',
|
||||||
'plugin:prettier-vue/recommended'
|
'plugin:prettier-vue/recommended'
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
@@ -26,6 +29,7 @@ module.exports = {
|
|||||||
arrowParens: 'always'
|
arrowParens: 'always'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
semi: 0,
|
||||||
'vue/no-v-html': 'off',
|
'vue/no-v-html': 'off',
|
||||||
'no-restricted-imports': [
|
'no-restricted-imports': [
|
||||||
'error',
|
'error',
|
||||||
|
|||||||
43
package.json
43
package.json
@@ -15,7 +15,7 @@
|
|||||||
"@octokit/core": "^5.0.0",
|
"@octokit/core": "^5.0.0",
|
||||||
"@octokit/rest": "^20.0.1",
|
"@octokit/rest": "^20.0.1",
|
||||||
"@toycode/markdown-it-class": "^1.2.4",
|
"@toycode/markdown-it-class": "^1.2.4",
|
||||||
"@vueuse/core": "^10.2.1",
|
"@vueuse/core": "^10.3.0",
|
||||||
"bulma": "^0.9.4",
|
"bulma": "^0.9.4",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
@@ -25,10 +25,9 @@
|
|||||||
"markdown-it-footnote": "^3.0.3",
|
"markdown-it-footnote": "^3.0.3",
|
||||||
"markdown-it-iframe": "^1.0.0",
|
"markdown-it-iframe": "^1.0.0",
|
||||||
"markdown-it-latex": "^0.2.0",
|
"markdown-it-latex": "^0.2.0",
|
||||||
"markdown-it-svg-code-copy": "^1.0.0",
|
|
||||||
"nanoid": "^4.0.2",
|
"nanoid": "^4.0.2",
|
||||||
"notyf": "^3.10.0",
|
"notyf": "^3.10.0",
|
||||||
"pinia": "^2.1.4",
|
"pinia": "^2.1.6",
|
||||||
"pouchdb-adapter-indexeddb": "^8.0.1",
|
"pouchdb-adapter-indexeddb": "^8.0.1",
|
||||||
"pouchdb-browser": "^8.0.1",
|
"pouchdb-browser": "^8.0.1",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.7.2",
|
||||||
@@ -39,29 +38,29 @@
|
|||||||
"vue-router": "^4.2.4"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.22.9",
|
||||||
|
"@rushstack/eslint-patch": "^1.3.2",
|
||||||
"@types/markdown-it": "^12.2.3",
|
"@types/markdown-it": "^12.2.3",
|
||||||
"@types/node": "^20.3.3",
|
"@types/node": "^20.4.8",
|
||||||
"@types/pouchdb-browser": "^6.1.3",
|
"@types/pouchdb-browser": "^6.1.3",
|
||||||
"@types/sanitize-html": "^2.6.0",
|
"@types/sanitize-html": "^2.9.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||||
"@typescript-eslint/parser": "^5.6.0",
|
"@typescript-eslint/parser": "^6.2.1",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"@vue/compiler-sfc": "^3.2.24",
|
"@vue/compiler-sfc": "^3.3.4",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
"@vue/eslint-config-typescript": "^9.1.0",
|
"@vue/eslint-config-typescript": "^11.0.3",
|
||||||
"@vue/test-utils": "^2.0.0-beta.8",
|
"eslint": "^8.46.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier-vue": "^4.2.0",
|
||||||
"eslint-plugin-prettier-vue": "^3.1.0",
|
"eslint-plugin-vue": "^9.16.1",
|
||||||
"eslint-plugin-vue": "^8.2.0",
|
"prettier": "^3.0.1",
|
||||||
"prettier": "^2.5.1",
|
"sass": "^1.64.2",
|
||||||
"sass": "^1.63.6",
|
|
||||||
"typescript": "~4.5.3",
|
"typescript": "~4.5.3",
|
||||||
"vite": "^4.4.4",
|
"vite": "^4.4.8",
|
||||||
"vite-plugin-pwa": "^0.16.4",
|
"vite-plugin-pwa": "^0.16.4",
|
||||||
"vitest": "^0.33.0",
|
"vitest": "^0.34.1",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1987
pnpm-lock.yaml
generated
1987
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
12
src/App.vue
12
src/App.vue
@@ -6,10 +6,18 @@ const { isReady } = useGitHubLogin()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<router-view v-if="isReady" />
|
<div id="main-app">
|
||||||
<new-version />
|
<router-view v-if="isReady" />
|
||||||
|
<new-version />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import 'styles/app';
|
@import 'styles/app';
|
||||||
|
|
||||||
|
#main-app {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ const focus = () => scrollToFocusedNote(undefined, true)
|
|||||||
<div class="repo-title">
|
<div class="repo-title">
|
||||||
<h1 class="title is-1">
|
<h1 class="title is-1">
|
||||||
[<router-link
|
[<router-link
|
||||||
:to="{ name: 'Home', params: { user, repo } }"
|
:to="{ name: 'FluxNoteView', params: { user, repo } }"
|
||||||
@click="resetStackedNotes"
|
@click="resetStackedNotes"
|
||||||
>{{ repo }}</router-link
|
>{{ repo }}</router-link
|
||||||
>]
|
>]
|
||||||
|
|||||||
@@ -1,3 +1,23 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useBacklinks } from '@/hooks/useBacklinks.hook'
|
||||||
|
import { useQueryStackedNotes } from '@/hooks/useQueryStackedNotes.hook'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
sha: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const shaProp = computed((props) => props.sha)
|
||||||
|
|
||||||
|
const { backlink } = useBacklinks(shaProp)
|
||||||
|
const { addStackedNote } = useQueryStackedNotes()
|
||||||
|
const hasBacklinks = computed(() => (backlink.value?.links.length ?? 0) > 0)
|
||||||
|
|
||||||
|
const emitNote = (sha: string) => {
|
||||||
|
addStackedNote(props.sha, sha)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="hasBacklinks" class="linked-notes">
|
<div v-if="hasBacklinks" class="linked-notes">
|
||||||
<h5 class="subtitle is-5">🔗</h5>
|
<h5 class="subtitle is-5">🔗</h5>
|
||||||
@@ -11,36 +31,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { useBacklinks } from '@/hooks/useBacklinks.hook'
|
|
||||||
import { useQueryStackedNotes } from '@/hooks/useQueryStackedNotes.hook'
|
|
||||||
import { computed, defineComponent } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'LinkedNotes',
|
|
||||||
props: {
|
|
||||||
sha: { type: String, required: true }
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { backlink } = useBacklinks(props.sha)
|
|
||||||
const { addStackedNote } = useQueryStackedNotes()
|
|
||||||
const hasBacklinks = computed(
|
|
||||||
() => (backlink.state.value?.links.length ?? 0) > 0
|
|
||||||
)
|
|
||||||
|
|
||||||
const emitNote = (sha: string) => {
|
|
||||||
addStackedNote(props.sha, sha)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
backlink: backlink.state,
|
|
||||||
hasBacklinks,
|
|
||||||
emitNote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.linked-notes {
|
.linked-notes {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-github">
|
<div class="login-github">
|
||||||
<br />
|
<br />
|
||||||
<a ;href="url" target="_blank" rel="noopener noreferrer">
|
<a :href="url.toString()" target="_blank" rel="noopener noreferrer">
|
||||||
login to
|
login to
|
||||||
<img src="@/assets/icons/github.svg" alt="GitHub icon" />
|
<img src="@/assets/icons/github.svg" alt="GitHub icon" />
|
||||||
</a>
|
</a>
|
||||||
@@ -25,8 +25,3 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.login-github {
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const reload = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button class="button is-primary" v-if="needRefresh" @click="reload">
|
<button v-if="needRefresh" class="button is-primary" @click="reload">
|
||||||
<LiteLoading v-if="isLoading" />
|
<LiteLoading v-if="isLoading" />
|
||||||
<span v-else>Reload</span>
|
<span v-else>Reload</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="buttons is-centered">
|
<div class="buttons is-centered">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
params: { user: 'lite-note', repo: 'getting-started' }
|
params: { user: 'lite-note', repo: 'getting-started' }
|
||||||
}"
|
}"
|
||||||
class="button is-primary"
|
class="button is-primary"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
params: {
|
params: {
|
||||||
user: username,
|
user: username,
|
||||||
repo: favoriteRepo.name
|
repo: favoriteRepo.name
|
||||||
@@ -102,15 +102,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
import SignInGithub from '@/components/SignInGithub.vue'
|
||||||
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 { useFavoriteRepos } from '@/modules/repo/hooks/useFavoriteRepos.hook'
|
|
||||||
import SignInGithub from '@/components/SignInGithub.vue'
|
|
||||||
import LastVisited from '@/modules/history/components/LastVisited.vue'
|
import LastVisited from '@/modules/history/components/LastVisited.vue'
|
||||||
|
import { useFavoriteRepos } from '@/modules/repo/hooks/useFavoriteRepos.hook'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'WelcomeWord',
|
name: 'WelcomeWorld',
|
||||||
components: { SignInGithub, LastVisited },
|
components: { SignInGithub, LastVisited },
|
||||||
setup() {
|
setup() {
|
||||||
const { isLogged, username } = useGitHubLogin()
|
const { isLogged, username } = useGitHubLogin()
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import { data } from '@/data/data'
|
|||||||
import { DataType } from '@/data/DataType.enum'
|
import { DataType } from '@/data/DataType.enum'
|
||||||
import { BacklinkNote } from '@/modules/note/models/BacklinkNote'
|
import { BacklinkNote } from '@/modules/note/models/BacklinkNote'
|
||||||
import { useAsyncState } from '@vueuse/core'
|
import { useAsyncState } from '@vueuse/core'
|
||||||
import { onUnmounted } from 'vue'
|
import { ComputedRef, onUnmounted, toValue } from 'vue'
|
||||||
|
|
||||||
export const useBacklinks = (sha: string) => {
|
export const useBacklinks = (sha: string | ComputedRef<string>) => {
|
||||||
const backlink = useAsyncState(
|
sha = toValue(sha)
|
||||||
|
|
||||||
|
const { state: backlink, execute } = useAsyncState(
|
||||||
data.get<DataType.BacklinkNote, BacklinkNote>(
|
data.get<DataType.BacklinkNote, BacklinkNote>(
|
||||||
data.generateId(DataType.BacklinkNote, sha)
|
data.generateId(DataType.BacklinkNote, sha)
|
||||||
),
|
),
|
||||||
@@ -21,7 +23,7 @@ export const useBacklinks = (sha: string) => {
|
|||||||
if (fileSha !== sha) {
|
if (fileSha !== sha) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
backlink.execute()
|
execute()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
retro: true
|
retro: true
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const useForm = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
push({
|
push({
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
params: {
|
params: {
|
||||||
user: userInput.value,
|
user: userInput.value,
|
||||||
repo: repoInput.value
|
repo: repoInput.value
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import markdownItCheckbox from 'markdown-it-checkbox'
|
|||||||
import markdownItFootnote from 'markdown-it-footnote'
|
import markdownItFootnote from 'markdown-it-footnote'
|
||||||
import markdownItIframe from 'markdown-it-iframe'
|
import markdownItIframe from 'markdown-it-iframe'
|
||||||
import markdownItLatex from 'markdown-it-latex'
|
import markdownItLatex from 'markdown-it-latex'
|
||||||
import markdownItSvgCodeCopy from 'markdown-it-svg-code-copy'
|
|
||||||
|
|
||||||
const md = new MarkdownIt({
|
const md = new MarkdownIt({
|
||||||
typographer: true,
|
typographer: true,
|
||||||
@@ -31,14 +30,6 @@ const md = new MarkdownIt({
|
|||||||
})
|
})
|
||||||
.use(twitterPlugin)
|
.use(twitterPlugin)
|
||||||
.use(markdownItCheckbox)
|
.use(markdownItCheckbox)
|
||||||
.use(markdownItSvgCodeCopy, {
|
|
||||||
svg: `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="36" height="36" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3a47" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
||||||
<rect x="8" y="8" width="10" height="10" rx="2" />
|
|
||||||
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
|
|
||||||
</svg>`,
|
|
||||||
buttonClass: 'button is-light'
|
|
||||||
})
|
|
||||||
.use(markdownItFootnote)
|
.use(markdownItFootnote)
|
||||||
.use(markdownItLatex)
|
.use(markdownItLatex)
|
||||||
.use(markdownItIframe, {
|
.use(markdownItIframe, {
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { NOTE_WIDTH } from '@/constants/note-width'
|
import { NOTE_WIDTH } from '@/constants/note-width'
|
||||||
import { useOverlay } from '@/hooks/useOverlay.hook'
|
import { useOverlay } from '@/hooks/useOverlay.hook'
|
||||||
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
||||||
import { readonly, ref } from 'vue'
|
|
||||||
import { useWindowSize } from '@vueuse/core'
|
import { useWindowSize } from '@vueuse/core'
|
||||||
import { nextTick } from 'vue'
|
import { nextTick, readonly, ref } from 'vue'
|
||||||
|
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
const stackedNotes = ref<string[]>([])
|
const stackedNotes = ref<string[]>([])
|
||||||
@@ -90,7 +88,7 @@ export const useQueryStackedNotes = () => {
|
|||||||
const newStackedNotes = getStackedNotes()
|
const newStackedNotes = getStackedNotes()
|
||||||
|
|
||||||
push({
|
push({
|
||||||
name: currentRoute.value.name ?? 'Home',
|
name: currentRoute.value.name ?? 'FluxNoteView',
|
||||||
params: {
|
params: {
|
||||||
user: store.user,
|
user: store.user,
|
||||||
repo: store.repo
|
repo: store.repo
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ref } from 'vue'
|
|||||||
import { Card } from '../models/Card'
|
import { Card } from '../models/Card'
|
||||||
|
|
||||||
defineProps<{ card: Card }>()
|
defineProps<{ card: Card }>()
|
||||||
const emit = defineEmits<{ success: []; fail: [] }>()
|
const emit = defineEmits<{ success: []; fail: []; needsReview: [] }>()
|
||||||
|
|
||||||
const flipped = ref(false)
|
const flipped = ref(false)
|
||||||
const flip = () => {
|
const flip = () => {
|
||||||
@@ -11,8 +11,8 @@ const flip = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const success = () => emit('success')
|
const success = () => emit('success')
|
||||||
|
|
||||||
const fail = () => emit('fail')
|
const fail = () => emit('fail')
|
||||||
|
const needsReview = () => emit('needsReview')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -27,8 +27,13 @@ const fail = () => emit('fail')
|
|||||||
<div class="actions">
|
<div class="actions">
|
||||||
<p>Did you remember this?</p>
|
<p>Did you remember this?</p>
|
||||||
<div class="buttons is-centered">
|
<div class="buttons is-centered">
|
||||||
<div class="button is-warning" @click.stop="fail">failed</div>
|
<button class="button is-warning" @click.stop="fail">failed</button>
|
||||||
<div class="button is-success" @click.stop="success">got it</div>
|
<button class="button is-success" @click.stop="success">
|
||||||
|
got it
|
||||||
|
</button>
|
||||||
|
<button class="button is-danger" @click.stop="needsReview">
|
||||||
|
<em>needs review</em>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const props = defineProps<{ cards: Repetition[] }>()
|
|||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
success: [id: string]
|
success: [id: string]
|
||||||
fail: [id: string]
|
fail: [id: string]
|
||||||
|
needsReview: [id: string]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const cards = ref(
|
const cards = ref(
|
||||||
@@ -32,6 +33,12 @@ const goToNextCard = (success: boolean) => {
|
|||||||
|
|
||||||
currentIndex.value++
|
currentIndex.value++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const needsReview = () => {
|
||||||
|
const id = cards.value[currentIndex.value].repetition._id ?? ''
|
||||||
|
emits('needsReview', id)
|
||||||
|
currentIndex.value++
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -52,6 +59,7 @@ const goToNextCard = (success: boolean) => {
|
|||||||
:card="card.card"
|
:card="card.card"
|
||||||
@success="goToNextCard(true)"
|
@success="goToNextCard(true)"
|
||||||
@fail="goToNextCard(false)"
|
@fail="goToNextCard(false)"
|
||||||
|
@needs-review="needsReview"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>No more cards to check!</div>
|
<div v-else>No more cards to check!</div>
|
||||||
|
|||||||
22
src/modules/card/hooks/useNeedReviewCards.ts
Normal file
22
src/modules/card/hooks/useNeedReviewCards.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { data } from '@/data/data'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { RepetitionCard } from '@/modules/card/models/RepetitionCard'
|
||||||
|
import { useAsyncState } from '@vueuse/core'
|
||||||
|
|
||||||
|
export const useNeedReviewCards = () => {
|
||||||
|
const { state: cardsToReview, isReady } = useAsyncState(async () => {
|
||||||
|
const repetitions = await data.getAll<
|
||||||
|
DataType.RepetitionCard,
|
||||||
|
RepetitionCard
|
||||||
|
>({
|
||||||
|
prefix: DataType.RepetitionCard
|
||||||
|
})
|
||||||
|
|
||||||
|
return repetitions.filter((repetition) => repetition.needsReview)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
cardsToReview,
|
||||||
|
isReady
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// https://npm.io/package/supermemo
|
// https://npm.io/package/supermemo
|
||||||
|
|
||||||
import { DataType } from '@/data/DataType.enum'
|
|
||||||
import { data } from '@/data/data'
|
import { data } from '@/data/data'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
import { useFile } from '@/hooks/useFile.hook'
|
import { useFile } from '@/hooks/useFile.hook'
|
||||||
import { useLinks } from '@/hooks/useLinks.hook'
|
import { useLinks } from '@/hooks/useLinks.hook'
|
||||||
import { useMarkdown } from '@/hooks/useMarkdown.hook'
|
import { useMarkdown } from '@/hooks/useMarkdown.hook'
|
||||||
@@ -53,12 +53,14 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
>(data.generateId(DataType.RepetitionCard, cardFile.path), {
|
>(data.generateId(DataType.RepetitionCard, cardFile.path), {
|
||||||
$type: DataType.RepetitionCard,
|
$type: DataType.RepetitionCard,
|
||||||
level: 1,
|
level: 1,
|
||||||
repeatDate: new Date()
|
repeatDate: new Date(),
|
||||||
|
needsReview: false
|
||||||
})
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isAfter(new Date(repetition.repeatDate), new Date()) ||
|
isAfter(new Date(repetition.repeatDate), new Date()) ||
|
||||||
repetition.level === MAX_LEVEL
|
repetition.level === MAX_LEVEL ||
|
||||||
|
repetition.needsReview
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -95,6 +97,7 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
|
|
||||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
...repetition,
|
...repetition,
|
||||||
|
needsReview: false,
|
||||||
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
||||||
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
||||||
})
|
})
|
||||||
@@ -113,10 +116,25 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
...repetition,
|
...repetition,
|
||||||
level,
|
level,
|
||||||
|
needsReview: false,
|
||||||
repeatDate: addDays(new Date(), level)
|
repeatDate: addDays(new Date(), level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const needsReview = async (cardId: string) => {
|
||||||
|
const repetition = await data.get<DataType.RepetitionCard, RepetitionCard>(
|
||||||
|
cardId
|
||||||
|
)
|
||||||
|
if (!repetition) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
|
...repetition,
|
||||||
|
needsReview: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
cards,
|
cards,
|
||||||
() =>
|
() =>
|
||||||
@@ -128,5 +146,11 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
|
|
||||||
watch(cardFiles, () => execute())
|
watch(cardFiles, () => execute())
|
||||||
|
|
||||||
return { cards, successRepetition, failRepetition, isLoading: !isReady }
|
return {
|
||||||
|
cards,
|
||||||
|
successRepetition,
|
||||||
|
failRepetition,
|
||||||
|
needsReview,
|
||||||
|
isLoading: !isReady
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ import { Model } from '@/data/models/Model'
|
|||||||
export interface RepetitionCard extends Model<DataType.RepetitionCard> {
|
export interface RepetitionCard extends Model<DataType.RepetitionCard> {
|
||||||
level: number
|
level: number
|
||||||
repeatDate: Date
|
repeatDate: Date
|
||||||
|
needsReview: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: `Home`,
|
name: `FluxNoteView`,
|
||||||
params: { user: lastVisitedRepo.user, repo: lastVisitedRepo.repo }
|
params: { user: lastVisitedRepo.user, repo: lastVisitedRepo.repo }
|
||||||
}"
|
}"
|
||||||
>{{ lastVisitedRepo.user }}/{{ lastVisitedRepo.repo }}</router-link
|
>{{ lastVisitedRepo.user }}/{{ lastVisitedRepo.repo }}</router-link
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { resolvePath } from '@/modules/repo/services/resolvePath'
|
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { resolvePath } from './resolvePath'
|
||||||
|
|
||||||
describe('resolve path service', () => {
|
describe('resolve path service', () => {
|
||||||
it('set the absolute path if path to resolve is empty', () => {
|
it('set the absolute path if path to resolve is empty', () => {
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router'
|
|
||||||
|
|
||||||
import Home from '@/views/HomeApp.vue'
|
import Home from '@/views/HomeApp.vue'
|
||||||
|
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
@@ -9,10 +8,10 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('@/views/RepoList.vue')
|
component: () => import('@/views/RepoList.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:user?/:repo?',
|
path: '/:user/:repo',
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
props: true,
|
props: true,
|
||||||
component: Home
|
component: () => import('@/views/FluxNoteView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:user/:repo/share/:note',
|
path: '/:user/:repo/share/:note',
|
||||||
@@ -44,11 +43,22 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
props: true,
|
props: true,
|
||||||
component: () => import('@/views/SpacedRepetitionCard.vue')
|
component: () => import('@/views/SpacedRepetitionCard.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/:user/:repo/need-review-cards',
|
||||||
|
name: 'NeedReviewCards',
|
||||||
|
props: true,
|
||||||
|
component: () => import('@/views/NeedReviewCards.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
name: 'About',
|
name: 'About',
|
||||||
component: () => import('@/views/AboutApp.vue')
|
component: () => import('@/views/AboutApp.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'Home',
|
||||||
|
component: Home
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/:catchAll(.*)',
|
path: '/:catchAll(.*)',
|
||||||
name: 'SpaceCowboy',
|
name: 'SpaceCowboy',
|
||||||
|
|||||||
16
src/views/FluxNoteView.vue
Normal file
16
src/views/FluxNoteView.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import FluxNote from '@/components/FluxNote.vue'
|
||||||
|
import { useComputeBacklinks } from '@/hooks/useComputeBacklinks.hook'
|
||||||
|
import { useQueryStackedNotes } from '@/hooks/useQueryStackedNotes.hook'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
useQueryStackedNotes()
|
||||||
|
useComputeBacklinks()
|
||||||
|
|
||||||
|
const props = defineProps<{ user: string; repo: string }>()
|
||||||
|
const routeKey = computed(() => `${props.user}-${props.repo}`)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<flux-note :key="routeKey" :user="user" :repo="repo" />
|
||||||
|
</template>
|
||||||
@@ -1,28 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AuthorizeUser from '@/components/AuthorizeUser.vue'
|
import AuthorizeUser from '@/components/AuthorizeUser.vue'
|
||||||
import { useComputeBacklinks } from '@/hooks/useComputeBacklinks.hook'
|
import WelcomeWorld from '@/components/WelcomeWorld.vue'
|
||||||
import { useQueryStackedNotes } from '@/hooks/useQueryStackedNotes.hook'
|
|
||||||
import { computed, defineAsyncComponent } from 'vue'
|
|
||||||
|
|
||||||
const FluxNote = defineAsyncComponent(() => import('@/components/FluxNote.vue'))
|
|
||||||
|
|
||||||
const WelcomeWorld = defineAsyncComponent(
|
|
||||||
() => import('@/components/WelcomeWorld.vue')
|
|
||||||
)
|
|
||||||
|
|
||||||
const props = defineProps<{ user?: string; repo?: string }>()
|
|
||||||
|
|
||||||
useQueryStackedNotes()
|
|
||||||
useComputeBacklinks()
|
|
||||||
const routeKey = computed(() => `${props.user}-${props.repo}`)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!user || !repo" class="home content">
|
<div class="home content">
|
||||||
<authorize-user class="authorize" />
|
<authorize-user class="authorize" />
|
||||||
<welcome-world />
|
<welcome-world />
|
||||||
</div>
|
</div>
|
||||||
<flux-note v-else :key="routeKey" :user="user" :repo="repo" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
38
src/views/NeedReviewCards.vue
Normal file
38
src/views/NeedReviewCards.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import FluxNote from '@/components/FluxNote.vue'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { useNeedReviewCards } from '@/modules/card/hooks/useNeedReviewCards'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
user: string
|
||||||
|
repo: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { cardsToReview } = useNeedReviewCards()
|
||||||
|
const cardNames = computed(() =>
|
||||||
|
cardsToReview.value.map((card) => ({
|
||||||
|
id: card._id,
|
||||||
|
name: card._id?.split(DataType.RepetitionCard).pop()
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="needs-review-cards">
|
||||||
|
<flux-note
|
||||||
|
key="needs-review-cards"
|
||||||
|
class="card-container"
|
||||||
|
:user="user"
|
||||||
|
:repo="repo"
|
||||||
|
:with-content="false"
|
||||||
|
>
|
||||||
|
needs review cards
|
||||||
|
<ul>
|
||||||
|
<li v-for="card in cardNames" :key="card.id">
|
||||||
|
{{ card.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</flux-note>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
params: { user: username, repo: repo.name }
|
params: { user: username, repo: repo.name }
|
||||||
}"
|
}"
|
||||||
>{{ repo.name }}</router-link
|
>{{ repo.name }}</router-link
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'Home',
|
name: 'FluxNoteView',
|
||||||
params: { user: username, repo: repo.name }
|
params: { user: username, repo: repo.name }
|
||||||
}"
|
}"
|
||||||
>{{ repo.name }}</router-link
|
>{{ repo.name }}</router-link
|
||||||
@@ -77,11 +77,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
|
||||||
import { useRepoList } from '@/modules/repo/hooks/useRepoList.hook'
|
|
||||||
import { useRepos } from '@/hooks/useRepos.hook'
|
|
||||||
import GoBack from '@/components/GoBack.vue'
|
import GoBack from '@/components/GoBack.vue'
|
||||||
|
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
||||||
|
import { useRepos } from '@/hooks/useRepos.hook'
|
||||||
|
import { useRepoList } from '@/modules/repo/hooks/useRepoList.hook'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'RepoList',
|
name: 'RepoList',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ defineProps<{
|
|||||||
repo: string
|
repo: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { cards, isLoading, successRepetition, failRepetition } =
|
const { cards, isLoading, successRepetition, failRepetition, needsReview } =
|
||||||
useSpacedRepetitionCards()
|
useSpacedRepetitionCards()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -27,9 +27,13 @@ const { cards, isLoading, successRepetition, failRepetition } =
|
|||||||
:cards="cards"
|
:cards="cards"
|
||||||
@success="successRepetition"
|
@success="successRepetition"
|
||||||
@fail="failRepetition"
|
@fail="failRepetition"
|
||||||
|
@needs-review="needsReview"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section v-else>No cards to review!</section>
|
<section v-else>No cards to review!</section>
|
||||||
|
<router-link :to="{ name: 'NeedReviewCards', params: { user, repo } }">
|
||||||
|
needs review cards
|
||||||
|
</router-link>
|
||||||
</flux-note>
|
</flux-note>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -18,12 +18,6 @@
|
|||||||
},
|
},
|
||||||
"lib": ["esnext", "dom", "dom.iterable", "scripthost", "ES2015"]
|
"lib": ["esnext", "dom", "dom.iterable", "scripthost", "ES2015"]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.tsx",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"tests/**/*.ts",
|
|
||||||
"tests/**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user