while upgrading to symfony 6.1
This commit is contained in:
.envTODOsymfony.lock
assets
app.jsbootstrap.jscontrollers.json
composer.jsoncomposer.lockpackage.jsonpostcss.config.jscontrollers
js
App.vue
components
AppLink.vueHandleLogout.vueLoginForm.vueNotFound.vueTheAbout.vueTheFooter.vueTheNavbar.vueTheSidebar.vue
blog
minesweeper
pages
projects
quotes
tabs
users
composables
index.jsrouter
stores
styles
public
src
Controller
Security
templates
webpack.config.jsyarn.lock@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-app-bar color="grey-lighten-2"/>
|
||||
<!--
|
||||
<the-navbar
|
||||
@invalidate-user="onUserInvalidate"
|
||||
/>
|
||||
-->
|
||||
<v-navigation-drawer></v-navigation-drawer>
|
||||
<v-main class="container-fluid text-center">
|
||||
<div class="col-xl-3">
|
||||
<the-sidebar/>
|
||||
</div>
|
||||
<div class="col-xl-9">
|
||||
<suspense>
|
||||
<template #default>
|
||||
<router-view
|
||||
@user-authenticated="onUserAuthenticated"
|
||||
/>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<div class="loading">
|
||||
loading …
|
||||
</div>
|
||||
</template>
|
||||
</suspense>
|
||||
</div>
|
||||
<div class="col mt-2"/>
|
||||
</v-main>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<the-footer/>
|
||||
</div>
|
||||
</div>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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'
|
||||
|
||||
if (window.user) {
|
||||
const { user } = window
|
||||
}
|
||||
if (window.quote) {
|
||||
const { quote } = window
|
||||
}
|
||||
|
||||
const onUserAuthenticated = (userUri) => {
|
||||
//console.log('authenticated')
|
||||
axios
|
||||
.get(userUri)
|
||||
.then((response) => {
|
||||
this.user = response.data
|
||||
})
|
||||
this.$router.push('/')
|
||||
}
|
||||
|
||||
const onUserInvalidate = () => {
|
||||
//console.log('invalidated')
|
||||
this.user = null
|
||||
window.user = null
|
||||
}
|
||||
|
||||
</script>
|
@ -1,48 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isExternal">
|
||||
<a :href="to">
|
||||
<span
|
||||
:class="`fa fa-lg fa-fw ${fa}`"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<slot/>
|
||||
</a>
|
||||
|
||||
<span
|
||||
class="fa fa-lg fa-fw fa-external-link"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<router-link
|
||||
v-else
|
||||
:to="{ name: props.to }"
|
||||
>
|
||||
<span
|
||||
:class="`fa fa-lg fa-fw ${fa}`"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<slot/>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
fa: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const isExternal = computed(() => props.to.startsWith('http'))
|
||||
</script>
|
@ -1,10 +0,0 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HandleLogout'
|
||||
}
|
||||
|
||||
</script>
|
@ -1,97 +0,0 @@
|
||||
<template>
|
||||
<div class="container box">
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div
|
||||
v-if="errorMessage"
|
||||
class="alert alert-danger mt-2"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<div class="form-group mt-2">
|
||||
<label for="exampleInputEmail1">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
v-model="username"
|
||||
type="text"
|
||||
class="form-control"
|
||||
aria-describedby="emailHelp"
|
||||
placeholder="Enter email"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group mt-2">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="Password"
|
||||
>
|
||||
</div>
|
||||
<div class="form-check mt-2">
|
||||
<input
|
||||
id="remember-me"
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="remember-me"
|
||||
>
|
||||
Remember Me
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary mt-2 mb-2"
|
||||
:class="{ disabled: isLoading }"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
const errorMessage = ref('')
|
||||
const isLoading = ref(false)
|
||||
const emit = defineEmits(['user-authenticated'])
|
||||
|
||||
const handleSubmit = () => {
|
||||
//console.log('handle submit')
|
||||
isLoading.value = true
|
||||
|
||||
axios
|
||||
.post('/login', {
|
||||
username: username.value,
|
||||
password: password.value
|
||||
})
|
||||
.then((response) => {
|
||||
//console.log(response.headers)
|
||||
|
||||
emit('user-authenticated', response.headers.location)
|
||||
username.value = ''
|
||||
password.value = ''
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
console.log(error.response.data)
|
||||
if (error.response.data.error) {
|
||||
errorMessage.value = error.response.data.error
|
||||
} else {
|
||||
errorMessage.value = 'Unknown error'
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
404 Not Found
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NotFound'
|
||||
}
|
||||
</script>
|
@ -1,14 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
Bio:
|
||||
|
||||
Symfonycast
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'TheAbout'
|
||||
}
|
||||
</script>
|
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<footer class="dark fixed-bottom">
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col text-center">
|
||||
<div>
|
||||
powered by
|
||||
<router-link
|
||||
to="/"
|
||||
class="d-inline-block mx-auto"
|
||||
>
|
||||
<img
|
||||
src="/build/images/Spookie/spookie_64x64.png"
|
||||
alt="Spookie"
|
||||
>
|
||||
</router-link>
|
||||
<div>
|
||||
<router-link
|
||||
:to="{ name: 'About'}"
|
||||
class="d-inline-block mx-auto"
|
||||
>
|
||||
About Me
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col md-4 text-left">
|
||||
<div id="legal">
|
||||
<h5 class="bd-text-purple-bright mb-1 mt-3">
|
||||
Legal
|
||||
</h5>
|
||||
<ul class="list-unstyled ml-3">
|
||||
<li>
|
||||
<router-link :to="{ name: 'Pages', params: {slug: 'imprint'}}">
|
||||
Imprint
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/pages/privacy-policy">
|
||||
Privacy Policy
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TheFooter'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="scss">
|
||||
|
||||
footer {
|
||||
color: lightgray;
|
||||
background: #0e0e10;
|
||||
}
|
||||
</style>
|
@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<nav
|
||||
class="
|
||||
grid fixed inset-x-0 top-0 flex-wrap justify-between items-center py-0 leading-6 border-b
|
||||
@border-orange-400 opacity-90 md:flex-nowrap md:justify-start md:px-24 box-border
|
||||
bg-neutral-800 text-stone-300 grid-cols-2 place-content-around"
|
||||
style="z-index: 1030;"
|
||||
>
|
||||
<div>
|
||||
<router-link
|
||||
class="py-1 mr-4 text-xl leading-7 text-white whitespace-nowrap cursor-pointer box-border
|
||||
hover:text-white focus:text-white"
|
||||
:to="{ name: 'Home' }"
|
||||
>
|
||||
<img
|
||||
src="/build/images/24unix/24_logo_bg_96x96.png"
|
||||
class="align-middle box-border"
|
||||
alt="24unix.net"
|
||||
>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<router-link
|
||||
id="buttonLogin"
|
||||
class="inline-block py-1 px-3 mt-6 text-base font-normal leading-normal text-center
|
||||
text-black align-middle bg-orange-400 rounded border border-orange-400 border-solid
|
||||
cursor-pointer select-none box-border hover:border-orange-400 hover:bg-orange-400 hover:text-black
|
||||
focus:border-orange-400 focus:bg-orange-400 focus:text-black"
|
||||
:to="{ name: 'LoginForm' }"
|
||||
role="button"
|
||||
style="text-decoration: none; transition: none 0s ease 0s; list-style: outside none none;"
|
||||
>
|
||||
<span class="fa fa-sign-in fa-lg fa-fw"></span> Log In
|
||||
</router-link>
|
||||
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
import 'vue-navigation-bar/dist/vue-navigation-bar.css'
|
||||
|
||||
const props = defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
username: 'tracer'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const isLoggedIn = () => (!!this.user)
|
||||
let showDropdown = ref(false)
|
||||
const toggleDropDown = () => {
|
||||
console.log('toggle', showDropdown)
|
||||
showDropdown.value = !showDropdown.value
|
||||
}
|
||||
|
||||
/*
|
||||
const logout = () => ({
|
||||
axios
|
||||
.get('/logout')
|
||||
.then(this.$emit('invalidate-user'))
|
||||
|
||||
})
|
||||
|
||||
*/
|
||||
</script>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
id="main-menu"
|
||||
class="container-fluid col sidenav-left box text-start"
|
||||
>
|
||||
<ul>
|
||||
<li
|
||||
v-for="link in links"
|
||||
:key="link.url"
|
||||
>
|
||||
<AppLink
|
||||
:to="link.url"
|
||||
:fa="link.fa"
|
||||
>
|
||||
{{ link.name }}
|
||||
</AppLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'TheSidebar',
|
||||
data: () => ({
|
||||
links: [
|
||||
{
|
||||
name: 'Projects',
|
||||
url: 'Projects',
|
||||
fa: 'fa-file-code-o',
|
||||
},
|
||||
{
|
||||
name: 'Blog',
|
||||
url: 'Blog',
|
||||
fa: 'fa-file-text-o',
|
||||
},
|
||||
{
|
||||
name: 'Gitea',
|
||||
url: 'https://git.24unix.net',
|
||||
fa: 'fa-gitea',
|
||||
},
|
||||
{
|
||||
name: 'NextCloud',
|
||||
url: 'https://cloud.24unix.net',
|
||||
fa: 'fa-nextcloud',
|
||||
},
|
||||
{
|
||||
name: 'Pastebin',
|
||||
url: 'https://pastebin.24unix.net',
|
||||
fa: 'fa-paste',
|
||||
},
|
||||
{
|
||||
name: 'YOURLS',
|
||||
url: 'https://y.24unix.net',
|
||||
fa: 'fa-link',
|
||||
external: true
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
</script>
|
@ -1,55 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- media -->
|
||||
<div class="h-64 w-auto md:w-1/2">
|
||||
<img
|
||||
class="inset-0 h-full w-full object-cover object-center"
|
||||
src="/build/images/tracer_schmolle150x150.png"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
<!-- content -->
|
||||
<div class="w-full py-4 px-6 text-gray-800 flex flex-col justify-between">
|
||||
<h3 class="font-semibold text-lg leading-tight truncate">
|
||||
{{ post.title }}
|
||||
</h3>
|
||||
<p class="mt-2">
|
||||
{{ post.body.split('.')[0] }} …
|
||||
</p>
|
||||
<p class="text-sm text-gray-700 uppercase tracking-wide font-semibold mt-2">
|
||||
{{ post.createdAt.toLocaleString('de-DE') }}
|
||||
</p>
|
||||
<p v-if="blogUser">
|
||||
{{ blogUser }}
|
||||
</p>
|
||||
<p class="font-normal text-gray-700 mb-3">
|
||||
dddd
|
||||
</p>
|
||||
<router-link
|
||||
:to="{ name: 'BlogPost', params: { id: post.id } }"
|
||||
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300
|
||||
font-medium rounded-lg text-sm px-3 py-2 text-center inline-flex items-center"
|
||||
>
|
||||
Read more
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useResource from '@/composables/useResource'
|
||||
|
||||
const props = defineProps({
|
||||
post: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
const post = { ...props.post }
|
||||
|
||||
const { items: blogUser, fetchOne } = useResource('users')
|
||||
fetchOne(post.user)
|
||||
|
||||
console.log("blug user", post.user)
|
||||
console.log(blogUser.value)
|
||||
</script>
|
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div class="pt-6 pb-12 bg-gray-300">
|
||||
<div
|
||||
id="card"
|
||||
class=""
|
||||
>
|
||||
<h2 class="text-center font-serif uppercase text-4xl xl:text-5xl">
|
||||
Recent Articles
|
||||
</h2>
|
||||
<!-- container for all cards -->
|
||||
<div class="container w-100 lg:w-4/5 mx-auto flex flex-col">
|
||||
<BlogCard
|
||||
v-for="post in blogPosts"
|
||||
:key="post.id"
|
||||
:post="post"
|
||||
class="
|
||||
flex flex-col md:flex-row overflow-hidden bg-white rounded-lg
|
||||
shadow-xl mt-4 w-100 mx-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup async>
|
||||
|
||||
import useResource from '@/composables/useResource'
|
||||
//import useUser from '@/composables/useUser'
|
||||
import BlogCard from '@/components/blog/BlogCard'
|
||||
|
||||
const {
|
||||
items: blogPosts,
|
||||
fetchAll
|
||||
} = useResource('users/1/blogPosts')
|
||||
fetchAll()
|
||||
|
||||
</script>
|
@ -1,47 +0,0 @@
|
||||
<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 async>
|
||||
import { useRoute } from 'vue-router'
|
||||
import useResource from '@/composables/useResource'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { item: blogPost, fetchOne: fetchOneBlog } = useResource('https://jsonplaceholder.typicode.com/posts')
|
||||
await fetchOneBlog(route.params.id)
|
||||
|
||||
const { item: user, fetchOne: fetchOneUser } = useResource('https://jsonplaceholder.typicode.com/users')
|
||||
fetchOneUser(blogPost.value.userId)
|
||||
|
||||
</script>
|
@ -1,3 +0,0 @@
|
||||
<template>
|
||||
|
||||
</template>
|
@ -1,60 +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 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>
|
@ -1,152 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="!isLoading"
|
||||
class="box p-3"
|
||||
>
|
||||
<tabs-group @tabActivated="tabActivated">
|
||||
<tab-content title="Visual Editor">
|
||||
<div class="editor mt-2">
|
||||
<QuillEditor
|
||||
ref="editor"
|
||||
theme="snow"
|
||||
:content="JSON.parse(page.content)"
|
||||
:options="editorOptions"
|
||||
:disabled="isVueEditorDisabled"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-primary mt-3 mb-2"
|
||||
@click="saveContent"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</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>
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||
<span class="sr-only">Loading …</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import 'highlight.js/styles/tomorrow-night-blue.css'
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
//import Quill from 'quill'
|
||||
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 TabContent from '@/components/tabs/TabContent'
|
||||
|
||||
Quill
|
||||
// .register('modules/syntax', syntax, false)
|
||||
.register('modules/htmlEditButton', htmlEditButton)
|
||||
|
||||
hljs.configure({
|
||||
languages: ['javascript', 'php', 'swift']
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'PagesEdit',
|
||||
components: {
|
||||
QuillEditor,
|
||||
TabsGroup,
|
||||
TabContent
|
||||
},
|
||||
data: () => ({
|
||||
page: null,
|
||||
isLoading: true,
|
||||
isVueEditorDisabled: false,
|
||||
editorOptions: {
|
||||
modules: {
|
||||
htmlEditButton: {
|
||||
debug: true
|
||||
},
|
||||
syntax: {
|
||||
highlight: (text) => hljs.highlightAuto(text).value
|
||||
}
|
||||
}
|
||||
},
|
||||
theme: 'snow'
|
||||
}),
|
||||
beforeMount() {
|
||||
const { slug } = this.$route.params
|
||||
|
||||
axios
|
||||
.get(`/api/pages?slug=${slug}`)
|
||||
.then((response) => {
|
||||
[this.page] = response.data['hydra:member']
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
saveContent() {
|
||||
this.page.content = JSON.stringify(this.$refs.editor.getContents())
|
||||
axios
|
||||
.put(`/api/pages/${this.page.id}`, this.page)
|
||||
.then(() => {
|
||||
//this.$router.push({
|
||||
// name: 'Pages',
|
||||
// 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) {
|
||||
this.isVueEditorDisabled = name === 'Raw Content'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="circle"
|
||||
>
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||
<span class="sr-only">Loading …</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="row"
|
||||
>
|
||||
<div class="col-sm-12">
|
||||
<!-- {% if is_granted('ROLE_ADMIN') %}
|
||||
<div class="d-flex justify-content-end">
|
||||
<a :to="id"><i class="fa fa-3x fa-fw fa-edit"></i></a>
|
||||
<a :to="project.id"><i class="fa fa-3x fa-fw fa-trash"></i></a>
|
||||
</div>
|
||||
{% endif %}-->
|
||||
|
||||
<div class="show-article-container p-3 mt-4">
|
||||
<div class="show-article-title-container d-inline-block pl-3 align-middle">
|
||||
<h2>{{ project.name }}</h2>
|
||||
</div>
|
||||
<div>
|
||||
Source:
|
||||
<a
|
||||
:href="project.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ project.url }}
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="fa fa-external-link"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col-sm-12">
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
class="article-text"
|
||||
v-html="readmeToHtml"
|
||||
/>
|
||||
<!-- eslint-enable -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import { marked } from 'marked'
|
||||
import Author from '@/components/users/UserCard'
|
||||
|
||||
export default {
|
||||
Name: 'ProjectDetails',
|
||||
components: {
|
||||
Author,
|
||||
marked
|
||||
},
|
||||
data: () => ({
|
||||
project: null,
|
||||
readme: null,
|
||||
isLoading: true
|
||||
}),
|
||||
computed: {
|
||||
readmeToHtml() {
|
||||
if (!this.isLoading) {
|
||||
return marked(this.readme)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const { id } = this.$route.params
|
||||
console.log(id)
|
||||
axios
|
||||
.get(`/api/projects/${id}`)
|
||||
.then((projectResponse) => {
|
||||
this.project = projectResponse.data
|
||||
console.log(this.project)
|
||||
axios
|
||||
.get(`${this.project.url}/raw/branch/master/README.md`)
|
||||
.then((response) => {
|
||||
this.readme = response.data
|
||||
this.isLoading = false
|
||||
console.log(response)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getProjects() {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,113 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="circle"
|
||||
>
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||
<span class="sr-only">Loading …</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="container-fluid"
|
||||
>
|
||||
<div class="row">
|
||||
<h2 class="mt-2">
|
||||
This is an overview of my current public (and open source) projects.
|
||||
</h2>
|
||||
<!-- projects List -->
|
||||
<div class="col-sm-12">
|
||||
<div
|
||||
v-for="project in projects"
|
||||
:key="project.id"
|
||||
>
|
||||
<div class="project-container bg-dark my-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<router-link :to="'/projects/' + project.id">
|
||||
<img
|
||||
v-if="project.teaserImage"
|
||||
class="blog-img"
|
||||
:src="'/uploads/projects/' + project.teaserImage"
|
||||
alt="Teaser"
|
||||
>
|
||||
<img
|
||||
v-else
|
||||
class="blog-img"
|
||||
src="/build/images/24unix/24_logo_bg_96x96.png"
|
||||
alt="Teaser"
|
||||
>
|
||||
</router-link>
|
||||
<br>
|
||||
<div>
|
||||
<div
|
||||
v-for="developer in project.developer"
|
||||
:key="developer"
|
||||
class="col"
|
||||
>
|
||||
<user-card :author-iri="developer"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-8 mt-2">
|
||||
<router-link :to="'/projects/' + project.id">
|
||||
<div class="article-title d-inline-block pl-3 align-middle">
|
||||
<h2 v-html="project.name"/>
|
||||
</div>
|
||||
</router-link>
|
||||
<br>
|
||||
<div class="blog-teaser mb-2 pb-2 text-xl-start">
|
||||
<span v-html="project.description"/>
|
||||
<br>
|
||||
<br>
|
||||
started: <span v-html="formatDate(project.createdAt)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="text-xl-start">
|
||||
<router-link to="/add">
|
||||
<i class="fa fa-plus-circle"/>
|
||||
</router-link>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import UserCard from '@/components/users/UserCard'
|
||||
|
||||
export default {
|
||||
name: 'ProjectsList',
|
||||
components: {
|
||||
UserCard,
|
||||
},
|
||||
data: () => ({
|
||||
projects: null,
|
||||
isLoading: true
|
||||
}),
|
||||
mounted() {
|
||||
this.getProjects()
|
||||
},
|
||||
methods: {
|
||||
getProjects() {
|
||||
axios
|
||||
.get('/api/projects')
|
||||
.then((response) => {
|
||||
this.projects = response.data['hydra:member']
|
||||
})
|
||||
this.isLoading = false
|
||||
console.log(this.projects)
|
||||
},
|
||||
formatDate(date) {
|
||||
return new Date(date).toLocaleDateString('de-DE')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<div class="d-flex flex-column justify-content-between box mt-2 p-3 mb-2">
|
||||
<div></div>
|
||||
<div>
|
||||
<span v-html="quote"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'Quote',
|
||||
props: ['quote']
|
||||
}
|
||||
</script>
|
@ -1,34 +0,0 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
v-show="title === selectedTitle"
|
||||
class="tab-content"
|
||||
>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { inject } from 'vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const selectedTitle = inject('selectedTitle')
|
||||
return {
|
||||
selectedTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tab-content {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
@ -1,78 +0,0 @@
|
||||
<template lang="html">
|
||||
<div class="tabs">
|
||||
<ul class="tabs-header">
|
||||
<li
|
||||
v-for="title in tabTitles"
|
||||
:key="title"
|
||||
:class="{ selected: title === selectedTitle }"
|
||||
class="btn"
|
||||
@click="handleClick(title)"
|
||||
>
|
||||
{{ title }}
|
||||
</li>
|
||||
</ul>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, provide } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'TabsGroup',
|
||||
setup(props, { slots }) {
|
||||
const tabTitles = ref(slots.default()
|
||||
.map((tab) => tab.props.title))
|
||||
const selectedTitle = ref(tabTitles.value[0])
|
||||
|
||||
provide('selectedTitle', selectedTitle)
|
||||
return {
|
||||
selectedTitle,
|
||||
tabTitles
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(title) {
|
||||
this.selectedTitle = title
|
||||
this.$emit('tabActivated', title)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@import "~styles/app.scss";
|
||||
.tabs {
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.tabs-header {
|
||||
margin-bottom: 10px;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tabs-header li {
|
||||
width: 140px;
|
||||
text-align: center;
|
||||
padding: 10px 20px;
|
||||
margin-right: 10px;
|
||||
background-color: #2e2e2e;
|
||||
border-radius: 5px;
|
||||
color: #999999;
|
||||
cursor: pointer;
|
||||
transition: 0.4s all ease-out;
|
||||
}
|
||||
|
||||
.tabs-header li.selected {
|
||||
background-color: $primary;
|
||||
color: $jet-black;
|
||||
}
|
||||
|
||||
.tabs-header li.selected:hover {
|
||||
/*border-color: $body-color; */
|
||||
}
|
||||
|
||||
</style>
|
@ -1,87 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="circle"
|
||||
>
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||
<span class="sr-only">Loading …</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="container box rounded bg-dark mt-5 mb-5"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="d-flex flex-column align-items-center text-center p-3 py-5">
|
||||
Profile of {{ user.username }}
|
||||
<img
|
||||
class="rounded-circle border-1 mt-5"
|
||||
src="/build/images/tracer_schmolle150x150.png"
|
||||
alt="profile image"
|
||||
>
|
||||
<span class="font-weight-bold">{{ user.username }}</span>
|
||||
<!--
|
||||
<span class="font-weight-bold">
|
||||
<a href="{{ path('app_main', { '_switch_user': app.user.username }) }}">
|
||||
switch user {{ user.username }}</span>
|
||||
-->
|
||||
<span class="text-white-50">
|
||||
<i class="fa fa-lg fa-envelope me-1"/>{{ user.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="p-3 py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="text-right">
|
||||
User Projects …
|
||||
</h4>
|
||||
</div>
|
||||
<div class="row mt-2"/>
|
||||
|
||||
<!--
|
||||
<div class="mt-5 text-center">
|
||||
<button class="btn btn-primary profile-button" type="button">Save Profile</button>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import axios from 'axios'
|
||||
|
||||
const user = reactive(null)
|
||||
const isLoading = ref(true)
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// if there is no param, we go to our own profile, elso to the login
|
||||
|
||||
if (route.params.username) {
|
||||
console.log('we have the username')
|
||||
} 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>
|
@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="circle"
|
||||
>
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw"/>
|
||||
<span class="sr-only">Loading …</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="mt-1 mb-1"
|
||||
>
|
||||
<router-link
|
||||
class="align-left blog-details"
|
||||
:to="'/profile/' + author.username"
|
||||
>
|
||||
<img
|
||||
class="article-author-img rounded-circle"
|
||||
:src="'build/images/' + author.avatar"
|
||||
alt="profile"
|
||||
>
|
||||
</router-link>
|
||||
<router-link :to="'/profile/' + author.username">
|
||||
{{ author.username }}
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserCard',
|
||||
props: {
|
||||
authorIri: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
author: null,
|
||||
isLoading: true
|
||||
}),
|
||||
mounted() {
|
||||
this.getAuthor()
|
||||
},
|
||||
methods: {
|
||||
getAuthor() {
|
||||
console.log(`here${this.authorIri}`)
|
||||
axios
|
||||
.get(this.authorIri)
|
||||
.then((response) => {
|
||||
console.log('response')
|
||||
console.log(response)
|
||||
this.author = response.data
|
||||
console.log(this.author)
|
||||
this.isLoading = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
console.log(this.author)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,34 +0,0 @@
|
||||
import { ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
export default function useResource(resource) {
|
||||
|
||||
console.log('useBlog')
|
||||
axios.defaults.headers.common['app-id'] = '628cbf673800f869ed218152' // for all requests
|
||||
|
||||
const apiBaseUrl = 'https://628cc5c6a3fd714fd03914c2.mockapi.io/api/'
|
||||
const items = ref([])
|
||||
const item = ref(null)
|
||||
const fetchAll = async () => {
|
||||
await axios
|
||||
.get(apiBaseUrl + resource)
|
||||
.then((response) => {
|
||||
console.log(response.data)
|
||||
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
|
||||
}
|
||||
}
|
@ -1,53 +1,17 @@
|
||||
// assets/js/index.js
|
||||
|
||||
import '../styles/app.scss'
|
||||
// CKEditor
|
||||
import '../styles/ckeditor.css'
|
||||
import 'fork-awesome/scss/fork-awesome.scss'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
require('bootstrap')
|
||||
import 'bootswatch/dist/slate/bootstrap.min.css'
|
||||
|
||||
import { createPinia } from 'pinia'
|
||||
$(document).ready(function () {
|
||||
console.log('ready')
|
||||
$('#toggleSidebar').on('click', function () {
|
||||
$('#toggleIcon').toggleClass('fa fa-lg fa-fw fa-caret-square-o-left')
|
||||
$('#toggleIcon').toggleClass('fa fa-lg fa-fw fa-caret-square-o-right')
|
||||
$('#sidebar').toggleClass('active')
|
||||
})
|
||||
})
|
||||
|
||||
//import { QuillEditor } from '@vueup/vue-quill'
|
||||
//import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||
//import '@vueup/vue-quill/dist/vue-quill.bubble.css'
|
||||
|
||||
import router from '@/router'
|
||||
import AppLink from '@/components/AppLink'
|
||||
import App from '@/App'
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
globalThis.__VUE_OPTIONS_API__ = true
|
||||
globalThis.__VUE_PROD_DEVTOOLS__ = true
|
||||
|
||||
// Matomo
|
||||
const _paq = window._paq = window._paq || []
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView'])
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function () {
|
||||
const u = 'https://analytics.24unix.net/'
|
||||
_paq.push(['setTrackerUrl', `${u}matomo.php`])
|
||||
_paq.push(['setSiteId', '1'])
|
||||
const d = document
|
||||
const g = d.createElement('script')
|
||||
const
|
||||
s = d.getElementsByTagName('script')[0]
|
||||
g.async = true
|
||||
g.src = `${u}matomo.js`
|
||||
s.parentNode.insertBefore(g, s)
|
||||
}())
|
||||
// End Matomo Code
|
||||
/* eslint-enable */
|
||||
|
||||
//globalThis.__VUE_OPTIONS_API__ = true;
|
||||
//globalThis.__VUE_PROD_DEVTOOLS__ = true;
|
||||
|
||||
createApp(App)
|
||||
.component('AppLink', AppLink)
|
||||
// .component('QuillEditor', QuillEditor)
|
||||
.use(createPinia())
|
||||
.use(router)
|
||||
.mount('#app')
|
||||
|
@ -1,86 +0,0 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import LoginForm from '@/components/LoginForm'
|
||||
import Quotes from '@/components/quotes'
|
||||
import Pages from '@/components/pages/PagesIndex'
|
||||
import PagesEdit from '@/components/pages/edit'
|
||||
import ProjectsList from '@/components/projects'
|
||||
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 TheAbout from '@/components/TheAbout'
|
||||
import NotFound from '@/components/NotFound'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Quotes
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
component: TheAbout
|
||||
},
|
||||
{
|
||||
path: '/form_login',
|
||||
name: 'LoginForm',
|
||||
component: LoginForm
|
||||
},
|
||||
{
|
||||
path: '/projects',
|
||||
name: 'Projects',
|
||||
component: ProjectsList
|
||||
},
|
||||
{
|
||||
path: '/projects/:id',
|
||||
name: 'ProjectDetails',
|
||||
component: ProjectsDetails
|
||||
},
|
||||
{
|
||||
path: '/blog',
|
||||
name: 'Blog',
|
||||
component: BlogIndex
|
||||
},
|
||||
{
|
||||
path: '/blog/post/:id',
|
||||
name: 'BlogPost',
|
||||
component: BlogPost
|
||||
},
|
||||
{
|
||||
path: '/pages/:slug',
|
||||
name: 'Pages',
|
||||
component: Pages,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '/pages/edit/:slug',
|
||||
component: PagesEdit,
|
||||
meta: { requiredAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/profile/:username?',
|
||||
name: 'Profile',
|
||||
component: ProfileView
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: NotFound
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
/*
|
||||
router.beforeEach((to) => {
|
||||
if (to.meta.requiredAuth && !window.user) {
|
||||
return { name: 'LoginForm' }
|
||||
}
|
||||
})
|
||||
|
||||
*/
|
||||
export default router
|
@ -1,13 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import axios from 'axios';
|
||||
|
||||
export const useQuotesStore = defineStore('QuotesStore', {
|
||||
state: () => ({
|
||||
quotes: []
|
||||
}),
|
||||
actions: {
|
||||
async fill() {
|
||||
this.quotes = (await axios.get('api/quotes')).data;
|
||||
}
|
||||
}
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const useUserStore = defineStore('UsersStore', {
|
||||
state: () => {
|
||||
|
||||
},
|
||||
|
||||
});
|
Reference in New Issue
Block a user