diff --git a/.prettierrc.yaml b/.prettierrc.yaml index 93841fd..f82509d 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -7,5 +7,4 @@ endOfLine: 'auto' pluginSearchDirs: false plugins: - 'prettier-plugin-astro' - - 'prettier-plugin-svelte' - 'prettier-plugin-tailwindcss' diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a57e938..e3cf23f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,7 +4,6 @@ "mgmcdermott.vscode-language-babel", "EditorConfig.EditorConfig", "esbenp.prettier-vscode", - "svelte.svelte-vscode", "bradlc.vscode-tailwindcss", "redhat.vscode-yaml" ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 17850c4..6c36765 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,14 +5,9 @@ "emmet.includeLanguages": { "javascript": "javascriptreact", "astro": "javascriptreact" }, "files.eol": "\n", "prettier.documentSelectors": ["**/*.astro"], - "svelte.enable-ts-plugin": true, "tailwindCSS.classAttributes": ["class", "className", "class:list"], "tailwindCSS.experimental.classRegex": [["/\\* tw \\*/ ([^;]*);", "'([^']*)'"]], - "tailwindCSS.includeLanguages": { - "javascript": "javascriptreact", - "astro": "javascriptreact", - "svelte": "javascriptreact" - }, + "tailwindCSS.includeLanguages": { "javascript": "javascriptreact", "astro": "javascriptreact" }, "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true } diff --git a/astro.config.ts b/astro.config.ts index 6c1456e..951d42d 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -1,12 +1,11 @@ import image from '@astrojs/image'; -import svelte from '@astrojs/svelte'; import tailwind from '@astrojs/tailwind'; import { defineConfig } from 'astro/config'; import { visualizer } from 'rollup-plugin-visualizer'; // https://astro.build/config export default defineConfig({ - integrations: [tailwind(), image(), svelte()], + integrations: [tailwind(), image()], vite: { plugins: [visualizer()], }, diff --git a/package-lock.json b/package-lock.json index 73b7d53..b6c2cbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.0.1", "dependencies": { "@floating-ui/dom": "1.1.0", - "iconify-icon": "1.0.2" + "iconify-icon": "1.0.2", + "nanoid": "4.0.0" }, "devDependencies": { "@astrojs/image": "0.12.1", @@ -5206,15 +5207,14 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz", + "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==", "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^14 || ^16 || >=18" } }, "node_modules/napi-build-utils": { @@ -5834,6 +5834,18 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -12187,10 +12199,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz", + "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==" }, "napi-build-utils": { "version": "1.0.2", @@ -12552,6 +12563,14 @@ "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + } } }, "postcss-import": { diff --git a/package.json b/package.json index 53d9c54..23ecce4 100644 --- a/package.json +++ b/package.json @@ -20,15 +20,13 @@ }, "dependencies": { "@floating-ui/dom": "1.1.0", - "iconify-icon": "1.0.2" + "iconify-icon": "1.0.2", + "nanoid": "4.0.0" }, "devDependencies": { "@astrojs/image": "0.12.1", "@astrojs/react": "1.2.2", - "@astrojs/svelte": "1.0.2", "@astrojs/tailwind": "2.1.3", - "@types/react": "18.0.26", - "@types/react-dom": "18.0.10", "astro": "1.9.2", "concurrently": "7.6.0", "iconify-icon-names": "1.1.0", @@ -36,10 +34,8 @@ "postcss": "8.4.21", "prettier": "2.8.2", "prettier-plugin-astro": "0.7.2", - "prettier-plugin-svelte": "2.9.0", "prettier-plugin-tailwindcss": "0.2.1", "rollup-plugin-visualizer": "5.9.0", - "svelte": "3.55.1", "tailwindcss": "3.2.4", "typescript": "4.9.4" } diff --git a/src/components/icon-button.astro b/src/components/icon-button.astro index 7781344..4775de1 100644 --- a/src/components/icon-button.astro +++ b/src/components/icon-button.astro @@ -1,7 +1,7 @@ --- import type { IconName } from '@/types/icon'; -import Icon from './icon.svelte'; +import Icon from './icon.astro'; type IconButtonSize = 'small' | 'large'; @@ -28,5 +28,5 @@ const classes = /* tw */ { --- - + diff --git a/src/components/icon-with-tooltip.svelte b/src/components/icon-with-tooltip.svelte deleted file mode 100644 index 8536e9f..0000000 --- a/src/components/icon-with-tooltip.svelte +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/src/components/icon.astro b/src/components/icon.astro new file mode 100644 index 0000000..2886c5b --- /dev/null +++ b/src/components/icon.astro @@ -0,0 +1,22 @@ +--- +import type { IconName } from '@/types/icon'; + +export interface Props { + name: IconName; + size: number; + color?: string; + class?: string; +} + +const { name, size, color = 'currentColor', ...props } = Astro.props; +--- + + + diff --git a/src/components/icon.svelte b/src/components/icon.svelte deleted file mode 100644 index 5c6ae07..0000000 --- a/src/components/icon.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -{#if isServer} -
-{:else} - > -{/if} diff --git a/src/components/sidebar-item.astro b/src/components/sidebar-item.astro new file mode 100644 index 0000000..dcd8174 --- /dev/null +++ b/src/components/sidebar-item.astro @@ -0,0 +1,34 @@ +--- +import type { SectionKey } from '@/types/data'; +import type { IconName } from '@/types/icon'; +import Icon from './icon.astro'; + +export interface Props { + section: SectionKey; + icon: IconName; + title?: string; +} + +const { section, icon, title = '', ...props } = Astro.props; +--- + + + + + + diff --git a/src/components/sidebar-item.svelte b/src/components/sidebar-item.svelte deleted file mode 100644 index 80a556e..0000000 --- a/src/components/sidebar-item.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - diff --git a/src/components/sidebar.astro b/src/components/sidebar.astro index 1ec9ceb..3c9c547 100644 --- a/src/components/sidebar.astro +++ b/src/components/sidebar.astro @@ -2,7 +2,7 @@ import type { Data } from '@/data'; import isSectionKey from '@/utils/is-section-key'; -import SidebarItem from './sidebar-item.svelte'; +import SidebarItem from './sidebar-item.astro'; export interface Props { className?: string; @@ -23,10 +23,31 @@ const sections = Object.keys(data).flatMap((key) => { --- + + diff --git a/src/components/tag.astro b/src/components/tag.astro index 99a52c1..66bfbdd 100644 --- a/src/components/tag.astro +++ b/src/components/tag.astro @@ -1,7 +1,7 @@ --- import type { IconName } from '@/types/icon'; -import Icon from './icon.svelte'; +import Icon from './icon.astro'; export interface Props { name?: IconName; @@ -14,6 +14,6 @@ const { name, color } = Astro.props;
- {name && } + {name && }
diff --git a/src/components/theme-toggle.astro b/src/components/theme-toggle.astro new file mode 100644 index 0000000..4b098ca --- /dev/null +++ b/src/components/theme-toggle.astro @@ -0,0 +1,25 @@ +--- +import Icon from './icon.astro'; +--- + + + + diff --git a/src/components/theme-toggle.svelte b/src/components/theme-toggle.svelte deleted file mode 100644 index 4307ba9..0000000 --- a/src/components/theme-toggle.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/src/components/tooltip.svelte b/src/components/tooltip.svelte deleted file mode 100644 index 3d274d5..0000000 --- a/src/components/tooltip.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - -
- -
- diff --git a/src/pages/_playground/icon.astro b/src/pages/_playground/icon.astro index 759dbf0..c54f32b 100644 --- a/src/pages/_playground/icon.astro +++ b/src/pages/_playground/icon.astro @@ -1,9 +1,9 @@ --- -import Icon from '@/components/icon.svelte'; +import Icon from '@/components/icon.astro'; ---
- +
diff --git a/src/pages/_playground/sidebar-item.astro b/src/pages/_playground/sidebar-item.astro index f37e493..63149b6 100644 --- a/src/pages/_playground/sidebar-item.astro +++ b/src/pages/_playground/sidebar-item.astro @@ -1,7 +1,7 @@ --- -import SidebarItem from '@/components/sidebar-item.svelte'; +import SidebarItem from '@/components/sidebar-item.astro'; ---
- +
diff --git a/src/pages/index.astro b/src/pages/index.astro index d656658..a0b6462 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,6 +1,6 @@ --- import Sidebar from '@/components/sidebar.astro'; -import ThemeToggle from '@/components/theme-toggle.svelte'; +import ThemeToggle from '@/components/theme-toggle.astro'; import ExperienceSection from '@/sections/experience/experience-section.astro'; import FavoritesSection from '@/sections/favorites/favorites-section.astro'; import MainSection from '@/sections/main/main-section.astro'; @@ -44,7 +44,7 @@ const seoImage = seo.image ? seo.image : '/favicon.svg'; - +
{data.skills && } @@ -54,5 +54,6 @@ const seoImage = seo.image ? seo.image : '/favicon.svg'; {data.favorites && }
+ diff --git a/src/scripts/initialize-tooltips.ts b/src/scripts/initialize-tooltips.ts new file mode 100644 index 0000000..fc8c958 --- /dev/null +++ b/src/scripts/initialize-tooltips.ts @@ -0,0 +1,73 @@ +import { computePosition, flip, shift, offset, autoUpdate, Placement } from '@floating-ui/dom'; +import { nanoid } from 'nanoid'; + +interface UpdateTooltipOptions { + element: HTMLElement; + tooltip: HTMLElement; + placement: Placement; +} + +const updateTooltip = + ({ element, tooltip, placement }: UpdateTooltipOptions) => + () => { + computePosition(element, tooltip, { placement, middleware: [offset(8), flip(), shift({ padding: 8 })] }).then( + ({ x, y }) => { + Object.assign(tooltip.style, { + left: `${x}px`, + top: `${y}px`, + }); + } + ); + }; + +const tooltipClass = + /* tw */ 'absolute top-0 left-0 hidden max-w-sm animate-show rounded-lg bg-gray-700 px-3 py-1 text-white dark:bg-gray-100 dark:text-gray-800 sm:max-w-xs'; + +const createTooltip = (content: string) => { + const tooltip = document.createElement('div'); + + tooltip.innerText = content; + tooltip.setAttribute('id', `tooltip-${nanoid(8)}`); + tooltip.setAttribute('class', tooltipClass); + tooltip.setAttribute('role', 'tooltip'); + + return tooltip; +}; + +const addListeners = (element: HTMLElement, tooltip: HTMLElement, updateFn: () => void) => { + element.addEventListener('mouseenter', () => { + tooltip.style.display = 'block'; + updateFn(); + }); + + element.addEventListener('mouseleave', () => { + tooltip.style.display = ''; + }); +}; + +const creteTooltipsForElements = (elements: HTMLElement[]) => { + const tooltipsContainer = document.createElement('div'); + + const tooltips = elements.map((element) => { + const tooltip = createTooltip(element.dataset.tooltip ?? ''); + tooltipsContainer.appendChild(tooltip); + return { tooltip, element }; + }); + + document.body.appendChild(tooltipsContainer); + + return tooltips; +}; + +const elements = [...document.querySelectorAll('[data-tooltip]')] as HTMLElement[]; +const elementsWithTooltips = creteTooltipsForElements(elements); + +elementsWithTooltips.forEach(({ element, tooltip }) => { + const placement = (element.dataset.tooltipPlacement ?? 'top') as Placement; + const updateFn = updateTooltip({ element, tooltip, placement }); + + element.setAttribute('aria-describedby', tooltip.id); + + autoUpdate(element, tooltip, updateFn); + addListeners(element, tooltip, updateFn); +}); diff --git a/src/sections/skills/skill.astro b/src/sections/skills/skill.astro index c66fdd8..67b62b6 100644 --- a/src/sections/skills/skill.astro +++ b/src/sections/skills/skill.astro @@ -1,10 +1,8 @@ --- -import IconWithTooltip from '@/components/icon-with-tooltip.svelte'; import Typography from '@/components/typography.astro'; -import type { IconName } from '@/types/icon'; import type { LevelledSkill } from '@/types/skills-section'; -import Icon from '../../components/icon.svelte'; +import Icon from '../../components/icon.astro'; import SkillLevel from './skill-level.astro'; export interface Props extends LevelledSkill {} @@ -17,21 +15,16 @@ const IconWrapper = url ? 'a' : 'div';
- {icon && } + {icon && } {name} { description && ( - +
+ +
) }
diff --git a/tailwind.config.cjs b/tailwind.config.cjs index 2f5f563..ea5f0a2 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -21,6 +21,15 @@ module.exports = { fluid200: 'repeat(auto-fit, minmax(200px, 1fr))', fluid240: 'repeat(auto-fit, minmax(240px, 1fr))', }, + keyframes: { + show: { + from: { opacity: '0' }, + to: { opacity: '1' }, + }, + }, + animation: { + show: 'show 225ms ease-in-out', + }, }, }, plugins: [],