♻️ Interactive v2 #1
| @@ -16,6 +16,8 @@ | ||||
|     "@fontsource/roboto": "^5.0.8", | ||||
|     "@mdi/font": "^7.4.47", | ||||
|     "@unocss/reset": "^0.58.5", | ||||
|     "dompurify": "^3.0.9", | ||||
|     "marked": "^12.0.0", | ||||
|     "pinia": "^2.1.7", | ||||
|     "universal-cookie": "^7.1.0", | ||||
|     "unocss": "^0.58.5", | ||||
| @@ -26,7 +28,9 @@ | ||||
|   "devDependencies": { | ||||
|     "@rushstack/eslint-patch": "^1.3.3", | ||||
|     "@tsconfig/node20": "^20.1.2", | ||||
|     "@types/dompurify": "^3.0.5", | ||||
|     "@types/node": "^20.11.10", | ||||
|     "@unocss/preset-typography": "^0.58.5", | ||||
|     "@vitejs/plugin-vue": "^5.0.3", | ||||
|     "@vitejs/plugin-vue-jsx": "^3.1.0", | ||||
|     "@vue/eslint-config-prettier": "^8.0.0", | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
|         <div> | ||||
|           <div class="font-bold">{{ props.item?.author.nick }}</div> | ||||
|           {{ props.item?.content }} | ||||
|           <div class="prose prose-post" v-html="parseContent(props.item.content)"></div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </template> | ||||
| @@ -21,11 +21,24 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import dompurify from "dompurify"; | ||||
| import { parse } from "marked"; | ||||
|  | ||||
| const props = defineProps<{ item: any }>(); | ||||
|  | ||||
| function parseContent(src: string): string { | ||||
|   return dompurify().sanitize(parse(src) as string); | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .rounded-card { | ||||
|   border-radius: 8px; | ||||
| } | ||||
| </style> | ||||
|  | ||||
| <style> | ||||
| .prose.prose-post, p { | ||||
|   margin: 0 !important; | ||||
| } | ||||
| </style> | ||||
| @@ -5,7 +5,7 @@ | ||||
|     </div> | ||||
|  | ||||
|     <v-infinite-scroll :items="props.posts" :onLoad="props.loader"> | ||||
|       <template v-for="(item, index) in props.posts" :key="item"> | ||||
|       <template v-for="item in props.posts" :key="item"> | ||||
|         <div class="mb-3 px-1"> | ||||
|           <post-item :item="item" /> | ||||
|         </div> | ||||
|   | ||||
							
								
								
									
										47
									
								
								pkg/views/src/components/publish/PostEditor.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/views/src/components/publish/PostEditor.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| <template> | ||||
|   <v-dialog v-model="editor.show" class="max-w-[540px]"> | ||||
|     <v-card title="New post"> | ||||
|       <v-form> | ||||
|         <v-card-text> | ||||
|           <v-textarea | ||||
|             required | ||||
|             hide-details | ||||
|             variant="outlined" | ||||
|             label="What's happened?!" | ||||
|           /> | ||||
|  | ||||
|           <div class="flex mt-1"> | ||||
|             <v-tooltip text="Planned publish" location="start"> | ||||
|               <template #activator="{ props }"> | ||||
|                 <v-btn v-bind="props" type="button" variant="text" icon="mdi-calendar" size="small" /> | ||||
|               </template> | ||||
|             </v-tooltip> | ||||
|             <v-tooltip text="Categories" location="start"> | ||||
|               <template #activator="{ props }"> | ||||
|                 <v-btn v-bind="props" type="button" variant="text" icon="mdi-shape" size="small" /> | ||||
|               </template> | ||||
|             </v-tooltip> | ||||
|             <v-tooltip text="Media" location="start"> | ||||
|               <template #activator="{ props }"> | ||||
|                 <v-btn v-bind="props" type="button" variant="text" icon="mdi-camera" size="small" /> | ||||
|               </template> | ||||
|             </v-tooltip> | ||||
|           </div> | ||||
|         </v-card-text> | ||||
|  | ||||
|         <v-card-actions> | ||||
|           <v-spacer></v-spacer> | ||||
|  | ||||
|           <v-btn type="reset" color="grey" @click="editor.show = false">Cancel</v-btn> | ||||
|           <v-btn type="submit" @click.prevent>Publish</v-btn> | ||||
|         </v-card-actions> | ||||
|       </v-form> | ||||
|     </v-card> | ||||
|   </v-dialog> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useEditor } from "@/stores/editor"; | ||||
|  | ||||
| const editor = useEditor(); | ||||
| </script> | ||||
| @@ -25,11 +25,25 @@ | ||||
|   <v-main> | ||||
|     <router-view /> | ||||
|   </v-main> | ||||
|  | ||||
|   <v-fab | ||||
|     class="editor-fab" | ||||
|     icon="mdi-pencil" | ||||
|     color="primary" | ||||
|     size="64" | ||||
|     appear | ||||
|     @click="editor.show = true" | ||||
|   /> | ||||
|  | ||||
|   <post-editor /> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { ref } from "vue"; | ||||
| import { useEditor } from "@/stores/editor"; | ||||
| import PostEditor from "@/components/publish/PostEditor.vue"; | ||||
|  | ||||
| const editor = useEditor() | ||||
| const navigationMenu = [ | ||||
|   { name: "Explore", icon: "mdi-compass", to: "explore" } | ||||
| ]; | ||||
| @@ -40,3 +54,11 @@ function toggleDrawer() { | ||||
|   drawerOpen.value = !drawerOpen.value; | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .editor-fab { | ||||
|   position: fixed !important; | ||||
|   bottom: 16px; | ||||
|   right: 20px; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import "vuetify/styles"; | ||||
| import { createVuetify } from "vuetify"; | ||||
| import { md3 } from "vuetify/blueprints"; | ||||
| import * as components from "vuetify/components"; | ||||
| import * as labsComponents from 'vuetify/labs/components' | ||||
| import * as directives from "vuetify/directives"; | ||||
|  | ||||
| import "@mdi/font/css/materialdesignicons.min.css"; | ||||
| @@ -22,8 +23,11 @@ const app = createApp(index); | ||||
|  | ||||
| app.use( | ||||
|   createVuetify({ | ||||
|     components, | ||||
|     directives, | ||||
|     components: { | ||||
|       ...components, | ||||
|       ...labsComponents, | ||||
|     }, | ||||
|     blueprint: md3, | ||||
|     theme: { | ||||
|       defaultTheme: "original", | ||||
|   | ||||
							
								
								
									
										8
									
								
								pkg/views/src/stores/editor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pkg/views/src/stores/editor.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import { defineStore } from "pinia"; | ||||
| import { ref } from "vue"; | ||||
|  | ||||
| export const useEditor = defineStore("editor", () => { | ||||
|   const show = ref(false); | ||||
|  | ||||
|   return { show }; | ||||
| }); | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <v-container class="flex max-md:flex-col gap-3 overflow-auto max-h-[calc(100vh-72px)] no-scrollbar"> | ||||
|   <v-container class="flex max-md:flex-col gap-3 overflow-auto max-h-[calc(100vh-64px)] no-scrollbar"> | ||||
|     <div class="timeline flex-grow-1 mt-[-16px]"> | ||||
|       <post-list :loading="loading" :posts="posts" :loader="readMore" /> | ||||
|     </div> | ||||
| @@ -56,4 +56,4 @@ async function readMore({ done }: any) { | ||||
| } | ||||
|  | ||||
| readPosts(); | ||||
| </script> | ||||
| </script> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { defineConfig, presetUno } from "unocss" | ||||
| import { defineConfig, presetAttributify, presetTypography, presetUno } from "unocss"; | ||||
|  | ||||
| export default defineConfig({ | ||||
|   presets: [presetUno({ preflight: false })] | ||||
|   presets: [presetAttributify(), presetTypography(), presetUno({ preflight: false })] | ||||
| }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user