mirror of
https://github.com/Lapikud/lapikud.github.io.git
synced 2026-08-08 12:41:59 +00:00
feat: Migrate more to VueV3 logic, navbar improvements
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
/** @type { import('@storybook/vue3-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../src/**/*.stories.js'],
|
||||
framework: {
|
||||
name: '@storybook/vue3-vite',
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,13 +0,0 @@
|
||||
/** @type { import('@storybook/vue3-vite').Preview } */
|
||||
const preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -15,15 +15,6 @@
|
||||
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
|
||||
|
||||
<title>Lapikud</title>
|
||||
<script>
|
||||
(function () {
|
||||
var redirect = sessionStorage.redirect;
|
||||
delete sessionStorage.redirect;
|
||||
if (redirect && redirect !== location.href) {
|
||||
history.replaceState(null, null, redirect);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
2542
package-lock.json
generated
2542
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,15 +7,11 @@
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build",
|
||||
"optimise": "node scripts/optimise-images.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/vue3-vite": "^10.2.15",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"storybook": "^10.2.15",
|
||||
"vite": "npm:rolldown-vite@7.2.5",
|
||||
"vue": "^3.5.25"
|
||||
},
|
||||
@@ -26,6 +22,7 @@
|
||||
"@lucide/vue": "^1.23.0",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"js-yaml": "^4.1.1",
|
||||
"lucide": "^1.23.0",
|
||||
"maplibre-gl": "^5.19.0",
|
||||
"sharp": "^0.34.5",
|
||||
"tailwindcss": "^4.1.17"
|
||||
|
||||
141
public/assets/asikarikas_logo_white.svg
Normal file
141
public/assets/asikarikas_logo_white.svg
Normal file
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="798px" height="301px" viewBox="0 0 798 301" enable-background="new 0 0 798 301" xml:space="preserve">
|
||||
<polyline fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="279.318,81.557 246.113,81.557
|
||||
208.437,43.879 90.656,43.879 "/>
|
||||
<polyline fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="246.114,81.557 199.732,81.557
|
||||
168.725,112.564 63.387,112.564 24.189,112.564 "/>
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="-131.841" y="-130" width="1000" height="1000"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M100.456,43.879c0,5.413-4.388,9.8-9.8,9.8c-5.412,0-9.8-4.387-9.8-9.8
|
||||
c0-5.412,4.388-9.8,9.8-9.8C96.068,34.08,100.456,38.467,100.456,43.879"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="90.656" cy="43.879" r="9.8"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M33.988,112.564c0,5.413-4.388,9.8-9.8,9.8c-5.412,0-9.8-4.387-9.8-9.8
|
||||
c0-5.412,4.388-9.799,9.8-9.799C29.6,102.765,33.988,107.152,33.988,112.564"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="24.188" cy="112.564" r="9.8"/>
|
||||
<polyline clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="
|
||||
515.697,81.557 548.902,81.557 586.579,43.879 704.359,43.879 "/>
|
||||
<polyline clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="
|
||||
548.902,81.557 595.284,81.557 626.291,112.564 731.628,112.564 770.827,112.564 "/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M714.159,43.879c0,5.413-4.388,9.8-9.8,9.8s-9.8-4.387-9.8-9.8
|
||||
c0-5.412,4.388-9.8,9.8-9.8S714.159,38.467,714.159,43.879"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="704.359" cy="43.879" r="9.8"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M780.627,112.564c0,5.413-4.388,9.8-9.8,9.8s-9.8-4.387-9.8-9.8
|
||||
c0-5.412,4.388-9.799,9.8-9.799S780.627,107.152,780.627,112.564"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="770.827" cy="112.564" r="9.8"/>
|
||||
<polyline clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="
|
||||
529.525,230.107 582.326,177.307 697.132,177.307 "/>
|
||||
<polyline clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="
|
||||
158.577,230.107 251.946,230.107 300.039,278.2 481.432,278.2 529.525,230.107 622.894,230.107 "/>
|
||||
<polyline clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" points="
|
||||
251.945,230.107 199.144,177.307 84.338,177.307 "/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M73.209,177.306c0,6.146,4.983,11.129,11.129,11.129
|
||||
s11.129-4.983,11.129-11.129s-4.983-11.129-11.129-11.129S73.209,171.16,73.209,177.306"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="84.338" cy="177.306" r="11.129"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M708.261,177.306c0,6.146-4.982,11.129-11.129,11.129
|
||||
c-6.146,0-11.129-4.983-11.129-11.129s4.983-11.129,11.129-11.129C703.278,166.177,708.261,171.16,708.261,177.306"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="697.132" cy="177.306" r="11.129"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M634.022,230.107c0,6.146-4.982,11.128-11.129,11.128
|
||||
s-11.129-4.982-11.129-11.128s4.982-11.129,11.129-11.129S634.022,223.961,634.022,230.107"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="622.894" cy="230.107" r="11.129"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#AEDAFF" d="M147.448,230.107c0,6.146,4.982,11.128,11.129,11.128
|
||||
c6.146,0,11.129-4.982,11.129-11.128s-4.983-11.129-11.129-11.129C152.43,218.979,147.448,223.961,147.448,230.107"/>
|
||||
|
||||
<circle clip-path="url(#SVGID_2_)" fill="none" stroke="#007EFF" stroke-width="9" stroke-miterlimit="10" cx="158.577" cy="230.107" r="11.129"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M272.659,240.478v-42.085h8.998v19.059l14.029-19.059h10.406l-15.063,19.174l15.609,22.911H295.8
|
||||
l-14.144-22.02v22.02H272.659z"/>
|
||||
<path fill="#FFFFFF" d="M304.803,240.478l16.012-42.085h10.291l16.242,42.085h-10.233l-3.421-8.94h-16.299l-2.932,8.94H304.803z
|
||||
M331.595,224.466l-4.714-13.597c-0.134-0.403-0.307-1.092-0.518-2.07s-0.431-2.175-0.661-3.593
|
||||
c-0.25,1.361-0.489,2.583-0.719,3.665c-0.23,1.083-0.402,1.807-0.518,2.17l-4.542,13.425H331.595z"/>
|
||||
<path fill="#FFFFFF" d="M382.218,240.478H371.84l-11.067-19.663v19.663h-8.998v-42.085h12.878c5.117,0,8.95,0.992,11.499,2.975
|
||||
s3.823,4.969,3.823,8.955c0,2.894-0.872,5.366-2.616,7.417c-1.744,2.051-3.996,3.249-6.755,3.594L382.218,240.478z
|
||||
M360.772,216.331h1.352c3.641,0,6.046-0.398,7.215-1.193c1.169-0.795,1.754-2.18,1.754-4.154c0-2.07-0.628-3.54-1.883-4.413
|
||||
c-1.255-0.872-3.618-1.308-7.086-1.308h-1.352V216.331z"/>
|
||||
<path fill="#FFFFFF" d="M387.622,240.478v-42.085h8.998v42.085H387.622z"/>
|
||||
<path fill="#FFFFFF" d="M406.222,240.478v-42.085h8.997v19.059l14.028-19.059h10.406l-15.063,19.174l15.609,22.911h-10.838
|
||||
l-14.144-22.02v22.02H406.222z"/>
|
||||
<path fill="#FFFFFF" d="M438.365,240.478l16.012-42.085h10.291l16.242,42.085h-10.234l-3.421-8.94h-16.299l-2.933,8.94H438.365z
|
||||
M465.156,224.466l-4.714-13.597c-0.135-0.403-0.307-1.092-0.518-2.07s-0.432-2.175-0.661-3.593
|
||||
c-0.249,1.361-0.488,2.583-0.719,3.665c-0.229,1.083-0.402,1.807-0.518,2.17l-4.542,13.425H465.156z"/>
|
||||
<path fill="#FFFFFF" d="M482.635,235.131l5.002-5.663c0.632,1.552,1.647,2.774,3.047,3.665c1.398,0.891,2.97,1.337,4.714,1.337
|
||||
c2.108,0,3.775-0.499,5.002-1.495c1.227-0.996,1.84-2.338,1.84-4.024c0-1.993-2.041-3.977-6.123-5.951
|
||||
c-1.322-0.632-2.367-1.15-3.133-1.552c-3.68-1.916-6.229-3.79-7.646-5.62c-1.419-1.83-2.128-4.01-2.128-6.54
|
||||
c0-3.469,1.375-6.319,4.125-8.552c2.75-2.232,6.319-3.349,10.709-3.349c2.548,0,4.747,0.446,6.597,1.337s3.483,2.285,4.901,4.183
|
||||
l-5.318,5.088c-0.632-1.226-1.471-2.142-2.515-2.745c-1.045-0.604-2.305-0.905-3.78-0.905c-1.782,0-3.22,0.445-4.313,1.336
|
||||
c-1.092,0.891-1.639,2.046-1.639,3.464c0,2.224,2.166,4.255,6.497,6.094c0.862,0.364,1.523,0.652,1.983,0.863
|
||||
c3.564,1.629,6.204,3.469,7.92,5.519c1.715,2.051,2.573,4.389,2.573,7.014c0,3.948-1.347,7.096-4.039,9.443
|
||||
c-2.693,2.348-6.311,3.521-10.853,3.521c-3.219,0-5.979-0.556-8.278-1.667C485.48,238.82,483.765,237.22,482.635,235.131z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M241.341,169.329l50.897-133.778h32.713l51.629,133.778H344.05l-10.874-28.418h-51.812l-9.32,28.418
|
||||
H241.341z M326.506,118.431L311.52,75.209c-0.427-1.279-0.975-3.473-1.645-6.579c-0.671-3.107-1.371-6.914-2.102-11.422
|
||||
c-0.792,4.326-1.553,8.209-2.284,11.65c-0.731,3.442-1.279,5.743-1.645,6.899l-14.438,42.673H326.506z"/>
|
||||
<path fill="#FFFFFF" d="M382.063,152.333l15.899-18.001c2.011,4.935,5.239,8.818,9.687,11.651
|
||||
c4.446,2.833,9.442,4.249,14.986,4.249c6.7,0,12-1.583,15.899-4.751c3.898-3.167,5.849-7.432,5.849-12.793
|
||||
c0-6.335-6.488-12.64-19.464-18.916c-4.203-2.01-7.524-3.655-9.96-4.935c-11.696-6.091-19.8-12.046-24.307-17.864
|
||||
c-4.509-5.817-6.763-12.747-6.763-20.789c0-11.025,4.371-20.087,13.113-27.185c8.741-7.096,20.088-10.646,34.038-10.646
|
||||
c8.102,0,15.092,1.417,20.972,4.249c5.878,2.833,11.071,7.265,15.58,13.295l-16.905,16.174c-2.01-3.898-4.676-6.808-7.995-8.727
|
||||
c-3.321-1.919-7.326-2.878-12.017-2.878c-5.665,0-10.234,1.417-13.707,4.25c-3.472,2.833-5.208,6.503-5.208,11.011
|
||||
c0,7.068,6.883,13.524,20.651,19.373c2.741,1.158,4.843,2.071,6.305,2.741c11.331,5.179,19.723,11.027,25.175,17.544
|
||||
c5.451,6.52,8.179,13.951,8.179,22.296c0,12.55-4.28,22.556-12.839,30.018c-8.56,7.463-20.058,11.194-34.495,11.194
|
||||
c-10.234,0-19.007-1.768-26.317-5.3C391.11,164.061,385.657,158.973,382.063,152.333z"/>
|
||||
<path fill="#FFFFFF" d="M496.013,169.329V35.551h28.602v133.778H496.013z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M275.115,237.214v-41.209h8.811v18.663l13.737-18.663h10.189l-14.75,18.775l15.284,22.435h-10.612
|
||||
l-13.849-21.562v21.562H275.115z"/>
|
||||
<path fill="#FFFFFF" d="M306.591,237.214l15.679-41.209h10.077l15.904,41.209h-10.021l-3.35-8.754h-15.96l-2.871,8.754H306.591z
|
||||
M332.825,221.535l-4.617-13.314c-0.131-0.394-0.3-1.069-0.506-2.026c-0.207-0.957-0.422-2.13-0.647-3.519
|
||||
c-0.244,1.333-0.479,2.529-0.704,3.589c-0.226,1.061-0.395,1.769-0.507,2.125l-4.448,13.146H332.825z"/>
|
||||
<path fill="#FFFFFF" d="M382.395,237.214h-10.162l-10.837-19.253v19.253h-8.811v-41.209h12.611c5.01,0,8.763,0.971,11.259,2.914
|
||||
c2.495,1.942,3.744,4.865,3.744,8.768c0,2.834-0.854,5.254-2.562,7.262c-1.708,2.008-3.913,3.181-6.615,3.519L382.395,237.214z
|
||||
M361.396,213.569h1.323c3.565,0,5.921-0.39,7.065-1.168c1.145-0.778,1.717-2.134,1.717-4.067c0-2.027-0.615-3.467-1.844-4.321
|
||||
c-1.229-0.854-3.542-1.281-6.938-1.281h-1.323V213.569z"/>
|
||||
<path fill="#FFFFFF" d="M387.687,237.214v-41.209h8.811v41.209H387.687z"/>
|
||||
<path fill="#FFFFFF" d="M405.898,237.214v-41.209h8.811v18.663l13.736-18.663h10.19l-14.75,18.775l15.284,22.435h-10.611
|
||||
l-13.85-21.562v21.562H405.898z"/>
|
||||
<path fill="#FFFFFF" d="M437.374,237.214l15.679-41.209h10.077l15.903,41.209h-10.021l-3.35-8.754h-15.96l-2.871,8.754H437.374z
|
||||
M463.608,221.535l-4.616-13.314c-0.132-0.394-0.301-1.069-0.507-2.026c-0.207-0.957-0.423-2.13-0.647-3.519
|
||||
c-0.244,1.333-0.479,2.529-0.704,3.589c-0.225,1.061-0.394,1.769-0.507,2.125l-4.447,13.146H463.608z"/>
|
||||
<path fill="#FFFFFF" d="M480.723,231.978l4.897-5.545c0.619,1.52,1.614,2.716,2.983,3.589c1.37,0.873,2.909,1.309,4.617,1.309
|
||||
c2.063,0,3.696-0.488,4.897-1.464c1.201-0.976,1.802-2.29,1.802-3.941c0-1.952-1.999-3.894-5.996-5.827
|
||||
c-1.295-0.619-2.317-1.126-3.068-1.52c-3.603-1.876-6.099-3.711-7.487-5.503s-2.083-3.927-2.083-6.404
|
||||
c0-3.396,1.347-6.188,4.039-8.375c2.693-2.186,6.188-3.279,10.485-3.279c2.496,0,4.649,0.437,6.461,1.309
|
||||
c1.811,0.873,3.41,2.238,4.799,4.096l-5.207,4.982c-0.62-1.201-1.44-2.097-2.464-2.688c-1.022-0.591-2.256-0.887-3.701-0.887
|
||||
c-1.745,0-3.152,0.437-4.223,1.309c-1.069,0.873-1.604,2.003-1.604,3.392c0,2.177,2.12,4.166,6.361,5.968
|
||||
c0.844,0.356,1.491,0.638,1.942,0.844c3.49,1.595,6.075,3.397,7.755,5.405c1.679,2.008,2.519,4.297,2.519,6.868
|
||||
c0,3.866-1.318,6.948-3.954,9.247c-2.637,2.299-6.179,3.448-10.626,3.448c-3.153,0-5.855-0.544-8.107-1.632
|
||||
C483.509,235.591,481.829,234.024,480.723,231.978z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M244.45,168.546l49.838-130.995h32.033l50.554,130.995h-31.854l-10.648-27.828h-50.733l-9.127,27.828
|
||||
H244.45z M327.843,118.707l-14.674-42.323c-0.418-1.252-0.955-3.4-1.61-6.442c-0.657-3.042-1.342-6.77-2.058-11.185
|
||||
c-0.776,4.236-1.521,8.039-2.237,11.408c-0.716,3.371-1.253,5.623-1.611,6.756l-14.137,41.786H327.843z"/>
|
||||
<path fill="#FFFFFF" d="M382.245,151.903l15.568-17.627c1.969,4.832,5.13,8.635,9.485,11.409c4.354,2.774,9.245,4.161,14.674,4.161
|
||||
c6.562,0,11.751-1.55,15.569-4.653c3.816-3.101,5.727-7.277,5.727-12.527c0-6.203-6.354-12.377-19.059-18.522
|
||||
c-4.116-1.968-7.368-3.579-9.753-4.832c-11.453-5.964-19.388-11.796-23.802-17.493c-4.415-5.696-6.621-12.482-6.621-20.356
|
||||
c0-10.796,4.279-19.669,12.84-26.619c8.56-6.949,19.67-10.424,33.331-10.424c7.933,0,14.777,1.387,20.534,4.161
|
||||
c5.756,2.774,10.841,7.114,15.256,13.019l-16.553,15.837c-1.969-3.817-4.579-6.666-7.829-8.545
|
||||
c-3.252-1.879-7.174-2.818-11.767-2.818c-5.548,0-10.021,1.387-13.422,4.161c-3.399,2.773-5.1,6.368-5.1,10.782
|
||||
c0,6.92,6.74,13.243,20.222,18.969c2.685,1.134,4.742,2.029,6.174,2.684c11.096,5.071,19.312,10.798,24.651,17.18
|
||||
c5.338,6.384,8.008,13.661,8.008,21.833c0,12.289-4.191,22.087-12.571,29.394c-8.382,7.308-19.641,10.961-33.778,10.961
|
||||
c-10.021,0-18.61-1.731-25.769-5.19C391.104,163.387,385.764,158.406,382.245,151.903z"/>
|
||||
<path fill="#FFFFFF" d="M493.823,168.546V37.551h28.007v130.995H493.823z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
8
public/assets/tipilan-icon-black.svg
Normal file
8
public/assets/tipilan-icon-black.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="175" height="150" viewBox="0 0 175 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M67.5 110V122.5V137.5C67.5 137.933 67.5219 138.36 67.5644 138.781C67.607 139.202 67.6699 139.618 67.7529 140.025C67.8358 140.433 67.939 140.833 68.0605 141.225C68.1818 141.617 68.3217 142.001 68.4794 142.375C68.6372 142.749 68.8118 143.114 69.0038 143.468C69.1958 143.822 69.4046 144.166 69.6288 144.498C69.853 144.83 70.0932 145.152 70.3476 145.46C70.6019 145.768 70.8708 146.064 71.1532 146.347C71.4357 146.629 71.7315 146.898 72.0399 147.152C72.3484 147.407 72.6695 147.647 73.0019 147.871C73.3343 148.095 73.6779 148.304 74.0321 148.496C74.3864 148.688 74.7508 148.863 75.1249 149.021C75.499 149.178 75.8834 149.318 76.2753 149.439C76.6672 149.561 77.0669 149.664 77.4745 149.747C77.8821 149.83 78.2974 149.893 78.7187 149.936C79.1399 149.978 79.5671 150 79.9999 150H94.9999C95.4327 150 95.8599 149.978 96.2812 149.936C96.7024 149.893 97.1177 149.83 97.5253 149.747C97.9329 149.664 98.3336 149.561 98.7255 149.439C99.1174 149.318 99.5008 149.178 99.8749 149.021C100.249 148.863 100.613 148.688 100.968 148.496C101.322 148.304 101.666 148.095 101.998 147.871C102.33 147.647 102.651 147.407 102.96 147.152C103.268 146.898 103.564 146.629 103.847 146.347C104.129 146.064 104.398 145.768 104.652 145.46C104.907 145.152 105.147 144.83 105.371 144.498C105.595 144.166 105.804 143.822 105.996 143.468C106.188 143.114 106.363 142.749 106.52 142.375C106.678 142.001 106.818 141.617 106.939 141.225C107.061 140.833 107.164 140.433 107.247 140.025C107.33 139.618 107.393 139.202 107.435 138.781C107.478 138.36 107.5 137.933 107.5 137.5V122.5V110H94.9998H79.9998H67.5Z" fill="#0A121F"/>
|
||||
<path d="M25 57.5L87.5 102.5L150 57.5L93.75 80L87.5 57.5L81.25 80L25 57.5Z" fill="#0A121F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M125 0V12.5V37.5V50H137.5H162.5C162.933 50 163.36 49.9781 163.781 49.9356C164.202 49.893 164.618 49.8301 165.025 49.7472C165.433 49.6642 165.834 49.561 166.226 49.4395C166.617 49.3182 167.001 49.1783 167.375 49.0206C167.749 48.863 168.113 48.6882 168.468 48.4962C168.822 48.3042 169.166 48.0954 169.498 47.8712C169.83 47.647 170.152 47.4068 170.46 47.1524C170.768 46.8981 171.064 46.6292 171.347 46.3468C171.629 46.0643 171.898 45.7685 172.152 45.4601C172.407 45.1516 172.647 44.8306 172.871 44.4982C173.095 44.1658 173.304 43.8222 173.496 43.4679C173.688 43.1136 173.863 42.7492 174.02 42.3751C174.178 42.0009 174.318 41.6166 174.439 41.2247C174.561 40.8328 174.664 40.4331 174.747 40.0255C174.83 39.6179 174.893 39.2026 174.936 38.7814C174.978 38.3601 175 37.9329 175 37.5001V12.5001V5.7671e-05H162.5H137.5L125 0Z" fill="#0A121F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M62.5 0V50H112.5V0H62.5Z" fill="#0A121F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0.000115342V12.5001V37.5001C0 37.9329 0.0219205 38.3601 0.0644401 38.7814C0.10696 39.2026 0.169891 39.6179 0.252851 40.0255C0.335812 40.4331 0.438994 40.8328 0.560468 41.2247C0.681791 41.6166 0.821689 42.001 0.979409 42.3751C1.1372 42.7492 1.31282 43.1136 1.5048 43.4679C1.69678 43.8222 1.90464 44.1658 2.12882 44.4982C2.35302 44.8306 2.59323 45.1516 2.84757 45.4601C3.10191 45.7685 3.37083 46.0644 3.65324 46.3468C3.93566 46.6292 4.23152 46.8982 4.53995 47.1525C4.8484 47.4068 5.16947 47.647 5.50188 47.8712C5.83427 48.0954 6.17787 48.3042 6.53214 48.4962C6.88643 48.6882 7.2508 48.8629 7.62492 49.0206C7.99903 49.1784 8.38343 49.3182 8.77531 49.4395C9.16719 49.5609 9.56693 49.6642 9.97453 49.7472C10.3821 49.8301 10.7974 49.893 11.2187 49.9356C11.6399 49.9781 12.0671 50 12.4999 50H37.4999H49.9999V37.5V12.5V0H37.4999H12.4999L0 0.000115342Z" fill="#0A121F"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
8
public/assets/tipilan-icon-white.svg
Normal file
8
public/assets/tipilan-icon-white.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="175" height="150" viewBox="0 0 175 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M67.5 110V122.5V137.5C67.5 137.933 67.5219 138.36 67.5644 138.781C67.607 139.202 67.6699 139.618 67.7529 140.025C67.8358 140.433 67.939 140.833 68.0605 141.225C68.1818 141.617 68.3217 142.001 68.4794 142.375C68.6372 142.749 68.8118 143.114 69.0038 143.468C69.1958 143.822 69.4046 144.166 69.6288 144.498C69.853 144.83 70.0932 145.152 70.3476 145.46C70.6019 145.768 70.8708 146.064 71.1532 146.347C71.4357 146.629 71.7315 146.898 72.0399 147.152C72.3484 147.407 72.6695 147.647 73.0019 147.871C73.3343 148.095 73.6779 148.304 74.0321 148.496C74.3864 148.688 74.7508 148.863 75.1249 149.021C75.499 149.178 75.8834 149.318 76.2753 149.439C76.6672 149.561 77.0669 149.664 77.4745 149.747C77.8821 149.83 78.2974 149.893 78.7187 149.936C79.1399 149.978 79.5671 150 79.9999 150H94.9999C95.4327 150 95.8599 149.978 96.2812 149.936C96.7024 149.893 97.1177 149.83 97.5253 149.747C97.9329 149.664 98.3336 149.561 98.7255 149.439C99.1174 149.318 99.5008 149.178 99.8749 149.021C100.249 148.863 100.613 148.688 100.968 148.496C101.322 148.304 101.666 148.095 101.998 147.871C102.33 147.647 102.651 147.407 102.96 147.152C103.268 146.898 103.564 146.629 103.847 146.347C104.129 146.064 104.398 145.768 104.652 145.46C104.907 145.152 105.147 144.83 105.371 144.498C105.595 144.166 105.804 143.822 105.996 143.468C106.188 143.114 106.363 142.749 106.52 142.375C106.678 142.001 106.818 141.617 106.939 141.225C107.061 140.833 107.164 140.433 107.247 140.025C107.33 139.618 107.393 139.202 107.435 138.781C107.478 138.36 107.5 137.933 107.5 137.5V122.5V110H94.9998H79.9998H67.5Z" fill="white"/>
|
||||
<path d="M25 57.5L87.5 102.5L150 57.5L93.75 80L87.5 57.5L81.25 80L25 57.5Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M125 0V12.5V37.5V50H137.5H162.5C162.933 50 163.36 49.9781 163.781 49.9356C164.202 49.893 164.618 49.8301 165.025 49.7472C165.433 49.6642 165.834 49.561 166.226 49.4395C166.617 49.3182 167.001 49.1783 167.375 49.0206C167.749 48.863 168.113 48.6882 168.468 48.4962C168.822 48.3042 169.166 48.0954 169.498 47.8712C169.83 47.647 170.152 47.4068 170.46 47.1524C170.768 46.8981 171.064 46.6292 171.347 46.3468C171.629 46.0643 171.898 45.7685 172.152 45.4601C172.407 45.1516 172.647 44.8306 172.871 44.4982C173.095 44.1658 173.304 43.8222 173.496 43.4679C173.688 43.1136 173.863 42.7492 174.02 42.3751C174.178 42.0009 174.318 41.6166 174.439 41.2247C174.561 40.8328 174.664 40.4331 174.747 40.0255C174.83 39.6179 174.893 39.2026 174.936 38.7814C174.978 38.3601 175 37.9329 175 37.5001V12.5001V5.7671e-05H162.5H137.5L125 0Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M62.5 0V50H112.5V0H62.5Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0.000115342V12.5001V37.5001C0 37.9329 0.0219205 38.3601 0.0644401 38.7814C0.10696 39.2026 0.169891 39.6179 0.252851 40.0255C0.335812 40.4331 0.438994 40.8328 0.560468 41.2247C0.681791 41.6166 0.821689 42.001 0.979409 42.3751C1.1372 42.7492 1.31282 43.1136 1.5048 43.4679C1.69678 43.8222 1.90464 44.1658 2.12882 44.4982C2.35302 44.8306 2.59323 45.1516 2.84757 45.4601C3.10191 45.7685 3.37083 46.0644 3.65324 46.3468C3.93566 46.6292 4.23152 46.8982 4.53995 47.1525C4.8484 47.4068 5.16947 47.647 5.50188 47.8712C5.83427 48.0954 6.17787 48.3042 6.53214 48.4962C6.88643 48.6882 7.2508 48.8629 7.62492 49.0206C7.99903 49.1784 8.38343 49.3182 8.77531 49.4395C9.16719 49.5609 9.56693 49.6642 9.97453 49.7472C10.3821 49.8301 10.7974 49.893 11.2187 49.9356C11.6399 49.9781 12.0671 50 12.4999 50H37.4999H49.9999V37.5V12.5V0H37.4999H12.4999L0 0.000115342Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
12
src/App.vue
12
src/App.vue
@@ -1,8 +1,20 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { Router, text } from "./lib/index.js";
|
||||
import { routes } from "./routes/index.js";
|
||||
import Navbar from "./layout/Navbar.vue";
|
||||
import Footer from "./layout/Footer.vue";
|
||||
|
||||
// Handle redirect from 404 page (replaces inline script in index.html)
|
||||
onMounted(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const redirect = sessionStorage.redirect;
|
||||
if (redirect && redirect !== window.location.href) {
|
||||
window.history.replaceState(null, null, redirect);
|
||||
}
|
||||
delete sessionStorage.redirect;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,22 @@
|
||||
export { navigate, goBack, reload, getPath, getQuery, switchLanguageRoute } from './router/router.js';
|
||||
export { useRouter } from './router/useRouter.js';
|
||||
export { default as Router } from './router/Router.vue';
|
||||
|
||||
export { currentLang, currentLocale, languageLocales, text, switchLang, usePageText } from './i18n.js';
|
||||
export { useLang } from './useLang.js';
|
||||
export { useImage } from './useImage.js';
|
||||
export { useYaml } from './useYaml.js';
|
||||
|
||||
// Backwards compatibility exports from old utilities
|
||||
export { navigate, goBack, reload, getPath, getQuery, switchLanguageRoute } from './router/router.js';
|
||||
export { getLangText } from './langHelpers.js';
|
||||
export { loadYaml } from './yaml.js';
|
||||
export {
|
||||
getRootAssetPath,
|
||||
getOptimisedImagePath,
|
||||
getHeroImagePath,
|
||||
getHeroImageSrcSet,
|
||||
getHeroImageFallback,
|
||||
getResponsiveImageSrcSet,
|
||||
getOptimisedImageSrcSet,
|
||||
getOptimisedImageFallback
|
||||
} from './imageHelpers.js';
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
<script setup>
|
||||
import { onBeforeUnmount, onMounted, shallowRef, watch } from 'vue';
|
||||
import { useRouter } from './useRouter.js';
|
||||
import { getLanguageFromRoute, getTranslatedRoute } from '../../routes';
|
||||
import { switchLang } from '../i18n.js';
|
||||
|
||||
const props = defineProps({ routes: { type: Object, required: true } });
|
||||
const currentPath = shallowRef(window.location.pathname);
|
||||
const router = useRouter();
|
||||
const currentPath = shallowRef(typeof window !== 'undefined' ? window.location.pathname : '/');
|
||||
const CurrentComponent = shallowRef(null);
|
||||
let routeRequest = 0;
|
||||
|
||||
// Sync with router composable's currentPath
|
||||
watch(() => router.currentPath.value, (path) => {
|
||||
currentPath.value = path;
|
||||
}, { immediate: true });
|
||||
|
||||
async function resolveCurrentComponent(path) {
|
||||
const request = ++routeRequest;
|
||||
const routeEntry = props.routes[path] || props.routes['/'];
|
||||
@@ -26,11 +35,21 @@ function navigate(url) {
|
||||
window.history.pushState({}, '', `${url.pathname}${url.search}${url.hash}`);
|
||||
window.scrollTo(0, 0);
|
||||
currentPath.value = url.pathname;
|
||||
router.currentPath.value = url.pathname;
|
||||
window.dispatchEvent(new PopStateEvent('popstate'));
|
||||
|
||||
// Handle language switching based on route
|
||||
const lang = getLanguageFromRoute(url.pathname);
|
||||
if (lang) switchLang(lang);
|
||||
}
|
||||
|
||||
const handlePopState = () => {
|
||||
currentPath.value = window.location.pathname;
|
||||
const newPath = window.location.pathname;
|
||||
currentPath.value = newPath;
|
||||
router.currentPath.value = newPath;
|
||||
|
||||
const lang = getLanguageFromRoute(newPath);
|
||||
if (lang) switchLang(lang);
|
||||
};
|
||||
|
||||
const handleClick = (event) => {
|
||||
@@ -54,6 +73,7 @@ onBeforeUnmount(() => {
|
||||
window.removeEventListener('popstate', handlePopState);
|
||||
window.removeEventListener('click', handleClick);
|
||||
});
|
||||
|
||||
watch(currentPath, resolveCurrentComponent, { immediate: true });
|
||||
</script>
|
||||
|
||||
|
||||
125
src/lib/router/useRouter.js
Normal file
125
src/lib/router/useRouter.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { computed, onScopeDispose, ref, watch } from 'vue';
|
||||
import { getLanguageFromRoute, getTranslatedRoute } from '../../routes';
|
||||
import { switchLang } from '../i18n.js';
|
||||
|
||||
/**
|
||||
* Vue composable for router functionality
|
||||
* Provides reactive navigation and route management
|
||||
*/
|
||||
export function useRouter() {
|
||||
const currentPath = ref(typeof window !== 'undefined' ? window.location.pathname : '/');
|
||||
const currentRoute = computed(() => currentPath.value);
|
||||
|
||||
/**
|
||||
* Navigate to a path (internal or external)
|
||||
* @param {string} path - The path or URL to navigate to
|
||||
* @param {Object} options - Navigation options
|
||||
* @param {boolean} options.external - Whether this is an external link
|
||||
*/
|
||||
function navigate(path, options = {}) {
|
||||
const { external = false } = options;
|
||||
|
||||
if (external) {
|
||||
window.open(path, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = new URL(path, window.location.origin);
|
||||
if (url.origin !== window.location.origin) {
|
||||
window.location.assign(url.href);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedLang =
|
||||
getLanguageFromRoute(window.location.pathname) ||
|
||||
localStorage.getItem('language') ||
|
||||
'est';
|
||||
url.pathname = getTranslatedRoute(url.pathname, selectedLang);
|
||||
commitNavigation(`${url.pathname}${url.search}${url.hash}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit navigation by updating history and path
|
||||
*/
|
||||
function commitNavigation(path) {
|
||||
window.history.pushState({}, '', path);
|
||||
window.scrollTo(0, 0);
|
||||
currentPath.value = path;
|
||||
window.dispatchEvent(new PopStateEvent('popstate'));
|
||||
|
||||
const lang = getLanguageFromRoute(new URL(path, window.location.origin).pathname);
|
||||
if (lang) switchLang(lang);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch language and navigate to translated route
|
||||
* @param {string} targetLang - Target language ('est' or 'en')
|
||||
*/
|
||||
function switchLanguageRoute(targetLang) {
|
||||
const currentPath = window.location.pathname;
|
||||
const translatedPath = getTranslatedRoute(currentPath, targetLang);
|
||||
|
||||
switchLang(targetLang);
|
||||
|
||||
if (translatedPath !== currentPath) {
|
||||
commitNavigation(translatedPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Go back in browser history
|
||||
*/
|
||||
function goBack() {
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the current page
|
||||
*/
|
||||
function reload() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current pathname
|
||||
* @returns {string} Current path
|
||||
*/
|
||||
function getPath() {
|
||||
return currentPath.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL query parameters as an object
|
||||
* @returns {Object} Query parameters
|
||||
*/
|
||||
function getQuery() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return Object.fromEntries(params.entries());
|
||||
}
|
||||
|
||||
// Set up popstate listener for browser navigation
|
||||
if (typeof window !== 'undefined') {
|
||||
const handlePopState = () => {
|
||||
currentPath.value = window.location.pathname;
|
||||
const lang = getLanguageFromRoute(window.location.pathname);
|
||||
if (lang) switchLang(lang);
|
||||
};
|
||||
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
|
||||
onScopeDispose(() => {
|
||||
window.removeEventListener('popstate', handlePopState);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
currentPath,
|
||||
currentRoute,
|
||||
navigate,
|
||||
switchLanguageRoute,
|
||||
goBack,
|
||||
reload,
|
||||
getPath,
|
||||
getQuery
|
||||
};
|
||||
}
|
||||
124
src/lib/useImage.js
Normal file
124
src/lib/useImage.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
getRootAssetPath,
|
||||
getOptimisedImagePath,
|
||||
getHeroImagePath,
|
||||
getHeroImageSrcSet,
|
||||
getHeroImageFallback,
|
||||
getResponsiveImageSrcSet,
|
||||
getOptimisedImageSrcSet,
|
||||
getOptimisedImageFallback
|
||||
} from './imageHelpers.js';
|
||||
|
||||
/**
|
||||
* Vue composable for image handling
|
||||
* Provides reactive image path generation
|
||||
*/
|
||||
export function useImage() {
|
||||
/**
|
||||
* Get an asset path from category root
|
||||
* @param {string} category - e.g., "helpdesk-page-images"
|
||||
* @param {string} filename - e.g., "helpdesk-icon.svg" or "helpdesk-icon"
|
||||
* @param {string} defaultExt - e.g., "svg"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getRootAssetPathComputed = (category, filename, defaultExt = "svg") => {
|
||||
return computed(() => getRootAssetPath(category, filename, defaultExt));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the optimised image path
|
||||
* @param {string} category - e.g., "mentors-images", "past-management-images"
|
||||
* @param {string} filename - e.g., "mari.jpg"
|
||||
* @param {string} format - "webp" or "jpg" (default: "webp")
|
||||
* @param {string} variant - e.g., "full", "400", "800", "1200" (default: "full")
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getOptimisedImagePathComputed = (category, filename, format = "webp", variant = "full") => {
|
||||
return computed(() => getOptimisedImagePath(category, filename, format, variant));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the hero image path
|
||||
* @param {string} category - e.g., "home-page-images"
|
||||
* @param {string} filename - e.g., "hero.png"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getHeroImagePathComputed = (category, filename) => {
|
||||
return computed(() => getHeroImagePath(category, filename));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get srcset for hero/background images with responsive variants
|
||||
* @param {string} category - e.g., "home-page-images"
|
||||
* @param {string} filename - e.g., "hero.png"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getHeroImageSrcSetComputed = (category, filename) => {
|
||||
return computed(() => getHeroImageSrcSet(category, filename));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the fallback (jpg) path for hero images
|
||||
* @param {string} category - e.g., "home-page-images"
|
||||
* @param {string} filename - e.g., "hero.png"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getHeroImageFallbackComputed = (category, filename) => {
|
||||
return computed(() => getHeroImageFallback(category, filename));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get srcset for responsive variants
|
||||
* @param {string} category - e.g., "home-page-images"
|
||||
* @param {string} filename - e.g., "hero.png"
|
||||
* @param {number[]} widths - e.g., [400, 800, 1200]
|
||||
* @param {string} format - "webp" or "jpg"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getResponsiveImageSrcSetComputed = (category, filename, widths = [400, 800, 1200], format = "webp") => {
|
||||
return computed(() => getResponsiveImageSrcSet(category, filename, widths, format));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get srcset for regular optimised images (full variant only)
|
||||
* @param {string} category - e.g., "mentors-images"
|
||||
* @param {string} filename - e.g., "mari.jpg"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getOptimisedImageSrcSetComputed = (category, filename) => {
|
||||
return computed(() => getOptimisedImageSrcSet(category, filename));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the fallback jpg for regular optimised images
|
||||
* @param {string} category - e.g., "mentors-images"
|
||||
* @param {string} filename - e.g., "mari.jpg"
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getOptimisedImageFallbackComputed = (category, filename) => {
|
||||
return computed(() => getOptimisedImageFallback(category, filename));
|
||||
};
|
||||
|
||||
return {
|
||||
// Computed versions
|
||||
getRootAssetPathComputed,
|
||||
getOptimisedImagePathComputed,
|
||||
getHeroImagePathComputed,
|
||||
getHeroImageSrcSetComputed,
|
||||
getHeroImageFallbackComputed,
|
||||
getResponsiveImageSrcSetComputed,
|
||||
getOptimisedImageSrcSetComputed,
|
||||
getOptimisedImageFallbackComputed,
|
||||
|
||||
// Original functions for backwards compatibility
|
||||
getRootAssetPath,
|
||||
getOptimisedImagePath,
|
||||
getHeroImagePath,
|
||||
getHeroImageSrcSet,
|
||||
getHeroImageFallback,
|
||||
getResponsiveImageSrcSet,
|
||||
getOptimisedImageSrcSet,
|
||||
getOptimisedImageFallback
|
||||
};
|
||||
}
|
||||
37
src/lib/useLang.js
Normal file
37
src/lib/useLang.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { computed } from 'vue';
|
||||
import { getLangText } from './langHelpers.js';
|
||||
import { currentLang } from './i18n.js';
|
||||
|
||||
/**
|
||||
* Vue composable for language helpers
|
||||
* Provides reactive language text handling
|
||||
*/
|
||||
export function useLang() {
|
||||
/**
|
||||
* Get text with language fallback (reactive version)
|
||||
* @param {Object} item - The item containing text
|
||||
* @param {string} key - The key to get text for
|
||||
* @returns {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const getLangTextComputed = (item, key) => {
|
||||
return computed(() => getLangText(item, key, currentLang.value));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get text with specific language fallback
|
||||
* @param {Object} item - The item containing text
|
||||
* @param {string} key - The key to get text for
|
||||
* @param {string} lang - Specific language to use (default: current language)
|
||||
* @returns {string}
|
||||
*/
|
||||
const getLangTextStatic = (item, key, lang = currentLang.value) => {
|
||||
return getLangText(item, key, lang);
|
||||
};
|
||||
|
||||
return {
|
||||
getLangTextComputed,
|
||||
getLangTextStatic,
|
||||
// Original function for backwards compatibility
|
||||
getLangText
|
||||
};
|
||||
}
|
||||
43
src/lib/useYaml.js
Normal file
43
src/lib/useYaml.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { ref } from 'vue';
|
||||
import { loadYaml } from './yaml.js';
|
||||
|
||||
/**
|
||||
* Vue composable for YAML data loading
|
||||
* Provides reactive YAML data loading
|
||||
*/
|
||||
export function useYaml() {
|
||||
/**
|
||||
* Load YAML data reactively
|
||||
* @param {string} path - Path to the YAML file
|
||||
* @param {any} fallback - Fallback value if loading fails
|
||||
* @returns {import('vue').Ref<any>} Reactive reference to the loaded data
|
||||
*/
|
||||
const loadYamlComposable = (path, fallback) => {
|
||||
const data = ref(fallback);
|
||||
const loading = ref(true);
|
||||
const error = ref(null);
|
||||
|
||||
loadYaml(path, fallback)
|
||||
.then((result) => {
|
||||
data.value = result;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
error.value = err;
|
||||
data.value = fallback;
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
loading,
|
||||
error
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
loadYamlComposable,
|
||||
// Original function for backwards compatibility
|
||||
loadYaml
|
||||
};
|
||||
}
|
||||
@@ -4,18 +4,21 @@
|
||||
Grid,
|
||||
} from "../components/index.js";
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { usePageText } from "../lib/index.js";
|
||||
import { getHeroImageFallback, getHeroImageSrcSet, getRootAssetPath } from "../lib/imageHelpers.js";
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { useRouter, usePageText, useImage, useYaml } from "../lib/index.js";
|
||||
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
import { navigate } from "../lib/router/router.js";
|
||||
import { createElement, BusFront, MapPin } from 'lucide';
|
||||
|
||||
// Initialize composables
|
||||
const router = useRouter();
|
||||
const image = useImage();
|
||||
const yaml = useYaml();
|
||||
|
||||
// Images
|
||||
const helpdeskbg = getHeroImageFallback("helpdesk-page-images", "helpdesk_bg");
|
||||
const helpdeskbgWebpSet = getHeroImageSrcSet("helpdesk-page-images", "helpdesk_bg");
|
||||
const helpdesk = getRootAssetPath("helpdesk-page-images", "helpdesk-on-black.png");
|
||||
const helpdeskbg = image.getHeroImageFallback("helpdesk-page-images", "helpdesk_bg");
|
||||
const helpdeskbgWebpSet = image.getHeroImageSrcSet("helpdesk-page-images", "helpdesk_bg");
|
||||
const helpdesk = image.getRootAssetPath("helpdesk-page-images", "helpdesk-on-black.png");
|
||||
|
||||
// Coordinates for Akadeemia tee 5, 12616 Tallinn [longitude, latitude]
|
||||
const center = [24.66887400515207, 59.396427975093935];
|
||||
@@ -35,7 +38,7 @@
|
||||
|
||||
// Navigate to directions using router
|
||||
const openDirections = (lng, lat, loc) => {
|
||||
navigate(getDirectionsUrl(lng, lat, loc), { external: true });
|
||||
router.navigate(getDirectionsUrl(lng, lat, loc), { external: true });
|
||||
};
|
||||
|
||||
// Load pricing data
|
||||
@@ -46,7 +49,7 @@
|
||||
const text = usePageText("Helpdesk");
|
||||
|
||||
onMounted(async () => {
|
||||
pricingData.value = await loadYaml('/_data/hinnakiri.yml', { services: [] });
|
||||
pricingData.value = await yaml.loadYaml('/_data/hinnakiri.yml', { services: [] });
|
||||
if (disposed || !mapElement.value) return;
|
||||
|
||||
map = new maplibregl.Map({
|
||||
@@ -70,9 +73,8 @@
|
||||
marker.setAttribute('aria-label', `Get directions to ${label}`);
|
||||
const markerLabel = document.createElement('span');
|
||||
markerLabel.textContent = label;
|
||||
const markerIcon = document.createElement('b');
|
||||
const markerIcon = type === 'bus' ? createElement(BusFront) : createElement(MapPin);
|
||||
markerIcon.setAttribute('aria-hidden', 'true');
|
||||
markerIcon.textContent = type === 'bus' ? '●' : '◆';
|
||||
marker.replaceChildren(markerLabel, markerIcon);
|
||||
marker.addEventListener('click', () => openDirections(coordinates[0], coordinates[1], type));
|
||||
new maplibregl.Marker({ element: marker }).setLngLat(coordinates).addTo(map);
|
||||
@@ -211,6 +213,6 @@
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 2px 5px rgb(0 0 0 / 20%);
|
||||
}
|
||||
.helpdesk-marker--location span { background: var(--orange); color: white; }
|
||||
.helpdesk-marker b { color: var(--orange); font-size: 1.5rem; line-height: 1; }
|
||||
.helpdesk-marker--location span { background: var(--color-orange-500); color: white; }
|
||||
.helpdesk-marker svg { color: var(--color-orange-500); width: 1.5rem; height: 1.5rem; }
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
<script setup>
|
||||
import {Section, Stack, Grid, Center, Image, Svg, Button} from "../components/index.js";
|
||||
import { navigate } from "../lib/router/router.js";
|
||||
import { usePageText, currentLang } from "../lib/index.js";
|
||||
import { getHeroImagePath, getHeroImageSrcSet, getHeroImageFallback, getOptimisedImagePath, getOptimisedImageFallback } from "../lib/imageHelpers.js";
|
||||
import { useRouter, usePageText, currentLang, useImage, useYaml } from "../lib/index.js";
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
|
||||
import { ArrowRight } from "@lucide/vue";
|
||||
import { ArrowLeft } from "@lucide/vue";
|
||||
|
||||
// Initialize composables
|
||||
const router = useRouter();
|
||||
const image = useImage();
|
||||
const yaml = useYaml();
|
||||
|
||||
// Partners data
|
||||
const partners = ref([]);
|
||||
const text = usePageText("Home");
|
||||
|
||||
|
||||
// Load partners data using yaml composable
|
||||
onMounted(async () => {
|
||||
partners.value = await loadYaml('/_data/partners.yml', []);
|
||||
partners.value = await yaml.loadYaml('/_data/partners.yml', []);
|
||||
});
|
||||
|
||||
const partnerLogoExtByName = {
|
||||
@@ -37,9 +40,9 @@
|
||||
<div class="relative min-h-screen flex items-center">
|
||||
<div class="absolute inset-0 left-1/2 w-screen -translate-x-1/2" aria-hidden="true">
|
||||
<Image
|
||||
:webpSrc="getHeroImagePath('home-page-images', 'hero')"
|
||||
:src="getHeroImageFallback('home-page-images', 'hero')"
|
||||
:webpSrcSet="getHeroImageSrcSet('home-page-images', 'hero')"
|
||||
:webpSrc="image.getHeroImagePath('home-page-images', 'hero')"
|
||||
:src="image.getHeroImageFallback('home-page-images', 'hero')"
|
||||
:webpSrcSet="image.getHeroImageSrcSet('home-page-images', 'hero')"
|
||||
:alt="text['hero']?.imageAlt || 'illustrative hero image'"
|
||||
objectFit="cover"
|
||||
class="w-full h-full"
|
||||
@@ -72,7 +75,7 @@
|
||||
</p>
|
||||
<Button
|
||||
class="rounded-lg border-orange-500 bg-orange-500 px-3 py-2 text-gray-900 transition-colors hover:border-orange-300 hover:bg-orange-300"
|
||||
:onClick="() => navigate('/tudengile')"
|
||||
:onClick="() => router.navigate('/tudengile')"
|
||||
>
|
||||
{{ text.hero?.joinButton || "Liitu LAPikutega!" }}
|
||||
</Button>
|
||||
@@ -99,8 +102,8 @@
|
||||
<Center dir="col" class="w-full max-w-sm justify-start mx-auto">
|
||||
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('home-page-images', 'student_temp', 'webp')"
|
||||
:src="getOptimisedImageFallback('home-page-images', 'student_temp')"
|
||||
:webpSrc="image.getOptimisedImagePath('home-page-images', 'student_temp', 'webp')"
|
||||
:src="image.getOptimisedImageFallback('home-page-images', 'student_temp')"
|
||||
:alt="text['services']?.student?.imageAlt || 'Tudengile Pilt'"
|
||||
objectFit="cover"
|
||||
class="w-full h-full rounded-full object-[center_35%]"
|
||||
@@ -114,8 +117,8 @@
|
||||
<Center dir="col" class="w-full max-w-sm justify-start mx-auto">
|
||||
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('home-page-images', 'helpdesk', 'webp')"
|
||||
:src="getOptimisedImageFallback('home-page-images', 'helpdesk')"
|
||||
:webpSrc="image.getOptimisedImagePath('home-page-images', 'helpdesk', 'webp')"
|
||||
:src="image.getOptimisedImageFallback('home-page-images', 'helpdesk')"
|
||||
:alt="text['services']?.helpdesk?.imageAlt || 'Helpdesk Pilt'"
|
||||
objectFit="cover"
|
||||
class="w-full h-full rounded-full object-[center_38%]"
|
||||
@@ -129,8 +132,8 @@
|
||||
<Center dir="col" class="w-full max-w-sm justify-start mx-auto md:col-span-2 lg:col-span-1">
|
||||
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('home-page-images', 'company_temp', 'webp')"
|
||||
:src="getOptimisedImageFallback('home-page-images', 'company_temp')"
|
||||
:webpSrc="image.getOptimisedImagePath('home-page-images', 'company_temp', 'webp')"
|
||||
:src="image.getOptimisedImageFallback('home-page-images', 'company_temp')"
|
||||
:alt="text['services']?.company?.imageAlt || 'Ettevõttele Pilt'"
|
||||
objectFit="cover"
|
||||
class="w-full h-full rounded-full object-[center_25%]"
|
||||
@@ -175,7 +178,7 @@
|
||||
<div class="flex flex-col items-start gap-6">
|
||||
<Button
|
||||
class="rounded-md border-3 border-orange-500 bg-transparent px-10 py-2 transition-colors hover:bg-orange-500/10"
|
||||
:onClick="() => navigate(currentLang === 'en' ? '/aboutus' : '/lapikutest')"
|
||||
:onClick="() => router.navigate(currentLang === 'en' ? '/aboutus' : '/lapikutest')"
|
||||
>
|
||||
{{ text.aboutSection?.moreInfo || "Rohkem infot" }}
|
||||
</Button>
|
||||
@@ -183,7 +186,7 @@
|
||||
<div class="flex items-center gap-4">
|
||||
<Button
|
||||
class="border-orange-500 bg-orange-500 px-20 py-2 transition-colors hover:border-orange-300 hover:bg-orange-300"
|
||||
:onClick="() => navigate(currentLang === 'en' ? '/contact' : '/kontakt')"
|
||||
:onClick="() => router.navigate(currentLang === 'en' ? '/contact' : '/kontakt')"
|
||||
>
|
||||
{{ text.aboutSection?.contact || "Kontakt" }}
|
||||
</Button>
|
||||
@@ -196,8 +199,8 @@
|
||||
<div class="relative overflow-hidden min-h-90 md:h-full md:self-stretch">
|
||||
<div class="absolute inset-0">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('home-page-images', 'about_us', 'webp')"
|
||||
:src="getOptimisedImageFallback('home-page-images', 'about_us')"
|
||||
:webpSrc="image.getOptimisedImagePath('home-page-images', 'about_us', 'webp')"
|
||||
:src="image.getOptimisedImageFallback('home-page-images', 'about_us')"
|
||||
:alt="text['aboutSection']?.imageAlt || 'Lapikud team'"
|
||||
objectFit="cover"
|
||||
class="h-full w-full max-w-none!"
|
||||
@@ -296,8 +299,8 @@
|
||||
<div class="relative overflow-hidden min-h-90 md:min-h-0 md:h-full md:self-stretch">
|
||||
<div class="absolute inset-0">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('home-page-images', 'temp', 'webp')"
|
||||
:src="getOptimisedImageFallback('home-page-images', 'temp')"
|
||||
:webpSrc="image.getOptimisedImagePath('home-page-images', 'temp', 'webp')"
|
||||
:src="image.getOptimisedImageFallback('home-page-images', 'temp')"
|
||||
:alt="text['whatWeDo']?.imageAlt || 'Lapikud parandamas riistvara'"
|
||||
objectFit="cover"
|
||||
class="h-full w-full max-w-none!"
|
||||
@@ -323,7 +326,7 @@
|
||||
<div class="flex flex-col items-end gap-6">
|
||||
<Button
|
||||
class="rounded-md border-3 border-orange-500 bg-transparent px-10 py-2 transition-colors hover:bg-orange-500/10"
|
||||
:onClick="() => navigate(currentLang === 'en' ? '/ourwork' : '/ettevottele')"
|
||||
:onClick="() => router.navigate(currentLang === 'en' ? '/ourwork' : '/ettevottele')"
|
||||
>
|
||||
{{ text.whatWeDo?.moreInfo || "Rohkem infot" }}
|
||||
</Button>
|
||||
@@ -332,7 +335,7 @@
|
||||
<ArrowLeft class="h-12 w-12 text-orange-500 md:h-14 md:w-14" :strokeWidth="2.4" />
|
||||
<Button
|
||||
class="border-orange-500 bg-orange-500 px-20 py-2 transition-colors hover:border-orange-300 hover:bg-orange-300"
|
||||
:onClick="() => navigate(currentLang === 'en' ? '/student' : '/tudengile')"
|
||||
:onClick="() => router.navigate(currentLang === 'en' ? '/student' : '/tudengile')"
|
||||
>
|
||||
{{ text.whatWeDo?.contact || "Kontakt" }}
|
||||
</Button>
|
||||
@@ -389,7 +392,7 @@
|
||||
<Center class="m-10">
|
||||
<Button
|
||||
class="rounded-md border-orange-500 bg-transparent px-20 py-3 transition-colors hover:bg-orange-500/10"
|
||||
:onClick="() => navigate('/partners')"
|
||||
:onClick="() => router.navigate('/partners')"
|
||||
>
|
||||
{{ text.partners?.moreInfo || "Rohkem infot partnerluste kohta" }}
|
||||
</Button>
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
Image,
|
||||
} from "../components/index.js";
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { currentLang, getLangText, usePageText } from "../lib/index.js";
|
||||
import { getOptimisedImagePath, getOptimisedImageFallback } from "../lib/imageHelpers.js";
|
||||
import { currentLang, getLangText, usePageText, useYaml, useImage } from "../lib/index.js";
|
||||
import { Mail } from "@lucide/vue";
|
||||
import { Phone } from "@lucide/vue";
|
||||
|
||||
// Initialize composables
|
||||
const yaml = useYaml();
|
||||
const image = useImage();
|
||||
|
||||
const currentManagement = ref([]);
|
||||
const pastManagement = ref([]);
|
||||
const loading = ref(true);
|
||||
@@ -46,8 +48,8 @@
|
||||
onMounted(async () => {
|
||||
try {
|
||||
[currentManagement.value, pastManagement.value] = await Promise.all([
|
||||
loadYaml('/_data/management.yml', []),
|
||||
loadYaml('/_data/past_management.yml', []),
|
||||
yaml.loadYaml('/_data/management.yml', []),
|
||||
yaml.loadYaml('/_data/past_management.yml', []),
|
||||
]);
|
||||
} catch (error) {
|
||||
console.error('Error loading management data:', error);
|
||||
@@ -88,9 +90,9 @@
|
||||
<div class="flex flex-col items-center gap-6 sm:flex-row sm:items-start">
|
||||
<div class="h-[150px] w-[150px] shrink-0">
|
||||
<picture>
|
||||
<source :srcset="getOptimisedImagePath('management-images', member.photo, 'webp')" type="image/webp" />
|
||||
<source :srcset="image.getOptimisedImagePath('management-images', member.photo, 'webp')" type="image/webp" />
|
||||
<img
|
||||
:src="getOptimisedImageFallback('management-images', member.photo)"
|
||||
:src="image.getOptimisedImageFallback('management-images', member.photo)"
|
||||
:alt="member.name"
|
||||
class="w-full h-full object-cover rounded-md"
|
||||
/>
|
||||
@@ -151,8 +153,8 @@
|
||||
<div class="h-24 w-24 overflow-hidden rounded-[10px] bg-linear-to-br outline-2 outline-transparent outline-offset-2 transition [@media(min-width:769px)]:h-28 [@media(min-width:769px)]:w-28">
|
||||
<template v-if="member.image">
|
||||
<Image
|
||||
:webpSrc="getOptimisedImagePath('past-management-images', member.image, 'webp')"
|
||||
:src="getOptimisedImageFallback('past-management-images', member.image)"
|
||||
:webpSrc="image.getOptimisedImagePath('past-management-images', member.image, 'webp')"
|
||||
:src="image.getOptimisedImageFallback('past-management-images', member.image)"
|
||||
:alt="member.name"
|
||||
objectFit="cover"
|
||||
class="block h-full w-full"
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
<script setup>
|
||||
import { Section, Container } from "../components/index.js";
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { currentLang, getLangText, usePageText } from "../lib/index.js";
|
||||
import { getOptimisedImagePath, getOptimisedImageFallback } from "../lib/imageHelpers.js";
|
||||
import { currentLang, getLangText, usePageText, useYaml, useImage } from "../lib/index.js";
|
||||
|
||||
import { Mail } from "@lucide/vue";
|
||||
import { Phone } from "@lucide/vue";
|
||||
import { MessageCircle } from "@lucide/vue";
|
||||
import { User } from "@lucide/vue";
|
||||
|
||||
// Initialize composables
|
||||
const yaml = useYaml();
|
||||
const image = useImage();
|
||||
|
||||
const mentors = ref([]);
|
||||
const activeMentors = computed(() => mentors.value.filter((mentor) => mentor.active !== false));
|
||||
const text = usePageText("Mentors");
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
mentors.value = await loadYaml('/_data/mentors.yml', []);
|
||||
mentors.value = await yaml.loadYaml('/_data/mentors.yml', []);
|
||||
});
|
||||
|
||||
function getContactIcon(contactType) {
|
||||
@@ -80,9 +81,9 @@
|
||||
<template v-if="mentor.photo">
|
||||
<div class="shrink-0">
|
||||
<picture>
|
||||
<source :srcset="getOptimisedImagePath('mentors-images', mentor.photo, 'webp')" type="image/webp" />
|
||||
<source :srcset="image.getOptimisedImagePath('mentors-images', mentor.photo, 'webp')" type="image/webp" />
|
||||
<img
|
||||
:src="getOptimisedImageFallback('mentors-images', mentor.photo)"
|
||||
:src="image.getOptimisedImageFallback('mentors-images', mentor.photo)"
|
||||
:alt="mentor.name"
|
||||
class="w-full md:w-48 h-48 object-cover"
|
||||
/>
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<script setup>
|
||||
import { Section, Grid, Card, Button } from "../components/index.js";
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { currentLang, getLangText, navigate, usePageText } from "../lib/index.js";
|
||||
import { getOptimisedImagePath, getOptimisedImageFallback } from "../lib/imageHelpers.js";
|
||||
import { currentLang, getLangText, usePageText, useRouter, useYaml, useImage } from "../lib/index.js";
|
||||
|
||||
import { ExternalLink } from "@lucide/vue";
|
||||
|
||||
// Initialize composables
|
||||
const router = useRouter();
|
||||
const yaml = useYaml();
|
||||
const image = useImage();
|
||||
|
||||
const projects = ref([]);
|
||||
const text = usePageText("OurWork");
|
||||
|
||||
onMounted(async () => {
|
||||
const parsed = await loadYaml('/_data/ourwork.yml', []);
|
||||
const parsed = await yaml.loadYaml('/_data/ourwork.yml', []);
|
||||
projects.value = parsed.filter((p) => p?.title);
|
||||
});
|
||||
|
||||
@@ -28,12 +31,12 @@
|
||||
|
||||
function projectImage(project) {
|
||||
return project?.photo
|
||||
? getOptimisedImagePath("ourwork-images", project.photo, "webp")
|
||||
? image.getOptimisedImagePath("ourwork-images", project.photo, "webp")
|
||||
: "";
|
||||
}
|
||||
|
||||
function handleImageError(event, photo) {
|
||||
event.currentTarget.src = getOptimisedImageFallback("ourwork-images", photo);
|
||||
event.currentTarget.src = image.getOptimisedImageFallback("ourwork-images", photo);
|
||||
}
|
||||
|
||||
function openCtaEmail() {
|
||||
@@ -41,7 +44,7 @@
|
||||
}
|
||||
|
||||
function openCtaContact() {
|
||||
navigate('/contact');
|
||||
router.navigate('/contact');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
Button,
|
||||
} from "../components/index.js";
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { usePageText } from "../lib/index.js";
|
||||
import { navigate } from "../lib/router/router.js";
|
||||
import { useRouter, usePageText, useYaml } from "../lib/index.js";
|
||||
|
||||
const router = useRouter();
|
||||
const yaml = useYaml();
|
||||
const members = ref({ junior: [], senior: [] });
|
||||
const text = usePageText("Student");
|
||||
const joinFormUrl = "https://pilves.lapikud.ee/apps/forms/s/WXed8sbG2s45GMKGAiXCemgE";
|
||||
|
||||
onMounted(async () => {
|
||||
members.value = await loadYaml('/_data/members.yml', { junior: [], senior: [] });
|
||||
members.value = await yaml.loadYaml('/_data/members.yml', { junior: [], senior: [] });
|
||||
});
|
||||
|
||||
const scrollToJoin = () => {
|
||||
@@ -144,7 +144,7 @@
|
||||
<p class="max-w-3xl text-base leading-8 text-white/70">{{ text.mentor?.description || '' }}</p>
|
||||
</div>
|
||||
<Button
|
||||
:onClick="() => navigate('/mentorid')"
|
||||
:onClick="() => router.navigate('/mentorid')"
|
||||
class="border-orange-500 bg-orange-500 px-8 py-3 text-sm font-semibold text-black hover:opacity-90"
|
||||
>
|
||||
{{ text.mentor?.cta || '' }}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<script setup>
|
||||
import { Section, Stack, Image } from "../components/index.js";
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { loadYaml } from '../lib/yaml.js';
|
||||
import { currentLang, currentLocale, getLangText, usePageText } from "../lib/index.js";
|
||||
import { getRootAssetPath } from "../lib/imageHelpers.js";
|
||||
import { currentLang, currentLocale, getLangText, usePageText, useYaml, useImage } from "../lib/index.js";
|
||||
|
||||
// Initialize composables
|
||||
const yaml = useYaml();
|
||||
const image = useImage();
|
||||
|
||||
const workshops = ref([]);
|
||||
const text = usePageText("Workshops");
|
||||
|
||||
onMounted(async () => {
|
||||
const parsed = await loadYaml('/_data/workshops.yml', []);
|
||||
const parsed = await yaml.loadYaml('/_data/workshops.yml', []);
|
||||
workshops.value = parsed.filter((w) => w?.title);
|
||||
});
|
||||
|
||||
@@ -88,7 +90,7 @@
|
||||
:class="`overflow-hidden ${getImageHeightClass(getGallery(workshop).length, i)}`"
|
||||
>
|
||||
<Image
|
||||
:src="getRootAssetPath('workshop-images', filename, 'jpg')"
|
||||
:src="image.getRootAssetPath('workshop-images', filename, 'jpg')"
|
||||
:alt="`${getField(workshop, 'title')} ${i + 1}`"
|
||||
objectFit="cover"
|
||||
class="h-full w-full"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import Svg, { VARIANTS } from '../components/Svg.vue';
|
||||
|
||||
export default {
|
||||
title: 'Components/Svg',
|
||||
component: Svg,
|
||||
argTypes: {
|
||||
type: { control: 'select', options: VARIANTS },
|
||||
},
|
||||
};
|
||||
|
||||
export const Preview = {
|
||||
args: { type: VARIANTS[0] },
|
||||
};
|
||||
Reference in New Issue
Block a user