Compare commits
41 Commits
0.8.11
...
414ef5c99d
Author | SHA1 | Date | |
---|---|---|---|
414ef5c99d
|
|||
0b7b87580a
|
|||
08f076e566
|
|||
26c27b9353 | |||
ce8b3a2e19 | |||
6d34c0d407 | |||
63607bbca3 | |||
745d2553a0
|
|||
8a19559cc7 | |||
42854db0fb
|
|||
7b72e3849b | |||
6a8dbb0c7c | |||
91fdf5a83f
|
|||
073f3a7916
|
|||
38202841ca | |||
0492922cce
|
|||
a17500835b | |||
2f8b97208c | |||
d6c30d5e5b
|
|||
a7ea9db3aa
|
|||
9134e78e8a | |||
2ca7d6705d | |||
5722e8c7a1 | |||
e39fd2acb8 | |||
0313fd54bc | |||
dbb0f6d7ff | |||
20669d9766 | |||
6b2e6353d1 | |||
6d112b52df | |||
ff17af604f | |||
32ea0989d7 | |||
e4ab7d134c | |||
5fad13655c | |||
8614d40a64 | |||
8c417b93b3 | |||
1d9519831b | |||
fa57f2e93f | |||
9e01002d4e | |||
cb52c169a3 | |||
3017668cd2 | |||
1972b3bc19 |
35
.gitea/workflows/process-issues.yaml
Normal file
35
.gitea/workflows/process-issues.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
name: process-issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '@daily'
|
||||
|
||||
jobs:
|
||||
process-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Python Script
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alexlebens/workflow-scripts
|
||||
ref: main
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
path: scripts
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install requests
|
||||
|
||||
- name: Run Script
|
||||
env:
|
||||
INSTANCE_URL: ${{ vars.INSTANCE_URL }}
|
||||
REPOSITORY: ${{ gitea.repository }}
|
||||
TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
STALE_DAYS: 3
|
||||
STALE_TAG: 'stale'
|
||||
EXCLUDE_TAG: 'renovate'
|
||||
run: python ./scripts/scripts/process-issues.py
|
35
.gitea/workflows/process-pull-requests.yaml
Normal file
35
.gitea/workflows/process-pull-requests.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
name: process-pull-requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '@daily'
|
||||
|
||||
jobs:
|
||||
process-pull-requests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Python Script
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: alexlebens/workflow-scripts
|
||||
ref: main
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
path: scripts
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install requests
|
||||
|
||||
- name: Run Script
|
||||
env:
|
||||
INSTANCE_URL: ${{ vars.INSTANCE_URL }}
|
||||
REPOSITORY: ${{ gitea.repository }}
|
||||
TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
STALE_DAYS: 3
|
||||
STALE_TAG: 'stale'
|
||||
REQUIRED_TAG: 'automerge'
|
||||
run: python ./scripts/scripts/process-pull-requests.py
|
@@ -13,7 +13,7 @@ on:
|
||||
jobs:
|
||||
renovate:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/renovatebot/renovate:40
|
||||
container: ghcr.io/renovatebot/renovate:41
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
@@ -1,75 +0,0 @@
|
||||
name: tag-old-issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '@daily'
|
||||
|
||||
jobs:
|
||||
tag-old-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Tag Old Issues
|
||||
env:
|
||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||
INSTANCE_URL: ${{ vars.INSTANCE_URL }}
|
||||
REPO_OWNER: ${{ github.repository_owner }}
|
||||
REPO_NAME: ${{ github.repository_name }}
|
||||
TAG_NAME: 'stale'
|
||||
DAYS_OLD: 3
|
||||
EXCLUDE_TAG_NAME: ''
|
||||
REQUIRED_TAG: 'automerge'
|
||||
run: |
|
||||
# Install necessary tools
|
||||
apt-get update && apt-get install -y jq curl
|
||||
|
||||
# --- Conditionally build the API URL ---
|
||||
API_URL="${GITEA_INSTANCE_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues?state=open"
|
||||
if [[ -n "${REQUIRED_TAG}" ]]; then
|
||||
echo "Filtering for issues with the required tag: ${REQUIRED_TAG}"
|
||||
# URL-encode the tag to handle special characters
|
||||
ENCODED_TAG=$(jq -s -R -r @uri <<< "${REQUIRED_TAG}")
|
||||
API_URL="${API_URL}&labels=${ENCODED_TAG}"
|
||||
else
|
||||
echo "No required tag specified. Checking all open issues."
|
||||
fi
|
||||
|
||||
# Fetch issues using the constructed URL
|
||||
ISSUES=$(curl -s -X GET \
|
||||
-H "Authorization: token ${BOT_TOKEN}" \
|
||||
-H "Accept: application/json" \
|
||||
"${API_URL}")
|
||||
|
||||
# Calculate the date ${DAYS_OLD} days ago in ISO 8601 format
|
||||
OLDER_THAN_DATE=$(date -d "-${DAYS_OLD} days" -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# Filter issues older than the specified date and without the exclusion tag
|
||||
echo "$ISSUES" | jq -c '.[] | select(.created_at < "'"$OLDER_THAN_DATE"'")' | while read -r issue; do
|
||||
ISSUE_NUMBER=$(echo "$issue" | jq -r '.number')
|
||||
LABELS=$(echo "$issue" | jq -r '.labels[].name')
|
||||
|
||||
# Check if the issue has the exclusion tag
|
||||
if ! echo "$LABELS" | grep -q -w "${EXCLUDE_TAG_NAME}"; then
|
||||
echo "Tagging issue #${ISSUE_NUMBER} as ${TAG_NAME}"
|
||||
|
||||
# Get existing labels for the issue
|
||||
EXISTING_LABELS=$(curl -s -X GET \
|
||||
-H "Authorization: token ${BOT_TOKEN}" \
|
||||
-H "Accept: application/json" \
|
||||
"${INSTANCE_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${ISSUE_NUMBER}/labels" | jq -r '.[].name')
|
||||
|
||||
# Add the new tag to the list of existing labels
|
||||
NEW_LABELS=$(echo -e "${EXISTING_LABELS}\n${TAG_NAME}" | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))')
|
||||
|
||||
# Update the issue with the new set of labels
|
||||
curl -s -X PUT \
|
||||
-H "Authorization: token ${BOT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"labels\": $(echo "$NEW_LABELS" | jq -r 'map(select(. != ""))')}" \
|
||||
"${INSTANCE_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${ISSUE_NUMBER}/labels"
|
||||
else
|
||||
echo "Skipping issue #${ISSUE_NUMBER} because it has the '${EXCLUDE_TAG_NAME}' tag."
|
||||
fi
|
||||
done
|
@@ -1,7 +1,7 @@
|
||||
ARG REGISTRY=docker.io
|
||||
FROM ${REGISTRY}/node:22.16.0-alpine3.22 AS base
|
||||
|
||||
LABEL version="0.8.11"
|
||||
LABEL version="0.8.12"
|
||||
LABEL description="Astro based personal website"
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
|
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "site-profile",
|
||||
"type": "module",
|
||||
"version": "0.8.11",
|
||||
"version": "0.8.12",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
@@ -17,10 +17,10 @@
|
||||
"@astrojs/node": "^9.2.2",
|
||||
"@astrojs/react": "^4.3.0",
|
||||
"@astrojs/rss": "^4.0.12",
|
||||
"@directus/sdk": "^19.1.0",
|
||||
"@directus/sdk": "^20.0.0",
|
||||
"@tailwindcss/postcss": "^4.1.8",
|
||||
"@tailwindcss/vite": "^4.1.8",
|
||||
"astro": "^5.9.2",
|
||||
"astro": "^5.10.0",
|
||||
"framer-motion": "^12.16.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
@@ -31,13 +31,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@typescript-eslint/parser": "8.34.0",
|
||||
"eslint": "9.28.0",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"eslint": "9.29.0",
|
||||
"eslint-config-prettier": "10.1.5",
|
||||
"eslint-plugin-astro": "1.3.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.12",
|
||||
"typescript-eslint": "8.34.0"
|
||||
"typescript-eslint": "8.34.1"
|
||||
}
|
||||
}
|
||||
|
1608
pnpm-lock.yaml
generated
1608
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,40 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended", "mergeConfidence:all-badges", ":rebaseStalePrs"],
|
||||
"timezone": "US/Central",
|
||||
"schedule": ["* */1 * * *"],
|
||||
"labels": [],
|
||||
"prHourlyLimit": 0,
|
||||
"prConcurrentLimit": 0,
|
||||
"packageRules": []
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended",
|
||||
"mergeConfidence:all-badges",
|
||||
":rebaseStalePrs"
|
||||
],
|
||||
"timezone": "US/Central",
|
||||
"labels": [],
|
||||
"prHourlyLimit": 0,
|
||||
"prConcurrentLimit": 0,
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Label dependency",
|
||||
"matchDatasources": [
|
||||
"npm"
|
||||
],
|
||||
"addLabels": [
|
||||
"automerge"
|
||||
],
|
||||
"automerge": false,
|
||||
"minimumReleaseAge": "1 days"
|
||||
},
|
||||
{
|
||||
"description": "Automerge dependency patch",
|
||||
"matchDatasources": [
|
||||
"npm"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
"patch"
|
||||
],
|
||||
"addLabels": [
|
||||
"dependency",
|
||||
"automerge"
|
||||
],
|
||||
"automerge": true,
|
||||
"minimumReleaseAge": "1 days"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -137,114 +137,113 @@ const socialLinks = [
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom section -->
|
||||
<div class="theme-transition-all mt-12 border-t border-zinc-200 pt-8 dark:border-zinc-800">
|
||||
<div class="flex flex-col items-center justify-between gap-4 md:flex-row">
|
||||
<p class="theme-transition-color text-sm text-zinc-600 dark:text-zinc-400">
|
||||
© {currentYear} All rights reserved.
|
||||
</p>
|
||||
<!-- Bottom section -->
|
||||
<div class="theme-transition-all mt-12 border-t border-zinc-200 pt-8 dark:border-zinc-800">
|
||||
<div class="flex flex-col items-center justify-between gap-4 md:flex-row">
|
||||
<p class="theme-transition-color text-sm text-zinc-600 dark:text-zinc-400">
|
||||
© {currentYear} All rights reserved.
|
||||
</p>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="theme-transition-color text-xs text-zinc-500 dark:text-zinc-400"
|
||||
>Built with</span
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="theme-transition-color text-xs text-zinc-500 dark:text-zinc-400"
|
||||
>Built with</span
|
||||
>
|
||||
<a
|
||||
href="https://astro.build"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="group inline-flex items-center text-xs text-zinc-600 transition-colors hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
<svg
|
||||
class="mr-1 h-4 w-4 text-[#FF5D01] group-hover:animate-pulse"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
>
|
||||
<a
|
||||
href="https://astro.build"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="group inline-flex items-center text-xs text-zinc-600 transition-colors hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
<svg
|
||||
class="mr-1 h-4 w-4 text-[#FF5D01] group-hover:animate-pulse"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.833 22.958c.622-1.185 1.832-1.918 3.18-1.918 2.292 0 4.145 1.86 4.145 4.153 0 1.34-.626 2.54-1.601 3.303 1.223-1.299 1.97-3.048 1.97-4.971 0-3.994-3.243-7.233-7.242-7.233-2.818 0-5.26 1.6-6.469 3.933.78-2.912 3.428-5.06 6.577-5.06 3.75 0 6.79 3.035 6.79 6.78 0 2.606-1.468 4.868-3.616 6.002a4.163 4.163 0 0 0 2.285-3.724c0-2.293-1.853-4.153-4.145-4.153-1.348 0-2.558.733-3.18 1.918l1.306-3.03Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M22.155 12.056c-.622 1.185-1.832 1.918-3.18 1.918-2.292 0-4.145-1.86-4.145-4.153 0-1.34.626-2.54 1.601-3.303-1.223 1.299-1.97 3.048-1.97 4.971 0 3.994 3.243 7.233 7.242 7.233 2.818 0 5.26-1.6 6.469-3.933-.78 2.912-3.428 5.06-6.577 5.06-3.75 0-6.79-3.035-6.79-6.78 0-2.606 1.468-4.868 3.616-6.002a4.163 4.163 0 0 0-2.285 3.724c0 2.293 1.853 4.153 4.145 4.153 1.348 0 2.558-.733 3.18-1.918l-1.306 3.03Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<span class="relative">
|
||||
Astro
|
||||
<span
|
||||
class="absolute bottom-0 left-0 h-0.5 w-0 bg-[#FF5D01] transition-all duration-300 group-hover:w-full"
|
||||
></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.833 22.958c.622-1.185 1.832-1.918 3.18-1.918 2.292 0 4.145 1.86 4.145 4.153 0 1.34-.626 2.54-1.601 3.303 1.223-1.299 1.97-3.048 1.97-4.971 0-3.994-3.243-7.233-7.242-7.233-2.818 0-5.26 1.6-6.469 3.933.78-2.912 3.428-5.06 6.577-5.06 3.75 0 6.79 3.035 6.79 6.78 0 2.606-1.468 4.868-3.616 6.002a4.163 4.163 0 0 0 2.285-3.724c0-2.293-1.853-4.153-4.145-4.153-1.348 0-2.558.733-3.18 1.918l1.306-3.03Z"
|
||||
fill="currentColor"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M22.155 12.056c-.622 1.185-1.832 1.918-3.18 1.918-2.292 0-4.145-1.86-4.145-4.153 0-1.34.626-2.54 1.601-3.303-1.223 1.299-1.97 3.048-1.97 4.971 0 3.994 3.243 7.233 7.242 7.233 2.818 0 5.26-1.6 6.469-3.933-.78 2.912-3.428 5.06-6.577 5.06-3.75 0-6.79-3.035-6.79-6.78 0-2.606 1.468-4.868 3.616-6.002a4.163 4.163 0 0 0-2.285 3.724c0 2.293 1.853 4.153 4.145 4.153 1.348 0 2.558-.733 3.18-1.918l-1.306 3.03Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<span class="relative">
|
||||
Astro
|
||||
<span
|
||||
class="absolute bottom-0 left-0 h-0.5 w-0 bg-[#FF5D01] transition-all duration-300 group-hover:w-full"
|
||||
></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.theme-transition-all {
|
||||
transition-property: background-color, border-color, color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.theme-transition-color {
|
||||
transition-property: color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.theme-transition-bg {
|
||||
transition-property: background-color;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float-slow {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0) translateX(0);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-10px) translateX(10px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-5px) translateX(-5px);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(10px) translateX(5px);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
.animate-float-slow {
|
||||
animation: float-slow 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animation-delay-1000 {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.animation-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
</style>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.theme-transition-all {
|
||||
transition-property: background-color, border-color, color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.theme-transition-color {
|
||||
transition-property: color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.theme-transition-bg {
|
||||
transition-property: background-color;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float-slow {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0) translateX(0);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-10px) translateX(10px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-5px) translateX(-5px);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(10px) translateX(5px);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
.animate-float-slow {
|
||||
animation: float-slow 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animation-delay-1000 {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.animation-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
</style>
|
||||
|
@@ -120,15 +120,12 @@ const skills = await directus.request(
|
||||
<div class="slider-track animate-slide flex">
|
||||
{
|
||||
skills.map((skill, index) => (
|
||||
<div
|
||||
class="skill-card theme-transition-element mx-2 min-w-[220px] transform rounded-xl border border-zinc-200 bg-white transition-all duration-300 hover:-translate-y-2 hover:scale-105 hover:border-zinc-300 hover:shadow-xl sm:mx-4 sm:min-w-[280px] dark:border-zinc-700 dark:bg-zinc-800/50 dark:hover:border-zinc-600"
|
||||
>
|
||||
<div class="skill-card theme-transition-element mx-2 min-w-[220px] transform rounded-xl border border-zinc-200 bg-white transition-all duration-300 hover:-translate-y-2 hover:scale-105 hover:border-zinc-300 hover:shadow-xl sm:mx-4 sm:min-w-[280px] dark:border-zinc-700 dark:bg-zinc-800/50 dark:hover:border-zinc-600">
|
||||
<div class="p-4 sm:p-6">
|
||||
<div class="mb-4 flex items-center justify-between sm:mb-6">
|
||||
<div class="flex items-center gap-2 sm:gap-4">
|
||||
<div class="theme-transition-bg theme-transition-color flex h-8 w-8 transform items-center justify-center rounded-lg bg-zinc-100 text-zinc-800 transition-transform group-hover:rotate-12 sm:h-12 sm:w-12 dark:bg-zinc-800 dark:text-zinc-200">
|
||||
<skill.icon
|
||||
/>
|
||||
<skill.icon />
|
||||
</div>
|
||||
<h3 class="theme-transition-color text-base font-semibold text-zinc-900 sm:text-xl dark:text-zinc-100">
|
||||
{skill.title}
|
||||
|
Reference in New Issue
Block a user