diff --git a/apps/back/src/api/apidocs.rs b/apps/back/src/api/apidocs.rs index 4b00135..97b540f 100644 --- a/apps/back/src/api/apidocs.rs +++ b/apps/back/src/api/apidocs.rs @@ -12,7 +12,7 @@ use super::home::get_home; use markdown_struct::{ blog_timeline::BlogTimeline, content_struct::{Page, PageShort}, - doc_header::{DocHeader, DocHeaderLink, DocHeaderSpec}, + doc_header::{DocHeader, DocHeaderLink, DocHeaderSpec, DocHeaderWritter}, doc_sidebar::DocCategory, }; use utoipa::OpenApi; @@ -38,6 +38,7 @@ use utoipa::OpenApi; DocHeader, DocHeaderSpec, DocHeaderLink, + DocHeaderWritter, BlogTimeline, HomeUrl, HomeHistoryUrl, diff --git a/apps/front/components.d.ts b/apps/front/components.d.ts index 325e5ec..799e3da 100644 --- a/apps/front/components.d.ts +++ b/apps/front/components.d.ts @@ -7,8 +7,10 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { + Avatar: typeof import('primevue/avatar')['default'] Card: typeof import('primevue/card')['default'] Checkbox: typeof import('primevue/checkbox')['default'] + Chip: typeof import('primevue/chip')['default'] Panel: typeof import('primevue/panel')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/apps/front/src/component/Doc/DocSidebar.vue b/apps/front/src/component/Doc/DocSidebar.vue index 680e982..a7bdb39 100644 --- a/apps/front/src/component/Doc/DocSidebar.vue +++ b/apps/front/src/component/Doc/DocSidebar.vue @@ -2,11 +2,17 @@ import { useRoute } from 'vue-router'; import { useDocStore } from '../../stores/doc'; import DocSidebarItem from './DocSidebarItem.vue'; +import { ref, watch } from 'vue'; const route = useRoute(); const docStore = useDocStore(); +let path = ref(Array.isArray(route.params.page) ? route.params.page : [route.params.page]); -let path = Array.isArray(route.params.page) ? route.params.page : [route.params.page]; +watch(() => route.params.page, (newValue, oldValue) => { + if (newValue !== oldValue) { + path.value = Array.isArray(newValue) ? newValue : [newValue]; + } +}); diff --git a/apps/front/src/component/Page/PageMetadata.vue b/apps/front/src/component/Page/PageMetadata.vue index d2dac56..f63a932 100644 --- a/apps/front/src/component/Page/PageMetadata.vue +++ b/apps/front/src/component/Page/PageMetadata.vue @@ -1,14 +1,61 @@ \ No newline at end of file + + + \ No newline at end of file diff --git a/apps/front/src/component/Page/PageTechnoChip.vue b/apps/front/src/component/Page/PageTechnoChip.vue new file mode 100644 index 0000000..90b4941 --- /dev/null +++ b/apps/front/src/component/Page/PageTechnoChip.vue @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/apps/front/src/markdown/detectLink.ts b/apps/front/src/markdown/detectLink.ts new file mode 100644 index 0000000..fa6388c --- /dev/null +++ b/apps/front/src/markdown/detectLink.ts @@ -0,0 +1,29 @@ +export type Link = { + url: string; + text: string; +}; + +export const detectLink = (text: string) => { + const textUrlArray = []; + const urlMdRegex = /\[(\?'text'[^\]]+)\]\((\?'url'[^)]+)\)/g; + while (urlMdRegex.exec(text)) { + textUrlArray.push({ + text: RegExp.$1, + url: RegExp.$2, + }); + } + const urlMdRegex2 = /<(\?'text'[^\]]+)>/g; + // eslint-disable-next-line no-constant-condition + while (true) { + const matched = urlMdRegex2.exec(text); + if (!matched) break; + textUrlArray.push({ + text: matched[1], + url: matched[1], + }); + const splitText = text.split(`<${matched[1]}>`); + textUrlArray.push(splitText[0]); + + text = splitText.slice(1).join(''); + } +}; diff --git a/apps/front/src/markdown/detectTextSpec.ts b/apps/front/src/markdown/detectTextSpec.ts new file mode 100644 index 0000000..105c212 --- /dev/null +++ b/apps/front/src/markdown/detectTextSpec.ts @@ -0,0 +1,31 @@ +export type TextSpec = { + start: number; + stop: number; + isLink: boolean; + url?: string; + isBold: boolean; + isItalic: boolean; + isCode: boolean; +}; + +export const detectTextSpec = (text: string) => { + const textUrlArray = []; + const urlMdRegex = /\[(\?'text'[^\]]+)\]\((\?'url'[^)]+)\)/g; + while (urlMdRegex.exec(text)) { + textUrlArray.push({ + text: RegExp.$1, + url: RegExp.$2, + }); + } + const urlMdRegex2 = /<(\?'text'[^\]]+)>/g; + // eslint-disable-next-line no-constant-condition + while (true) { + text.search(urlMdRegex2); + const matched = urlMdRegex2.exec(text); + if (!matched) break; + const splitText = text.split(`<${matched[1]}>`); + textUrlArray; + + text = splitText.slice(1).join(''); + } +}; diff --git a/apps/front/src/markdown/index.ts b/apps/front/src/markdown/index.ts index 81e76d8..b2acd96 100644 --- a/apps/front/src/markdown/index.ts +++ b/apps/front/src/markdown/index.ts @@ -86,6 +86,5 @@ export const transformContent = (content: string): TitleBlock[] => { titleBlocks[titleBlocks.length - 1].appendBlock(block); } }); - console.log(titleBlocks); return titleBlocks; }; diff --git a/apps/front/src/stores/doc.ts b/apps/front/src/stores/doc.ts index db0ed8f..5c64937 100644 --- a/apps/front/src/stores/doc.ts +++ b/apps/front/src/stores/doc.ts @@ -1,4 +1,4 @@ -import { DocCategory, getDocSidebar } from '@portfolio/api-client'; +import { DocCategory, getDocSidebar, PageShort } from '@portfolio/api-client'; import { defineStore } from 'pinia'; export interface DocState { @@ -57,5 +57,24 @@ export const useDocStore = defineStore({ } return; }, + technoExists(techno: string): PageShort | undefined { + if (!this.docContent) return; + return this.technoExistsRecursive(techno, this.docContent); + }, + technoExistsRecursive( + techno: string, + category: DocCategory, + ): PageShort | undefined { + for (const page of category.pages) { + if (page.name.toLowerCase() === techno.toLowerCase()) { + return page; + } + } + for (const subCategory of category.sub_categories) { + const found = this.technoExistsRecursive(techno, subCategory); + if (found) return found; + } + return; + }, }, }); diff --git a/apps/front/tsconfig.json b/apps/front/tsconfig.json index e7b4430..c7f95da 100644 --- a/apps/front/tsconfig.json +++ b/apps/front/tsconfig.json @@ -18,6 +18,5 @@ "path": "./tsconfig.spec.json" } ], - "extends": "../../tsconfig.base.json", - "composite": true + "extends": "../../tsconfig.base.json" } diff --git a/libs/back/markdown_struct/src/blog_timeline.rs b/libs/back/markdown_struct/src/blog_timeline.rs index 3930eb4..30a0861 100644 --- a/libs/back/markdown_struct/src/blog_timeline.rs +++ b/libs/back/markdown_struct/src/blog_timeline.rs @@ -74,6 +74,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: vec![], @@ -118,6 +119,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: vec![], @@ -141,6 +143,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: vec![], diff --git a/libs/back/markdown_struct/src/content_struct.rs b/libs/back/markdown_struct/src/content_struct.rs index 0b3df92..65f610d 100644 --- a/libs/back/markdown_struct/src/content_struct.rs +++ b/libs/back/markdown_struct/src/content_struct.rs @@ -78,6 +78,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: vec![], diff --git a/libs/back/markdown_struct/src/doc_header.rs b/libs/back/markdown_struct/src/doc_header.rs index c966c6c..8f8a198 100644 --- a/libs/back/markdown_struct/src/doc_header.rs +++ b/libs/back/markdown_struct/src/doc_header.rs @@ -30,6 +30,10 @@ fn empty_doc_header_spec() -> DocHeaderSpec { } } +fn default_doc_header_writter() -> DocHeaderWritter { + Default::default() +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, ToSchema)] pub struct DocHeaderSpec { #[serde(default = "false_default")] @@ -56,11 +60,30 @@ pub struct DocHeaderLink { pub url: String, } +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, ToSchema)] +pub struct DocHeaderWritter { + pub name: String, + pub url: String, + pub avatar: String, +} + +impl Default for DocHeaderWritter { + fn default() -> Self { + DocHeaderWritter { + name: "Maxime".to_string(), + url: "https://maxleriche.net".to_string(), + avatar: "https://avatars.githubusercontent.com/u/24699592?s=80".to_string(), + } + } +} + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, ToSchema)] pub struct DocHeader { pub title: String, pub date: DateTime, pub description: Option, + #[serde(default = "default_doc_header_writter")] + pub writter: DocHeaderWritter, #[serde(default = "default_weight")] pub weight: i32, #[serde(default = "empty_doc_header_spec")] @@ -79,6 +102,11 @@ impl Default for DocHeader { title: "".to_string(), date: Utc::now(), description: None, + writter: DocHeaderWritter { + name: "".to_string(), + url: "".to_string(), + avatar: "".to_string(), + }, weight: 0, spec: DocHeaderSpec::default(), tags: Vec::new(), @@ -294,9 +322,11 @@ THIS IS A TEST let schema_header_spec = DocHeaderSpec::schema(); let schema_header_link = DocHeaderLink::schema(); let schema_header = DocHeader::schema(); + let schema_writter = DocHeaderWritter::schema(); assert_eq!(schema_header_spec.0, "DocHeaderSpec"); assert_eq!(schema_header_link.0, "DocHeaderLink"); assert_eq!(schema_header.0, "DocHeader"); + assert_eq!(schema_writter.0, "DocHeaderWritter"); } } diff --git a/libs/back/markdown_struct/src/doc_sidebar.rs b/libs/back/markdown_struct/src/doc_sidebar.rs index d4f4fb4..cbfca05 100644 --- a/libs/back/markdown_struct/src/doc_sidebar.rs +++ b/libs/back/markdown_struct/src/doc_sidebar.rs @@ -85,6 +85,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: vec![], diff --git a/libs/back/markdown_struct/src/page_database.rs b/libs/back/markdown_struct/src/page_database.rs index 9a10b55..8080285 100644 --- a/libs/back/markdown_struct/src/page_database.rs +++ b/libs/back/markdown_struct/src/page_database.rs @@ -101,6 +101,7 @@ mod tests { .unwrap() .into(), description: None, + writter: Default::default(), weight: 0, spec: Default::default(), tags: Vec::new(), diff --git a/libs/front/api-client/src/api/schemas.gen.ts b/libs/front/api-client/src/api/schemas.gen.ts index 11c1ee6..9502860 100644 --- a/libs/front/api-client/src/api/schemas.gen.ts +++ b/libs/front/api-client/src/api/schemas.gen.ts @@ -77,6 +77,9 @@ export const $DocHeader = { weight: { type: 'integer', format: 'int32' + }, + writter: { + '$ref': '#/components/schemas/DocHeaderWritter' } } } as const; @@ -109,6 +112,22 @@ export const $DocHeaderSpec = { } } as const; +export const $DocHeaderWritter = { + type: 'object', + required: ['name', 'url', 'avatar'], + properties: { + avatar: { + type: 'string' + }, + name: { + type: 'string' + }, + url: { + type: 'string' + } + } +} as const; + export const $HomeContent = { type: 'object', required: ['name', 'presentation', 'coverTitle', 'cvUrl', 'url', 'history'], diff --git a/libs/front/api-client/src/api/types.gen.ts b/libs/front/api-client/src/api/types.gen.ts index ad9fe07..a7d7c52 100644 --- a/libs/front/api-client/src/api/types.gen.ts +++ b/libs/front/api-client/src/api/types.gen.ts @@ -22,6 +22,7 @@ export type DocHeader = { techno?: Array<(string)>; title: string; weight?: number; + writter?: DocHeaderWritter; }; export type DocHeaderLink = { @@ -35,6 +36,12 @@ export type DocHeaderSpec = { project?: boolean; }; +export type DocHeaderWritter = { + avatar: string; + name: string; + url: string; +}; + export type HomeContent = { coverTitle: Array<(string)>; cvUrl: string; diff --git a/swagger.json b/swagger.json index 13e143c..e133bf4 100644 --- a/swagger.json +++ b/swagger.json @@ -241,6 +241,9 @@ "weight": { "type": "integer", "format": "int32" + }, + "writter": { + "$ref": "#/components/schemas/DocHeaderWritter" } } }, @@ -273,6 +276,25 @@ } } }, + "DocHeaderWritter": { + "type": "object", + "required": [ + "name", + "url", + "avatar" + ], + "properties": { + "avatar": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "HomeContent": { "type": "object", "required": [