From bb65f049927cb4735f9aa190be3c75c724daae91 Mon Sep 17 00:00:00 2001 From: Dilanka-H Date: Mon, 24 Nov 2025 14:45:21 +0700 Subject: [PATCH] edit the layout handling and add cv download --- Dockerfile | 1 + css/main.css | 279 ++++++++++++++++--------- internal/api/project_handler.go | 87 ++++---- internal/routes/routes.go | 1 + internal/store/template_store.go | 74 +++++++ views/experience.html | 4 +- views/header.html | 33 --- views/helper-blocks.html | 9 +- views/index.html | 58 +---- views/partials/about-partial.html | 17 +- views/partials/experience-partial.html | 10 +- views/partials/projects-partial.html | 7 +- views/projects.html | 4 +- views/script.html | 20 +- 14 files changed, 351 insertions(+), 253 deletions(-) create mode 100644 internal/store/template_store.go delete mode 100644 views/header.html diff --git a/Dockerfile b/Dockerfile index 1b2eecf..04783ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,6 +34,7 @@ COPY --from=builder /app/css ./css COPY --from=builder /app/views ./views COPY --from=builder /app/my_website.db ./ COPY --from=builder /app/data ./data +COPY --from=builder /app/documents ./documents EXPOSE 8080 diff --git a/css/main.css b/css/main.css index 99aed16..1288cf9 100644 --- a/css/main.css +++ b/css/main.css @@ -7,6 +7,7 @@ 'Noto Color Emoji'; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + --color-blue-100: oklch(93.2% 0.032 255.585); --color-blue-600: oklch(54.6% 0.245 262.881); --color-purple-300: oklch(82.7% 0.119 306.383); --color-gray-300: oklch(87.2% 0.01 258.338); @@ -201,9 +202,15 @@ .inset-0 { inset: calc(var(--spacing) * 0); } + .top-1 { + top: calc(var(--spacing) * 1); + } .top-1\/2 { top: calc(1/2 * 100%); } + .top-3 { + top: calc(var(--spacing) * 3); + } .top-3\/4 { top: calc(3/4 * 100%); } @@ -222,6 +229,9 @@ .top-70 { top: calc(var(--spacing) * 70); } + .right-1 { + right: calc(var(--spacing) * 1); + } .right-1\/3 { right: calc(1/3 * 100%); } @@ -243,6 +253,9 @@ .bottom-20 { bottom: calc(var(--spacing) * 20); } + .left-1 { + left: calc(var(--spacing) * 1); + } .left-1\/3 { left: calc(1/3 * 100%); } @@ -303,6 +316,9 @@ .mt-6 { margin-top: calc(var(--spacing) * 6); } + .mt-10 { + margin-top: calc(var(--spacing) * 10); + } .mt-16 { margin-top: calc(var(--spacing) * 16); } @@ -330,33 +346,69 @@ .hidden { display: none; } + .inline-block { + display: inline-block; + } .inline-flex { display: inline-flex; } + .table { + display: table; + } + .h-2 { + height: calc(var(--spacing) * 2); + } .h-2\.5 { height: calc(var(--spacing) * 2.5); } .min-h-screen { min-height: 100vh; } + .w-0 { + width: calc(var(--spacing) * 0); + } .w-0\.5 { width: calc(var(--spacing) * 0.5); } + .w-2 { + width: calc(var(--spacing) * 2); + } .w-2\.5 { width: calc(var(--spacing) * 2.5); } + .w-auto { + width: auto; + } + .w-fit { + width: fit-content; + } .max-w-2xl { max-width: var(--container-2xl); } .max-w-3xl { max-width: var(--container-3xl); } + .flex-shrink { + flex-shrink: 1; + } + .flex-shrink-0 { + flex-shrink: 0; + } + .flex-shrink-1 { + flex-shrink: 1; + } .flex-grow { flex-grow: 1; } + .border-collapse { + border-collapse: collapse; + } .cursor-pointer { cursor: pointer; } + .resize { + resize: both; + } .list-inside { list-style-position: inside; } @@ -378,9 +430,6 @@ .items-center { align-items: center; } - .justify-between { - justify-content: space-between; - } .justify-center { justify-content: center; } @@ -407,6 +456,20 @@ margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); } } + .space-y-5 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-x-3 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 3) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse))); + } + } .space-x-5 { :where(& > :not(:last-child)) { --tw-space-x-reverse: 0; @@ -414,16 +477,12 @@ margin-inline-end: calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-x-reverse))); } } - .space-x-6 { - :where(& > :not(:last-child)) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(var(--spacing) * 6) * var(--tw-space-x-reverse)); - margin-inline-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse))); - } - } .overflow-hidden { overflow: hidden; } + .rounded { + border-radius: 0.25rem; + } .rounded-full { border-radius: calc(infinity * 1px); } @@ -441,12 +500,18 @@ .border-secondary { border-color: #d3d9e6; } + .border-white { + border-color: var(--color-white); + } .border-white\/20 { border-color: color-mix(in srgb, #fff 20%, transparent); @supports (color: color-mix(in lab, red, red)) { border-color: color-mix(in oklab, var(--color-white) 20%, transparent); } } + .bg-accent { + background-color: #9333ea; + } .bg-accent\/5 { background-color: color-mix(in oklab, #9333ea 5%, transparent); } @@ -459,12 +524,30 @@ .p-4 { padding: calc(var(--spacing) * 4); } + .px-2 { + padding-inline: calc(var(--spacing) * 2); + } + .px-3 { + padding-inline: calc(var(--spacing) * 3); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .px-5 { + padding-inline: calc(var(--spacing) * 5); + } .px-6 { padding-inline: calc(var(--spacing) * 6); } .px-8 { padding-inline: calc(var(--spacing) * 8); } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } .py-3 { padding-block: calc(var(--spacing) * 3); } @@ -489,6 +572,9 @@ .text-start { text-align: start; } + .align-middle { + vertical-align: middle; + } .text-3xl { font-size: var(--text-3xl); line-height: var(--tw-leading, var(--text-3xl--line-height)); @@ -533,6 +619,9 @@ --tw-font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold); } + .text-blue-100 { + color: var(--color-blue-100); + } .text-blue-600 { color: var(--color-blue-600); } @@ -542,6 +631,9 @@ .text-gray-500 { color: var(--color-gray-500); } + .text-purple-300 { + color: var(--color-purple-300); + } .text-purple-300\/50 { color: color-mix(in srgb, oklch(82.7% 0.119 306.383) 50%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -562,11 +654,22 @@ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } + .filter { + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } .backdrop-blur-xl { --tw-backdrop-blur: blur(var(--blur-xl)); -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } + .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -697,15 +800,6 @@ } } } - .hover\:dark\:bg-darkaccent\/0 { - &:hover { - @media (hover: hover) { - @media (prefers-color-scheme: dark) { - background-color: color-mix(in oklab, #2563eb 0%, transparent); - } - } - } - } .hover\:dark\:bg-darkaccent\/30 { &:hover { @media (hover: hover) { @@ -734,15 +828,6 @@ } } } - .hover\:\[\&\>svg\]\:text-\[\#cc6d00\] { - &:hover { - @media (hover: hover) { - &>svg { - color: #cc6d00; - } - } - } - } .hover\:\[\&\>svg\]\:drop-shadow-\[0_0_6px_rgba\(35\,36\,59\,0\.5\)\] { &:hover { @media (hover: hover) { @@ -881,6 +966,64 @@ inherits: false; initial-value: 0 0 #0000; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-blur { + syntax: "*"; + inherits: false; +} +@property --tw-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-invert { + syntax: "*"; + inherits: false; +} +@property --tw-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-drop-shadow-size { + syntax: "*"; + inherits: false; +} @property --tw-backdrop-blur { syntax: "*"; inherits: false; @@ -936,59 +1079,6 @@ inherits: false; initial-value: 1; } -@property --tw-blur { - syntax: "*"; - inherits: false; -} -@property --tw-brightness { - syntax: "*"; - inherits: false; -} -@property --tw-contrast { - syntax: "*"; - inherits: false; -} -@property --tw-grayscale { - syntax: "*"; - inherits: false; -} -@property --tw-hue-rotate { - syntax: "*"; - inherits: false; -} -@property --tw-invert { - syntax: "*"; - inherits: false; -} -@property --tw-opacity { - syntax: "*"; - inherits: false; -} -@property --tw-saturate { - syntax: "*"; - inherits: false; -} -@property --tw-sepia { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow-color { - syntax: "*"; - inherits: false; -} -@property --tw-drop-shadow-alpha { - syntax: ""; - inherits: false; - initial-value: 100%; -} -@property --tw-drop-shadow-size { - syntax: "*"; - inherits: false; -} @layer properties { @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { *, ::before, ::after, ::backdrop { @@ -1011,19 +1101,7 @@ --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; - --tw-backdrop-blur: initial; - --tw-backdrop-brightness: initial; - --tw-backdrop-contrast: initial; - --tw-backdrop-grayscale: initial; - --tw-backdrop-hue-rotate: initial; - --tw-backdrop-invert: initial; - --tw-backdrop-opacity: initial; - --tw-backdrop-saturate: initial; - --tw-backdrop-sepia: initial; - --tw-duration: initial; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-scale-z: 1; + --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; @@ -1037,6 +1115,19 @@ --tw-drop-shadow-color: initial; --tw-drop-shadow-alpha: 100%; --tw-drop-shadow-size: initial; + --tw-backdrop-blur: initial; + --tw-backdrop-brightness: initial; + --tw-backdrop-contrast: initial; + --tw-backdrop-grayscale: initial; + --tw-backdrop-hue-rotate: initial; + --tw-backdrop-invert: initial; + --tw-backdrop-opacity: initial; + --tw-backdrop-saturate: initial; + --tw-backdrop-sepia: initial; + --tw-duration: initial; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-scale-z: 1; } } } diff --git a/internal/api/project_handler.go b/internal/api/project_handler.go index 27aa0f2..a7fda47 100644 --- a/internal/api/project_handler.go +++ b/internal/api/project_handler.go @@ -4,14 +4,25 @@ import ( "database/sql" "duhweb/internal/store" "html/template" + "io" "net/http" + "os" ) type ApiHandler struct { Templates *template.Template ProjectStore *store.SQLiteProjectStore ExperienceStore *store.SQLiteExperienceStore - FooterTemplateData []FooterTemplateData +} + +type Layout struct { + TemplateStore store.TemplateStore + Project []store.Project + Experience []store.ExperienceJSON +} + +var layout = Layout{ + TemplateStore: *store.NewTemplateStore(), } func (h *ApiHandler) Render(w http.ResponseWriter, tmpl string, data interface{}) { @@ -21,65 +32,24 @@ func (h *ApiHandler) Render(w http.ResponseWriter, tmpl string, data interface{} } } -type FooterTemplateData struct { - Link string - Height string - Width string - Path string -} - func NewApiHandler(db *sql.DB) *ApiHandler { tmpl := template.Must(template.New("").ParseGlob("views/*.html")) template.Must(tmpl.ParseGlob("views/partials/*.html")) - footerTemplateData := []FooterTemplateData{ - { - Link: "mailto:dilankaherath14@gmail.com", - Height: "5", - Width: "5", - Path: "M61.4 64C27.5 64 0 91.5 0 125.4 0 126.3 0 127.1 .1 128L0 128 0 384c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-256-.1 0c0-.9 .1-1.7 .1-2.6 0-33.9-27.5-61.4-61.4-61.4L61.4 64zM464 192.3L464 384c0 8.8-7.2 16-16 16L64 400c-8.8 0-16-7.2-16-16l0-191.7 154.8 117.4c31.4 23.9 74.9 23.9 106.4 0L464 192.3zM48 125.4C48 118 54 112 61.4 112l389.2 0c7.4 0 13.4 6 13.4 13.4 0 4.2-2 8.2-5.3 10.7L280.2 271.5c-14.3 10.8-34.1 10.8-48.4 0L53.3 136.1c-3.3-2.5-5.3-6.5-5.3-10.7z", - }, - { - Link: "https://www.linkedin.com/in/dilanka-herath", - Height: "5", - Width: "5", - Path: "M100.3 448H7.4V148.9h92.9zM53.8 108.1C24.1 108.1 0 83.5 0 53.8a53.8 53.8 0 0 1 107.6 0c0 29.7-24.1 54.3-53.8 54.3zM447.9 448h-92.7V302.4c0-34.7-.7-79.2-48.3-79.2-48.3 0-55.7 37.7-55.7 76.7V448h-92.8V148.9h89.1v40.8h1.3c12.4-23.5 42.7-48.3 87.9-48.3 94 0 111.3 61.9 111.3 142.3V448z", - }, - { - Link: "https://github.com/DilankaHer", - Height: "5", - Width: "5", - Path: "M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z", - }, - { - Link: "https://line.me/ti/p/~dilankaa", - Height: "5", - Width: "5", - Path: "M311 196.8l0 81.3c0 2.1-1.6 3.7-3.7 3.7l-13 0c-1.3 0-2.4-.7-3-1.5L254 230 254 278.2c0 2.1-1.6 3.7-3.7 3.7l-13 0c-2.1 0-3.7-1.6-3.7-3.7l0-81.3c0-2.1 1.6-3.7 3.7-3.7l12.9 0c1.1 0 2.4 .6 3 1.6l37.3 50.3 0-48.2c0-2.1 1.6-3.7 3.7-3.7l13 0c2.1-.1 3.8 1.6 3.8 3.5l0 .1zm-93.7-3.7l-13 0c-2.1 0-3.7 1.6-3.7 3.7l0 81.3c0 2.1 1.6 3.7 3.7 3.7l13 0c2.1 0 3.7-1.6 3.7-3.7l0-81.3c0-1.9-1.6-3.7-3.7-3.7zm-31.4 68.1l-35.6 0 0-64.4c0-2.1-1.6-3.7-3.7-3.7l-13 0c-2.1 0-3.7 1.6-3.7 3.7l0 81.3c0 1 .3 1.8 1 2.5 .7 .6 1.5 1 2.5 1l52.2 0c2.1 0 3.7-1.6 3.7-3.7l0-13c0-1.9-1.6-3.7-3.5-3.7l.1 0zm193.7-68.1l-52.3 0c-1.9 0-3.7 1.6-3.7 3.7l0 81.3c0 1.9 1.6 3.7 3.7 3.7l52.2 0c2.1 0 3.7-1.6 3.7-3.7l0-13.1c0-2.1-1.6-3.7-3.7-3.7l-35.5 0 0-13.6 35.5 0c2.1 0 3.7-1.6 3.7-3.7l0-13.1c0-2.1-1.6-3.7-3.7-3.7l-35.5 0 0-13.7 35.5 0c2.1 0 3.7-1.6 3.7-3.7l0-13c-.1-1.9-1.7-3.7-3.7-3.7l.1 0zM512 93.4l0 326c-.1 51.2-42.1 92.7-93.4 92.6l-326 0C41.4 511.9-.1 469.8 0 418.6l0-326C.1 41.4 42.2-.1 93.4 0l326 0c51.2 .1 92.7 42.1 92.6 93.4zM441.6 233.5c0-83.4-83.7-151.3-186.4-151.3S68.8 150.1 68.8 233.5c0 74.7 66.3 137.4 155.9 149.3 21.8 4.7 19.3 12.7 14.4 42.1-.8 4.7-3.8 18.4 16.1 10.1s107.3-63.2 146.5-108.2c27-29.7 39.9-59.8 39.9-93.1l0-.2z", - }, - { - Link: "https://wa.me/66615971121", - Height: "5", - Width: "5", - Path: "M380.9 97.1c-41.9-42-97.7-65.1-157-65.1-122.4 0-222 99.6-222 222 0 39.1 10.2 77.3 29.6 111L0 480 117.7 449.1c32.4 17.7 68.9 27 106.1 27l.1 0c122.3 0 224.1-99.6 224.1-222 0-59.3-25.2-115-67.1-157zm-157 341.6c-33.2 0-65.7-8.9-94-25.7l-6.7-4-69.8 18.3 18.6-68.1-4.4-7c-18.5-29.4-28.2-63.3-28.2-98.2 0-101.7 82.8-184.5 184.6-184.5 49.3 0 95.6 19.2 130.4 54.1s56.2 81.2 56.1 130.5c0 101.8-84.9 184.6-186.6 184.6zM325.1 300.5c-5.5-2.8-32.8-16.2-37.9-18-5.1-1.9-8.8-2.8-12.5 2.8s-14.3 18-17.6 21.8c-3.2 3.7-6.5 4.2-12 1.4-32.6-16.3-54-29.1-75.5-66-5.7-9.8 5.7-9.1 16.3-30.3 1.8-3.7 .9-6.9-.5-9.7s-12.5-30.1-17.1-41.2c-4.5-10.8-9.1-9.3-12.5-9.5-3.2-.2-6.9-.2-10.6-.2s-9.7 1.4-14.8 6.9c-5.1 5.6-19.4 19-19.4 46.3s19.9 53.7 22.6 57.4c2.8 3.7 39.1 59.7 94.8 83.8 35.2 15.2 49 16.5 66.6 13.9 10.7-1.6 32.8-13.4 37.4-26.4s4.6-24.1 3.2-26.4c-1.3-2.5-5-3.9-10.5-6.6z", - }, - } - return &ApiHandler{ Templates: tmpl, ProjectStore: store.NewSQLiteProjectStore(db), ExperienceStore: store.NewSQLiteExperienceStore(db), - FooterTemplateData: footerTemplateData, } } func (h *ApiHandler) InitPage(w http.ResponseWriter, r *http.Request) { var hxRequest = r.Header.Get("HX-Request") if hxRequest != "true" { - h.Render(w, "index", h.FooterTemplateData) + h.Render(w, "index", layout) return } - h.Render(w, "about-partial", h.FooterTemplateData) + h.Render(w, "about-partial", layout) } func (h *ApiHandler) ProjectsPage(w http.ResponseWriter, r *http.Request) { @@ -89,11 +59,12 @@ func (h *ApiHandler) ProjectsPage(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } + layout.Project = projects if hxRequest != "true" { - h.Render(w, "projects", projects) + h.Render(w, "projects", layout) return } - h.Render(w, "projects-partial", projects) + h.Render(w, "projects-partial", layout.Project) } func (h *ApiHandler) ExperiencePage(w http.ResponseWriter, r *http.Request) { @@ -104,9 +75,29 @@ func (h *ApiHandler) ExperiencePage(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } + layout.Experience = experiences if hxRequest != "true" { - h.Render(w, "experience", experiences) + h.Render(w, "experience", layout) return } - h.Render(w, "experience-partial", experiences) + h.Render(w, "experience-partial", layout.Experience) } + +func (h *ApiHandler) MakeDownloadLink(w http.ResponseWriter, r *http.Request) { + file, err := os.Open("./documents/DilankaHerath-CV.pdf") + w.Header().Set("Hx-Trigger", "DownloadCVButton") + + if err != nil { + http.Error(w, "Failed to open CV file", http.StatusInternalServerError) + return + } + defer file.Close() + + w.Header().Set("Content-Type", "application/pdf") + w.Header().Set("Content-Disposition", "attachment; filename=\"DilankaHerath-CV.pdf\"") + + _, err = io.Copy(w, file) + if err != nil { + return + } +} \ No newline at end of file diff --git a/internal/routes/routes.go b/internal/routes/routes.go index e5aa1c3..256a8d5 100644 --- a/internal/routes/routes.go +++ b/internal/routes/routes.go @@ -12,5 +12,6 @@ func SetupRoutes(app *app.Application) *chi.Mux { r.Get("/", app.ApiHandler.InitPage) r.Get("/projects", app.ApiHandler.ProjectsPage) r.Get("/experience", app.ApiHandler.ExperiencePage) + r.Get("/download", app.ApiHandler.MakeDownloadLink) return r } diff --git a/internal/store/template_store.go b/internal/store/template_store.go new file mode 100644 index 0000000..b21a34b --- /dev/null +++ b/internal/store/template_store.go @@ -0,0 +1,74 @@ +package store + +type TemplateStore struct { + Footer []Footer + ScatterWord []ScatterWord +} + +type Footer struct { + Link string + Height string + Width string + Path string +} + +type ScatterWord struct { + AxisY string + AxisX string + Word string +} + +func NewTemplateStore() *TemplateStore { + footer := []Footer{ + { + Link: "mailto:dilankaherath14@gmail.com", + Height: "5", + Width: "5", + Path: "M61.4 64C27.5 64 0 91.5 0 125.4 0 126.3 0 127.1 .1 128L0 128 0 384c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-256-.1 0c0-.9 .1-1.7 .1-2.6 0-33.9-27.5-61.4-61.4-61.4L61.4 64zM464 192.3L464 384c0 8.8-7.2 16-16 16L64 400c-8.8 0-16-7.2-16-16l0-191.7 154.8 117.4c31.4 23.9 74.9 23.9 106.4 0L464 192.3zM48 125.4C48 118 54 112 61.4 112l389.2 0c7.4 0 13.4 6 13.4 13.4 0 4.2-2 8.2-5.3 10.7L280.2 271.5c-14.3 10.8-34.1 10.8-48.4 0L53.3 136.1c-3.3-2.5-5.3-6.5-5.3-10.7z", + }, + { + Link: "https://www.linkedin.com/in/dilanka-herath", + Height: "5", + Width: "5", + Path: "M100.3 448H7.4V148.9h92.9zM53.8 108.1C24.1 108.1 0 83.5 0 53.8a53.8 53.8 0 0 1 107.6 0c0 29.7-24.1 54.3-53.8 54.3zM447.9 448h-92.7V302.4c0-34.7-.7-79.2-48.3-79.2-48.3 0-55.7 37.7-55.7 76.7V448h-92.8V148.9h89.1v40.8h1.3c12.4-23.5 42.7-48.3 87.9-48.3 94 0 111.3 61.9 111.3 142.3V448z", + }, + { + Link: "https://github.com/DilankaHer", + Height: "5", + Width: "5", + Path: "M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z", + }, + { + Link: "https://line.me/ti/p/~dilankaa", + Height: "5", + Width: "5", + Path: "M311 196.8l0 81.3c0 2.1-1.6 3.7-3.7 3.7l-13 0c-1.3 0-2.4-.7-3-1.5L254 230 254 278.2c0 2.1-1.6 3.7-3.7 3.7l-13 0c-2.1 0-3.7-1.6-3.7-3.7l0-81.3c0-2.1 1.6-3.7 3.7-3.7l12.9 0c1.1 0 2.4 .6 3 1.6l37.3 50.3 0-48.2c0-2.1 1.6-3.7 3.7-3.7l13 0c2.1-.1 3.8 1.6 3.8 3.5l0 .1zm-93.7-3.7l-13 0c-2.1 0-3.7 1.6-3.7 3.7l0 81.3c0 2.1 1.6 3.7 3.7 3.7l13 0c2.1 0 3.7-1.6 3.7-3.7l0-81.3c0-1.9-1.6-3.7-3.7-3.7zm-31.4 68.1l-35.6 0 0-64.4c0-2.1-1.6-3.7-3.7-3.7l-13 0c-2.1 0-3.7 1.6-3.7 3.7l0 81.3c0 1 .3 1.8 1 2.5 .7 .6 1.5 1 2.5 1l52.2 0c2.1 0 3.7-1.6 3.7-3.7l0-13c0-1.9-1.6-3.7-3.5-3.7l.1 0zm193.7-68.1l-52.3 0c-1.9 0-3.7 1.6-3.7 3.7l0 81.3c0 1.9 1.6 3.7 3.7 3.7l52.2 0c2.1 0 3.7-1.6 3.7-3.7l0-13.1c0-2.1-1.6-3.7-3.7-3.7l-35.5 0 0-13.6 35.5 0c2.1 0 3.7-1.6 3.7-3.7l0-13.1c0-2.1-1.6-3.7-3.7-3.7l-35.5 0 0-13.7 35.5 0c2.1 0 3.7-1.6 3.7-3.7l0-13c-.1-1.9-1.7-3.7-3.7-3.7l.1 0zM512 93.4l0 326c-.1 51.2-42.1 92.7-93.4 92.6l-326 0C41.4 511.9-.1 469.8 0 418.6l0-326C.1 41.4 42.2-.1 93.4 0l326 0c51.2 .1 92.7 42.1 92.6 93.4zM441.6 233.5c0-83.4-83.7-151.3-186.4-151.3S68.8 150.1 68.8 233.5c0 74.7 66.3 137.4 155.9 149.3 21.8 4.7 19.3 12.7 14.4 42.1-.8 4.7-3.8 18.4 16.1 10.1s107.3-63.2 146.5-108.2c27-29.7 39.9-59.8 39.9-93.1l0-.2z", + }, + { + Link: "https://wa.me/66615971121", + Height: "5", + Width: "5", + Path: "M380.9 97.1c-41.9-42-97.7-65.1-157-65.1-122.4 0-222 99.6-222 222 0 39.1 10.2 77.3 29.6 111L0 480 117.7 449.1c32.4 17.7 68.9 27 106.1 27l.1 0c122.3 0 224.1-99.6 224.1-222 0-59.3-25.2-115-67.1-157zm-157 341.6c-33.2 0-65.7-8.9-94-25.7l-6.7-4-69.8 18.3 18.6-68.1-4.4-7c-18.5-29.4-28.2-63.3-28.2-98.2 0-101.7 82.8-184.5 184.6-184.5 49.3 0 95.6 19.2 130.4 54.1s56.2 81.2 56.1 130.5c0 101.8-84.9 184.6-186.6 184.6zM325.1 300.5c-5.5-2.8-32.8-16.2-37.9-18-5.1-1.9-8.8-2.8-12.5 2.8s-14.3 18-17.6 21.8c-3.2 3.7-6.5 4.2-12 1.4-32.6-16.3-54-29.1-75.5-66-5.7-9.8 5.7-9.1 16.3-30.3 1.8-3.7 .9-6.9-.5-9.7s-12.5-30.1-17.1-41.2c-4.5-10.8-9.1-9.3-12.5-9.5-3.2-.2-6.9-.2-10.6-.2s-9.7 1.4-14.8 6.9c-5.1 5.6-19.4 19-19.4 46.3s19.9 53.7 22.6 57.4c2.8 3.7 39.1 59.7 94.8 83.8 35.2 15.2 49 16.5 66.6 13.9 10.7-1.6 32.8-13.4 37.4-26.4s4.6-24.1 3.2-26.4c-1.3-2.5-5-3.9-10.5-6.6z", + }, + } + + scatter := []ScatterWord{ + {AxisY: "top-10", AxisX: "left-5", Word: "Golang"}, + {AxisY: "top-40", AxisX: "right-10", Word: "React"}, + {AxisY: "bottom-20", AxisX: "left-1/3", Word: "HTMX"}, + {AxisY: "top-1/2", AxisX: "right-1/4", Word: "Node"}, + {AxisY: "top-3/4", AxisX: "right-20", Word: "Kafka"}, + {AxisY: "top-3/4", AxisX: "left-20", Word: "Docker"}, + {AxisY: "top-20", AxisX: "left-100", Word: "Mongo"}, + {AxisY: "top-15", AxisX: "right-100", Word: "C++"}, + {AxisY: "bottom-20", AxisX: "right-1/3", Word: "Javascript"}, + {AxisY: "top-1/2", AxisX: "left-1/4", Word: "Nest"}, + {AxisY: "top-70", AxisX: "left-50", Word: "MySQL"}, + {AxisY: "top-70", AxisX: "right-50", Word: "Python"}, + } + + return &TemplateStore{ + Footer: footer, + ScatterWord: scatter, + } +} \ No newline at end of file diff --git a/views/experience.html b/views/experience.html index 536e8de..86d6c16 100644 --- a/views/experience.html +++ b/views/experience.html @@ -14,10 +14,10 @@ >
- {{ template "experience-partial" .}} + {{ template "experience-partial" .Experience}}
- {{ template "footer" }} + {{ template "footer" .TemplateStore.Footer}} {{ template "script" }} diff --git a/views/header.html b/views/header.html deleted file mode 100644 index 27ef624..0000000 --- a/views/header.html +++ /dev/null @@ -1,33 +0,0 @@ -{{ block "header" .}} -
- -
-{{ end }} diff --git a/views/helper-blocks.html b/views/helper-blocks.html index 74f71ca..ed0b1be 100644 --- a/views/helper-blocks.html +++ b/views/helper-blocks.html @@ -11,4 +11,11 @@ -{{ end }} \ No newline at end of file +{{ end }} + +{{ block "scattered-words" .}} + {{.Word}} + +{{ end}} \ No newline at end of file diff --git a/views/index.html b/views/index.html index 511a977..68e64d2 100644 --- a/views/index.html +++ b/views/index.html @@ -17,62 +17,14 @@ id="scatteredWords" class="pointer-events-none absolute inset-0 overflow-hidden select-none hidden md:block" > - Golang - React - HTMX - Node - Kafka - Docker - Mongo - C++ - Javascript - Nest - MySQL - Python + {{ range .TemplateStore.ScatterWord }} + {{ template "scattered-words" . }} + {{ end }} - - - -
{{ template "about-partial" . }}
+
{{ template "about-partial" }}
- {{ template "footer" .}} + {{ template "footer" .TemplateStore.Footer}} {{ template "script" }} diff --git a/views/partials/about-partial.html b/views/partials/about-partial.html index 1c8ef15..8506882 100644 --- a/views/partials/about-partial.html +++ b/views/partials/about-partial.html @@ -19,7 +19,7 @@ hx-get="/projects" hx-target="#content" hx-push-url="true" - class="px-8 py-6 rounded-full bg-accent/5 dark:bg-darkaccent/40 backdrop-blur-xl border border-white/20 shadow-xl text-xl font-semibold hover:bg-accent/10 hover:dark:bg-darkaccent/30 transition" + class="cursor-pointer px-6 py-4 rounded-full bg-accent/5 dark:bg-darkaccent/40 backdrop-blur-xl border border-white/20 shadow-xl text-xl font-semibold hover:bg-accent/10 hover:dark:bg-darkaccent/30 transition" > Projects @@ -29,7 +29,7 @@ hx-get="/experience" hx-target="#content" hx-push-url="true" - class="px-8 py-6 rounded-full bg-accent/5 dark:bg-darkaccent/40 backdrop-blur-xl border border-white/20 shadow-xl text-xl font-semibold hover:bg-accent/10 hover:dark:bg-darkaccent/30 transition" + class="cursor-pointer px-6 py-4 rounded-full bg-accent/5 dark:bg-darkaccent/40 backdrop-blur-xl border border-white/20 shadow-xl text-xl font-semibold hover:bg-accent/10 hover:dark:bg-darkaccent/30 transition" > Experience @@ -41,11 +41,22 @@ >

About Me

- I’m a [Your Profession] with experience in [key skills]. I enjoy solving + I'm a [Your Profession] with experience in [key skills]. I enjoy solving problems, learning new technologies, and building applications that make an impact. Currently exploring Go, htmx, and modern web tools.

+ + {{ end }} diff --git a/views/partials/experience-partial.html b/views/partials/experience-partial.html index 1f40986..7be30c6 100644 --- a/views/partials/experience-partial.html +++ b/views/partials/experience-partial.html @@ -49,27 +49,19 @@
-
+
-

{{ .StartFrom }}

- -

{{ .Company }} – {{ .EmployeeType }}

- -

{{ .Position }}

- -
    {{ range .Tasks }}
  • {{ . }}
  • {{ end }}
-
{{ end }} diff --git a/views/partials/projects-partial.html b/views/partials/projects-partial.html index 18c3b29..f7e1577 100644 --- a/views/partials/projects-partial.html +++ b/views/partials/projects-partial.html @@ -16,10 +16,11 @@ Projects
-{{ range . }} {{ template "project-partial-range" . }} {{ end}} {{ end }} {{ -block "project-partial-range" . }} +{{ range . }} {{ template "project" . }} {{ end}} {{ end }} + +{{block "project" . }}
{{ .Title }} - {{ .Description }}
-{{ end }} +{{ end }} \ No newline at end of file diff --git a/views/projects.html b/views/projects.html index 1cdbbf3..987524a 100644 --- a/views/projects.html +++ b/views/projects.html @@ -13,9 +13,9 @@ class="bg-primary dark:bg-darkprimary text-bodytext dark:text-darkbodytext flex flex-col min-h-screen" > -
{{ template "projects-partial" .}}
+
{{ template "projects-partial" .Project}}
- {{ template "footer" }} + {{ template "footer" .TemplateStore.Footer}} {{ template "script" }} diff --git a/views/script.html b/views/script.html index 61761dd..8889a2b 100644 --- a/views/script.html +++ b/views/script.html @@ -1,7 +1,6 @@ {{ block "script" .}} {{ end }}