before suspend
This commit is contained in:
parent
8fab301419
commit
aec0b4356a
18
.eslintrc
18
.eslintrc
|
@ -11,7 +11,8 @@
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"browser": true
|
"browser": true,
|
||||||
|
"vue/setup-compiler-macros": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"semi": [
|
"semi": [
|
||||||
|
@ -23,11 +24,22 @@
|
||||||
"error",
|
"error",
|
||||||
"tab"
|
"tab"
|
||||||
],
|
],
|
||||||
"vue/html-closing-bracket-spacing": ["error", {
|
"vue/html-closing-bracket-spacing": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
"startTag": "never",
|
"startTag": "never",
|
||||||
"endTag": "never",
|
"endTag": "never",
|
||||||
"selfClosingTag": "never"
|
"selfClosingTag": "never"
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
|
"vue/component-api-style": [
|
||||||
|
"error",
|
||||||
|
[
|
||||||
|
"script-setup",
|
||||||
|
"composition"
|
||||||
|
]
|
||||||
|
// "script-setup", "composition", "composition-vue2", or "options"
|
||||||
|
],
|
||||||
"indent": [
|
"indent": [
|
||||||
"error",
|
"error",
|
||||||
"tab"
|
"tab"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
- use quill vue
|
||||||
|
- add linenumbering
|
||||||
|
- add yntax highlighning
|
||||||
|
|
||||||
|
- pinia
|
||||||
|
- harden Api-Platform
|
||||||
|
- learn tailwind
|
||||||
|
|
|
@ -2,20 +2,18 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<nav-bar
|
<the-navbar
|
||||||
:user="user"
|
@invalidate-user="onUserInvalidate"
|
||||||
@invalidate-user="onInvalidateUser"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-5 main-content">
|
<div class="row mt-5 main-content">
|
||||||
<div class="col-xl-3">
|
<div class="col-xl-3">
|
||||||
<sidebar/>
|
<the-sidebar/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-9">
|
<div class="col-xl-9">
|
||||||
<router-view
|
<router-view
|
||||||
:quote="quote"
|
|
||||||
@user-authenticated="onUserAuthenticated"
|
@user-authenticated="onUserAuthenticated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,58 +22,41 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<footer-component/>
|
<the-footer/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
//import RouterView from 'vue-router'
|
||||||
|
import TheNavbar from '@/components/TheNavbar'
|
||||||
|
import TheSidebar from '@/components/TheSidebar'
|
||||||
|
import TheFooter from '@/components/TheFooter'
|
||||||
|
|
||||||
import routerView from 'vue-router'
|
|
||||||
import NavBar from '@/components/TheNavbar'
|
|
||||||
import Sidebar from '@/components/TheSidebar'
|
|
||||||
import FooterComponent from '@/components/TheFooter'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'App',
|
|
||||||
components: {
|
|
||||||
routerView,
|
|
||||||
Sidebar,
|
|
||||||
NavBar,
|
|
||||||
FooterComponent
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
user: null,
|
|
||||||
quote: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
if (window.user) {
|
if (window.user) {
|
||||||
this.user = window.user
|
const { user } = window
|
||||||
console.log(this.user)
|
|
||||||
}
|
}
|
||||||
if (window.quote) {
|
if (window.quote) {
|
||||||
this.quote = window.quote
|
const { quote } = window
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
const onUserAuthenticated = (userUri) => {
|
||||||
onUserAuthenticated(userUri) {
|
//console.log('authenticated')
|
||||||
console.log('authenticated')
|
|
||||||
axios
|
axios
|
||||||
.get(userUri)
|
.get(userUri)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.user = response.data
|
this.user = response.data
|
||||||
})
|
})
|
||||||
this.$router.push('/')
|
this.$router.push('/')
|
||||||
},
|
}
|
||||||
onInvalidateUser() {
|
|
||||||
console.log('invalidated')
|
const onUserInvalidate = () => {
|
||||||
|
//console.log('invalidated')
|
||||||
this.user = null
|
this.user = null
|
||||||
window.user = null
|
window.user = null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
v-else
|
v-else
|
||||||
v-bind="$props"
|
:to="{ name: props.to }"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
:class="`fa fa-lg fa-fw ${fa}`"
|
:class="`fa fa-lg fa-fw ${fa}`"
|
||||||
|
@ -29,21 +29,20 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
import { RouterLink } from 'vue-router'
|
import { RouterLink } from 'vue-router'
|
||||||
|
|
||||||
export default {
|
const props = defineProps({
|
||||||
props: {
|
to: {
|
||||||
...RouterLink.props,
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
fa: {
|
fa: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
computed: {
|
|
||||||
isExternal() {
|
const isExternal = computed(() => props.to.startsWith('http'))
|
||||||
return typeof this.to === 'string' && this.to.startsWith('http')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<div class="container box">
|
<div class="container box">
|
||||||
<form @submit.prevent="handleSubmit">
|
<form @submit.prevent="handleSubmit">
|
||||||
<div
|
<div
|
||||||
v-if="error"
|
v-if="errorMessage"
|
||||||
class="alert alert-danger"
|
class="alert alert-danger mt-2"
|
||||||
>
|
>
|
||||||
{{ error }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-2">
|
<div class="form-group mt-2">
|
||||||
<label for="exampleInputEmail1">Username</label>
|
<label for="exampleInputEmail1">Username</label>
|
||||||
|
@ -52,58 +52,45 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { ref, defineEmits } from 'vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
const username = ref('')
|
||||||
name: 'LoginForm',
|
const password = ref('')
|
||||||
/*
|
const errorMessage = ref('')
|
||||||
props: {
|
const isLoading = ref(false)
|
||||||
user: {
|
const emit = defineEmits(['user-authenticated'])
|
||||||
Type: Object
|
|
||||||
}
|
const handleSubmit = () => {
|
||||||
},
|
//console.log('handle submit')
|
||||||
*/
|
isLoading.value = true
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
error: '',
|
|
||||||
isLoading: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleSubmit() {
|
|
||||||
console.log('handle submit')
|
|
||||||
this.isLoading = true
|
|
||||||
this.error = ''
|
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.post('/login', {
|
.post('/login', {
|
||||||
username: this.username,
|
username: username.value,
|
||||||
password: this.password
|
password: password.value
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log(response.headers)
|
//console.log(response.headers)
|
||||||
|
|
||||||
this.$emit('user-authenticated', response.headers.location)
|
emit('user-authenticated', response.headers.location)
|
||||||
this.username = ''
|
username.value = ''
|
||||||
this.password = ''
|
password.value = ''
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
console.log(error)
|
||||||
console.log(error.response.data)
|
console.log(error.response.data)
|
||||||
if (error.response.data.error) {
|
if (error.response.data.error) {
|
||||||
this.error = error.response.data.error
|
errorMessage.value = error.response.data.error
|
||||||
} else {
|
} else {
|
||||||
this.error = 'Unknown error'
|
errorMessage.value = 'Unknown error'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.isLoading = false
|
isLoading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
Bio:
|
||||||
|
|
||||||
|
Symfonycast
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TheAbout'
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -14,6 +14,14 @@
|
||||||
alt="Spookie"
|
alt="Spookie"
|
||||||
>
|
>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<div>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'About'}"
|
||||||
|
class="d-inline-block mx-auto"
|
||||||
|
>
|
||||||
|
About Me
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col md-4 text-left">
|
<div class="col md-4 text-left">
|
||||||
|
|
|
@ -116,37 +116,30 @@
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import 'vue-navigation-bar/dist/vue-navigation-bar.css'
|
import 'vue-navigation-bar/dist/vue-navigation-bar.css'
|
||||||
|
|
||||||
export default {
|
const props = defineProps({
|
||||||
name: 'TheNavbar',
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
user: {
|
user: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null
|
default() {
|
||||||
|
return {
|
||||||
|
username: 'tracer'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
data: () => ({}),
|
|
||||||
computed: {
|
|
||||||
isLoggedIn() {
|
|
||||||
return !!this.user
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {
|
})
|
||||||
logout() {
|
|
||||||
console.log('logout')
|
const isLoggedIn = () => (!!this.user)
|
||||||
|
|
||||||
|
/*
|
||||||
|
const logout = () => ({
|
||||||
axios
|
axios
|
||||||
.get('/logout')
|
.get('/logout')
|
||||||
.then(this.$emit('invalidate-user'))
|
.then(this.$emit('invalidate-user'))
|
||||||
}
|
|
||||||
|
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -30,6 +30,11 @@ export default {
|
||||||
url: 'Projects',
|
url: 'Projects',
|
||||||
fa: 'fa-file-code-o',
|
fa: 'fa-file-code-o',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Blog',
|
||||||
|
url: 'Blog',
|
||||||
|
fa: 'fa-file-text-o',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Gitea',
|
name: 'Gitea',
|
||||||
url: 'https://git.24unix.net',
|
url: 'https://git.24unix.net',
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
flex
|
||||||
|
m-2
|
||||||
|
gap-2
|
||||||
|
items-center
|
||||||
|
shadow-md
|
||||||
|
w-1/4
|
||||||
|
flex-grow
|
||||||
|
rounded
|
||||||
|
overflow-hidden
|
||||||
|
"
|
||||||
|
style="border: 1px solid #eee"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="https://via.placeholder.com/150"
|
||||||
|
style="background: #cccccc"
|
||||||
|
width="150"
|
||||||
|
height="150"
|
||||||
|
alt="placeholder"
|
||||||
|
>
|
||||||
|
<router-link :to="{ name: 'BlogPost', params: { id: post.id } }">
|
||||||
|
{{ post.title }}<br>
|
||||||
|
User: {{ post.userId }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
console.log('BlogCard')
|
||||||
|
const props = defineProps({
|
||||||
|
post: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const post = { ...props.post }
|
||||||
|
</script>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
flex
|
||||||
|
m-2
|
||||||
|
gap-2
|
||||||
|
items-center
|
||||||
|
shadow-md
|
||||||
|
w-1/4
|
||||||
|
flex-grow
|
||||||
|
rounded
|
||||||
|
overflow-hidden
|
||||||
|
"
|
||||||
|
style="border: 1px solid #eee"
|
||||||
|
>
|
||||||
|
BlogIndex
|
||||||
|
|
||||||
|
<BlogCard
|
||||||
|
v-for="post in blogPosts"
|
||||||
|
:key="post.id"
|
||||||
|
:post="post"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import useResource from '@/composables/useResource'
|
||||||
|
//import useUser from '@/composables/useUser'
|
||||||
|
import BlogCard from '@/components/blog/BlogCard'
|
||||||
|
|
||||||
|
const { items: blogPosts, fetchAll } = useResource('https://jsonplaceholder.typicode.com/posts')
|
||||||
|
fetchAll()
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="blogPost"
|
||||||
|
class="
|
||||||
|
flex
|
||||||
|
m-2
|
||||||
|
gap-2
|
||||||
|
items-center
|
||||||
|
shadow-md
|
||||||
|
w-1/4
|
||||||
|
flex-grow
|
||||||
|
rounded
|
||||||
|
overflow-hidden
|
||||||
|
"
|
||||||
|
style="border: 1px solid #eee"
|
||||||
|
>
|
||||||
|
BlogIPost
|
||||||
|
<img
|
||||||
|
src="https://via.placeholder.com/150"
|
||||||
|
style="background: #cccccc"
|
||||||
|
width="150"
|
||||||
|
height="150"
|
||||||
|
alt="placeholder"
|
||||||
|
>
|
||||||
|
user {{ blogPost.userId }}:
|
||||||
|
<div v-if="user">
|
||||||
|
"{{ user.name }}
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{{ blogPost.title }}<br>
|
||||||
|
{{ blogPost.body }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { watch } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import useResource from '@/composables/useResource'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const { item: blogPost, fetchOne: fetchOneBlog } = useResource('https://jsonplaceholder.typicode.com/posts')
|
||||||
|
fetchOneBlog(route.params.id)
|
||||||
|
|
||||||
|
const { item: user, fetchOne: fetchOneUser } = useResource('https://jsonplaceholder.typicode.com/users')
|
||||||
|
watch(
|
||||||
|
() => ({ ...blogPost.value }),
|
||||||
|
() => fetchOneUser(blogPost.value.userId)
|
||||||
|
)
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<template>
|
||||||
|
<div class="box ma7 p-5">
|
||||||
|
<h2
|
||||||
|
v-if="page"
|
||||||
|
v-html="page.name"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="page"
|
||||||
|
v-html="page.content"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<router-link
|
||||||
|
:to="editTarget"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<button>
|
||||||
|
<i class="fa fa-2x fa-fw fa-edit"/>
|
||||||
|
</button>
|
||||||
|
</router-link>
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, watchEffect, computed } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
//import h from 'highlightjs'
|
||||||
|
//import hi from 'highlightjs-line-numbers.js'
|
||||||
|
|
||||||
|
//hi.highlightAll()
|
||||||
|
//hi.initLineNumbersOnLoad()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
slug: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let page = reactive({ name: '', slug: '' })
|
||||||
|
|
||||||
|
const editTarget = computed(() => {
|
||||||
|
if (page) {
|
||||||
|
return `/pages/edit/${page.slug}`
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const getPagesDetails = async (slug) => {
|
||||||
|
console.log('get page details')
|
||||||
|
await axios.get(`/api/pages?slug=${slug}`)
|
||||||
|
.then((response) => {
|
||||||
|
page = response.data['hydra:member']
|
||||||
|
console.log(page)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// watch fpr slug
|
||||||
|
watchEffect(() => getPagesDetails(props.slug))
|
||||||
|
</script>
|
|
@ -6,22 +6,13 @@
|
||||||
<tabs-group @tabActivated="tabActivated">
|
<tabs-group @tabActivated="tabActivated">
|
||||||
<tab-content title="Visual Editor">
|
<tab-content title="Visual Editor">
|
||||||
<div class="editor mt-2">
|
<div class="editor mt-2">
|
||||||
<VueEditor
|
<QuillEditor
|
||||||
v-model="page.content"
|
ref="editor"
|
||||||
:editor-options="editorOptions"
|
theme="snow"
|
||||||
|
:content="JSON.parse(page.content)"
|
||||||
|
:options="editorOptions"
|
||||||
:disabled="isVueEditorDisabled"
|
:disabled="isVueEditorDisabled"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</tab-content>
|
|
||||||
<tab-content title="Raw Content">
|
|
||||||
<div>
|
|
||||||
<textarea
|
|
||||||
v-model="page.content"
|
|
||||||
class="p-fluid pages-editor-raw"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</tab-content>
|
|
||||||
</tabs-group>
|
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary mt-3 mb-2"
|
class="btn btn-primary mt-3 mb-2"
|
||||||
@click="saveContent"
|
@click="saveContent"
|
||||||
|
@ -29,6 +20,44 @@
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</tab-content>
|
||||||
|
<tab-content title="Preview">
|
||||||
|
<div class="preview mt-2 no-overflow">
|
||||||
|
<QuillEditor
|
||||||
|
ref="preview"
|
||||||
|
theme="bubble"
|
||||||
|
class="no-overflow"
|
||||||
|
:content="JSON.parse(page.content)"
|
||||||
|
:options="editorOptions"
|
||||||
|
:disabled="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<div>
|
||||||
|
<textarea
|
||||||
|
v-model="page.content"
|
||||||
|
class="p-fluid pages-editor-raw"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</tab-content>
|
||||||
|
<tab-content title="Delta">
|
||||||
|
<div class="editor mt-2">
|
||||||
|
<textarea
|
||||||
|
ref="delta"
|
||||||
|
v-model="page.content"
|
||||||
|
class="p-fluid pages-editor-raw"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn btn-primary mt-3 mb-2"
|
||||||
|
@click="saveDelta"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</tab-content>
|
||||||
|
</tabs-group>
|
||||||
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||||
<span class="sr-only">Loading …</span>
|
<span class="sr-only">Loading …</span>
|
||||||
|
@ -39,20 +68,31 @@
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// Basic Use - Covers most scenarios
|
import 'highlight.js/styles/tomorrow-night-blue.css'
|
||||||
// https://github.com/davidroyer/vue2-editor => docs apply for version 3, too
|
import hljs from 'highlight.js'
|
||||||
import { VueEditor } from 'vue3-editor'
|
|
||||||
|
|
||||||
import hljs from 'highlightjs'
|
//import Quill from 'quill'
|
||||||
import 'highlightjs/styles/dracula.css'
|
import { Quill, QuillEditor } from '@vueup/vue-quill'
|
||||||
|
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||||
|
import '@vueup/vue-quill/dist/vue-quill.bubble.css'
|
||||||
|
|
||||||
|
import htmlEditButton from 'quill-html-edit-button'
|
||||||
|
|
||||||
import TabsGroup from '@/components/tabs/TabsGroup'
|
import TabsGroup from '@/components/tabs/TabsGroup'
|
||||||
import TabContent from '@/components/tabs/TabContent'
|
import TabContent from '@/components/tabs/TabContent'
|
||||||
|
|
||||||
|
Quill
|
||||||
|
// .register('modules/syntax', syntax, false)
|
||||||
|
.register('modules/htmlEditButton', htmlEditButton)
|
||||||
|
|
||||||
|
hljs.configure({
|
||||||
|
languages: ['javascript', 'php', 'swift']
|
||||||
|
})
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PagesEdit',
|
name: 'PagesEdit',
|
||||||
components: {
|
components: {
|
||||||
VueEditor,
|
QuillEditor,
|
||||||
TabsGroup,
|
TabsGroup,
|
||||||
TabContent
|
TabContent
|
||||||
},
|
},
|
||||||
|
@ -62,12 +102,15 @@ export default {
|
||||||
isVueEditorDisabled: false,
|
isVueEditorDisabled: false,
|
||||||
editorOptions: {
|
editorOptions: {
|
||||||
modules: {
|
modules: {
|
||||||
|
htmlEditButton: {
|
||||||
|
debug: true
|
||||||
|
},
|
||||||
syntax: {
|
syntax: {
|
||||||
highlight: (text) => hljs.highlightAuto(text).value
|
highlight: (text) => hljs.highlightAuto(text).value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
theme: 'snow'
|
theme: 'snow'
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
const { slug } = this.$route.params
|
const { slug } = this.$route.params
|
||||||
|
@ -81,13 +124,24 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
saveContent() {
|
saveContent() {
|
||||||
|
this.page.content = JSON.stringify(this.$refs.editor.getContents())
|
||||||
axios
|
axios
|
||||||
.put(`/api/pages/${this.page.id}`, this.page)
|
.put(`/api/pages/${this.page.id}`, this.page)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$router.push({
|
//this.$router.push({
|
||||||
name: 'Pages',
|
// name: 'Pages',
|
||||||
params: { slug: this.page.slug }
|
// params: { slug: this.page.slug }
|
||||||
|
//})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
saveDelta() {
|
||||||
|
axios
|
||||||
|
.put(`/api/pages/${this.page.id}`, this.page)
|
||||||
|
.then(() => {
|
||||||
|
//this.$router.push({
|
||||||
|
// name: 'Pages',
|
||||||
|
// params: { slug: this.page.slug }
|
||||||
|
//})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
tabActivated(name) {
|
tabActivated(name) {
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="box ma7 p-5">
|
|
||||||
<h2
|
|
||||||
v-if="page"
|
|
||||||
v-html="page.name"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-if="page"
|
|
||||||
v-html="page.content"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<router-link
|
|
||||||
:to="editTarget"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
<button>
|
|
||||||
<i class="fa fa-2x fa-fw fa-edit"/>
|
|
||||||
</button>
|
|
||||||
</router-link>
|
|
||||||
<hr>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
//import h from 'highlightjs'
|
|
||||||
//import hi from 'highlightjs-line-numbers.js'
|
|
||||||
|
|
||||||
//hi.highlightAll()
|
|
||||||
//hi.initLineNumbersOnLoad()
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'PagesDisplay',
|
|
||||||
props: {
|
|
||||||
slug: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: () => ({
|
|
||||||
page: null
|
|
||||||
}),
|
|
||||||
computed: {
|
|
||||||
editTarget() {
|
|
||||||
if (this.page) {
|
|
||||||
return `/pages/edit/${this.page.slug}`
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
this.getPagesDetails()
|
|
||||||
this.$watch(
|
|
||||||
() => this.slug,
|
|
||||||
() => {
|
|
||||||
this.getPagesDetails()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async getPagesDetails() {
|
|
||||||
await axios.get(`/api/pages?slug=${this.slug}`)
|
|
||||||
.then((response) => {
|
|
||||||
[this.page] = response.data['hydra:member']
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -5,6 +5,7 @@
|
||||||
v-for="title in tabTitles"
|
v-for="title in tabTitles"
|
||||||
:key="title"
|
:key="title"
|
||||||
:class="{ selected: title === selectedTitle }"
|
:class="{ selected: title === selectedTitle }"
|
||||||
|
class="btn"
|
||||||
@click="handleClick(title)"
|
@click="handleClick(title)"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
@ -39,7 +40,9 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
|
|
||||||
|
@import "~styles/app.scss";
|
||||||
.tabs {
|
.tabs {
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -56,15 +59,20 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
background-color: #ddd;
|
background-color: #2e2e2e;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: black;
|
color: #999999;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: 0.4s all ease-out;
|
transition: 0.4s all ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-header li.selected {
|
.tabs-header li.selected {
|
||||||
background-color: #0984e3;
|
background-color: $primary;
|
||||||
color: white;
|
color: $jet-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs-header li.selected:hover {
|
||||||
|
border-color: $body-color;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -50,36 +50,38 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
const user = reactive(null)
|
||||||
name: 'ProfileView',
|
const isLoading = ref(true)
|
||||||
data: () => ({
|
const router = useRouter()
|
||||||
user: null,
|
const route = useRoute()
|
||||||
isLoading: true
|
|
||||||
}),
|
|
||||||
computed: {
|
|
||||||
getUserEndpoint() {
|
|
||||||
if (this.$route.params.username) {
|
|
||||||
return `/api/users?username=${this.$route.params.username}`
|
|
||||||
}
|
|
||||||
return '/api/users?username=tracer'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
axios
|
|
||||||
.get(this.getUserEndpoint)
|
|
||||||
.then((response) => {
|
|
||||||
console.log(response);
|
|
||||||
[this.user] = response.data['hydra:member']
|
|
||||||
|
|
||||||
console.log(this.user)
|
// if there is no param, we go to our own profile, elso to the login
|
||||||
this.isLoading = false
|
|
||||||
})
|
if (route.params.username) {
|
||||||
.catch((error) => {
|
console.log('we have the username')
|
||||||
console.log(error)
|
} else if (window.user) {
|
||||||
})
|
console.log(window.user)
|
||||||
}
|
} else {
|
||||||
|
router.push({ name: 'LoginForm' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userEndpoint = '/api/users?username=tracer'
|
||||||
|
axios
|
||||||
|
.get(userEndpoint)
|
||||||
|
.then((response) => {
|
||||||
|
//console.log(response);
|
||||||
|
[user.value] = response.data['hydra:member']
|
||||||
|
|
||||||
|
//console.log(this.user)
|
||||||
|
isLoading.value = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
//console.log(error)
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default function useResource(resource) {
|
||||||
|
console.log('useBlog')
|
||||||
|
const items = ref([])
|
||||||
|
const item = ref(null)
|
||||||
|
const fetchAll = async () => {
|
||||||
|
await axios
|
||||||
|
.get(resource)
|
||||||
|
.then((response) => {
|
||||||
|
items.value = response.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const fetchOne = async (id) => {
|
||||||
|
console.log('fetchOne', id)
|
||||||
|
await axios
|
||||||
|
.get(`${resource}/${id}`)
|
||||||
|
.then((response) => {
|
||||||
|
item.value = response.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
items,
|
||||||
|
fetchAll,
|
||||||
|
item,
|
||||||
|
fetchOne
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,11 @@ import 'bootstrap/dist/js/bootstrap'
|
||||||
|
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
import VueHighLightJS from 'vue3-highlightjs'
|
//import { QuillEditor } from '@vueup/vue-quill'
|
||||||
import 'vue3-highlightjs/styles/dracula.css'
|
//import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||||
|
//import '@vueup/vue-quill/dist/vue-quill.bubble.css'
|
||||||
|
|
||||||
import Router from '@/router'
|
import router from '@/router'
|
||||||
import AppLink from '@/components/AppLink'
|
import AppLink from '@/components/AppLink'
|
||||||
import App from '@/App'
|
import App from '@/App'
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ _paq.push(['enableLinkTracking']);
|
||||||
|
|
||||||
createApp(App)
|
createApp(App)
|
||||||
.component('AppLink', AppLink)
|
.component('AppLink', AppLink)
|
||||||
|
// .component('QuillEditor', QuillEditor)
|
||||||
.use(createPinia())
|
.use(createPinia())
|
||||||
.use(VueHighLightJS)
|
.use(router)
|
||||||
.use(Router)
|
|
||||||
.mount('#app')
|
.mount('#app')
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import LoginForm from '@/components/LoginForm'
|
import LoginForm from '@/components/LoginForm'
|
||||||
import Quotes from '@/components/quotes'
|
import Quotes from '@/components/quotes'
|
||||||
import Pages from '@/components/pages'
|
import Pages from '@/components/pages/PagesIndex'
|
||||||
import PagesEdit from '@/components/pages/edit'
|
import PagesEdit from '@/components/pages/edit'
|
||||||
import ProjectsList from '@/components/projects'
|
import ProjectsList from '@/components/projects'
|
||||||
import ProjectsDetails from '@/components/projects/ProjectDetails'
|
import ProjectsDetails from '@/components/projects/ProjectDetails'
|
||||||
|
import BlogIndex from '@/components/blog/BlogIndex'
|
||||||
|
import BlogPost from '@/components/blog/BlogPost'
|
||||||
import ProfileView from '@/components/users/ProfileView'
|
import ProfileView from '@/components/users/ProfileView'
|
||||||
|
import TheAbout from '@/components/TheAbout'
|
||||||
import NotFound from '@/components/NotFound'
|
import NotFound from '@/components/NotFound'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
|
@ -14,6 +17,11 @@ const routes = [
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: Quotes
|
component: Quotes
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/about',
|
||||||
|
name: 'About',
|
||||||
|
component: TheAbout
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/form_login',
|
path: '/form_login',
|
||||||
name: 'LoginForm',
|
name: 'LoginForm',
|
||||||
|
@ -29,6 +37,16 @@ const routes = [
|
||||||
name: 'ProjectDetails',
|
name: 'ProjectDetails',
|
||||||
component: ProjectsDetails
|
component: ProjectsDetails
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/blog',
|
||||||
|
name: 'Blog',
|
||||||
|
component: BlogIndex
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/blog/post/:id',
|
||||||
|
name: 'BlogPost',
|
||||||
|
component: BlogPost
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/pages/:slug',
|
path: '/pages/:slug',
|
||||||
name: 'Pages',
|
name: 'Pages',
|
||||||
|
@ -57,10 +75,12 @@ const router = createRouter({
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
/* eslint-disable */
|
/*
|
||||||
router.beforeEach((to) => {
|
router.beforeEach((to) => {
|
||||||
if (to.meta.requiredAuth && !window.user) {
|
if (to.meta.requiredAuth && !window.user) {
|
||||||
return { name: 'LoginForm' }
|
return { name: 'LoginForm' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
*/
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -68,6 +68,11 @@ $mango: #FF8040;
|
||||||
height: 650px !important;
|
height: 650px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-overflow {
|
||||||
|
overflow-y: visible !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
.ql-syntax {
|
.ql-syntax {
|
||||||
background-color: #222222;
|
background-color: #222222;
|
||||||
border: 1px solid #888;
|
border: 1px solid #888;
|
||||||
|
@ -85,11 +90,37 @@ $mango: #FF8040;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ql-editor {
|
||||||
|
counter-reset: line;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor div:before {
|
||||||
|
counter-increment: line;
|
||||||
|
content: counter(line);
|
||||||
|
display: inline-block;
|
||||||
|
border-right: 1px solid red;
|
||||||
|
padding: 0 .5em;
|
||||||
|
margin-right: .5em;
|
||||||
|
color: #888
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-syntax pre:before {
|
||||||
|
counter-increment: line;
|
||||||
|
content: counter(line);
|
||||||
|
display: inline-block;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
padding: 2px .5em;
|
||||||
|
margin-right: .5em;
|
||||||
|
color: #888
|
||||||
|
}
|
||||||
|
/*
|
||||||
pre span.hljs-tag::before, span.hljs-attr::before {
|
pre span.hljs-tag::before, span.hljs-attr::before {
|
||||||
content: "xxx";
|
content: "xxx";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|
14
package.json
14
package.json
|
@ -26,28 +26,26 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||||
|
"@vueup/vue-quill": "^1.0.0-beta.8",
|
||||||
"axios": "^0.27.1",
|
"axios": "^0.27.1",
|
||||||
"bootsdark": "^1.0.16",
|
"bootsdark": "^1.0.16",
|
||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"ckeditor": "^4.12.1",
|
"eslint": "^8.15.0",
|
||||||
"ckeditor4": "^4.18.0",
|
|
||||||
"eslint": "^8.14.0",
|
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-vue": "^8.7.1",
|
"eslint-plugin-vue": "^8.7.1",
|
||||||
"fork-awesome": "^1.2.0",
|
"fork-awesome": "^1.2.0",
|
||||||
"highlightjs": "^9.16.2",
|
"highlight.js": "^11.5.1",
|
||||||
"highlightjs-line-numbers.js": "^2.8.0",
|
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"less": "^4.1.2",
|
"less": "^4.1.2",
|
||||||
"marked": "^4.0.15",
|
"marked": "^4.0.15",
|
||||||
"pinia": "^2.0.14",
|
"pinia": "^2.0.14",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"primevue": "^3.12.6",
|
"primevue": "^3.12.6",
|
||||||
|
"quill": "^1.3.7",
|
||||||
|
"quill-html-edit-button": "^2.2.12",
|
||||||
"vue": "3",
|
"vue": "3",
|
||||||
"vue-navigation-bar": "^5.0.0",
|
"vue-navigation-bar": "^5.0.0",
|
||||||
"vue-router": "4",
|
"vue-router": "4"
|
||||||
"vue3-editor": "^0.1.1",
|
|
||||||
"vue3-highlightjs": "^1.0.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ Encore
|
||||||
styles: path.resolve(__dirname, 'assets', 'styles')
|
styles: path.resolve(__dirname, 'assets', 'styles')
|
||||||
})
|
})
|
||||||
.enableSassLoader()
|
.enableSassLoader()
|
||||||
.enableVueLoader()
|
.enableVueLoader(() => {}, { runtimeCompilerBuild: false })
|
||||||
.enableTypeScriptLoader()
|
.enableTypeScriptLoader()
|
||||||
.autoProvidejQuery()
|
.autoProvidejQuery()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue