General improvements.

This commit is contained in:
2026-04-19 22:28:23 +01:00
parent 74953e3dcc
commit 49666d733d
2 changed files with 198 additions and 64 deletions

View File

@@ -1,23 +1,171 @@
#!/usr/bin/bash #!/usr/bin/bash
function cleanup() {
rm -rf repos tmp-portfolio
}
directory="$1"
if [ ! "$directory" ]; then
echo "Usage: $0 <directory>"
exit 1
fi
trap cleanup EXIT
GIT_URL='https://git.seanhealy.ie' GIT_URL='https://git.seanhealy.ie'
GIT_USER=sean GIT_USER=sean
GITHUB_USER=seanhly
GITLAB_USER=seanhly
CODEBERG_USER=seanhly
TOKEN="$(pass gitea-api-token)" TOKEN="$(pass gitea-api-token)"
EXCLUDE_LANGUAGES=(Makefile TeX) EXCLUDE_LANGUAGES=(Makefile TeX)
function my_curl() {
curl -s "$GIT_URL/api/v1/users/$GIT_USER/repos" \
-H 'Accept: application/json' \
-H "Authorization: $TOKEN" | jq -c '
sort_by(.updated_at) | reverse | .[] | select(.private == false) | select(.empty == false) | [
.name,
.description,
.languages_url,
.website,
.updated_at,
.avatar_url,
.licenses
]'
}
mkdir -p tmp-portfolio
portfolio_index=""
while read project; do
i=0
name=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
echo "Processing $name..."
description=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
languages_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
languages="$(curl -s "$languages_url" -H "Authorization: $TOKEN" |
jq -r 'to_entries[]|[.key,.value]|@tsv')"
total_bytes=$(echo "$languages" | awk '{sum += $2} END {print sum}')
languages_percentages=$(echo "$languages" |
awk -v total="$total_bytes" '{print $2 / total"\t"$1}' |
sort -n -r
)
git clone --depth 1 -b main --single-branch "$GIT_URL/$GIT_USER/$name" "repos/$name" 2>/dev/null >/dev/null
echo $'Percentage\tLanguages' > /tmp/languages.tsv
echo "$languages_percentages" >> /tmp/languages.tsv
(cat > /tmp/plot.R) <<EOF
#!/usr/bin/Rscript
library(ggplot2)
data <- read.csv("/tmp/languages.tsv", sep="\t")
data\$Languages <- factor(data\$Languages, levels=data\$Languages[order(data\$Percentage, decreasing=TRUE)])
if (nrow(data) == 1) {
data\$Percentage <- 0
}
plot <- ggplot(data, aes(x="", y=Percentage, fill=Languages)) +
geom_bar(stat="identity", width=1) +
coord_polar("y", start=0) +
theme_void() +
scale_fill_brewer(palette="Set3") +
theme(legend.text=element_text(size=16), legend.title=element_text(size=18))
ggsave("repos/$name/$name-languages.png", plot, width=5, height=5)
EOF
Rscript /tmp/plot.R
language_list="$(
(cut -d$'\t' -f2 <<< "$languages_percentages") |
grep -v -F -w -f <(printf "%s\n" "${EXCLUDE_LANGUAGES[@]}")
)"
website=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
updated_at=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
updated_at=$(date -d "$updated_at" +"%B %d, %Y")
avatar_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
licenses=$(jq -r '.['$i'] | join(", ")' <<< "$project"); i=$((i + 1))
mkdir -p repos
cp project-style.css "repos/$name/"
(cd "repos/$name" && (cat > "$name.qmd") <<EOF
---
execute:
enabled: false
format:
html:
embed-resources: true
css: project-style.css
---
[← Back to Portfolio](index.html)
Mirrors:
- [codeberg.org/$CODEBERG_USER/$name](https://codeberg.org/$CODEBERG_USER/$name)
- [github.com/$GITHUB_USER/$name](https://github.com/$GITHUB_USER/$name)
- [gitlab.com/$GITLAB_USER/$name](https://gitlab.com/$GITLAB_USER/$name)
![Languages used](./$name-languages.png)
\`\`\`{bash}
git clone https://codeberg.org/$CODEBERG_USER/$name
\`\`\`
$(cat README.md)
EOF
)
portfolio_index+="$(
cat <<EOF cat <<EOF
<a href="$name.html">
<section>
<h2>$name</h2>
<img src="$avatar_url" alt="Avatar" width="100" height="100" alt="$name (logo)">
<p>$description</p>
<ul class="languages">
EOF
)"
(cd "repos/$name" &&
quarto render "$name.qmd" -o "$name.html" >/dev/null 2>/dev/null &&
mv "$name.html" "../../tmp-portfolio/$name.html"
)
while read -r language; do
portfolio_index+="<li class='language'>$language</li>"
done <<< "$language_list"
portfolio_index+="$(
cat <<EOF
</ul>
<p>Last Updated: $updated_at</p>
<p>Licenses: $licenses</p>
</section>
</a>
EOF
)"
done < <(my_curl)
portfolio_index="$(
cat <<EOF
<h1>Projects</h1>
<div id="git-portfolio"> <div id="git-portfolio">
<style> <style>
#git-portfolio { #git-portfolio {
display: flex; display: inline-flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center;
} }
#git-portfolio section { #git-portfolio section {
background: wheat;
padding: 15px; padding: 15px;
max-width: 400px;
border: 2px black solid;
margin: 10px; margin: 10px;
border-radius: 20px; border-radius: 20px;
background: linear-gradient(30deg, rgba(100, 43, 200, 0.4), rgba(198, 66, 110, 0.4));
position: relative;
width: 100%;
box-sizing: border-box;
max-width: 420px;
}
#git-portfolio a {
color: black;
text-decoration: none;
display: inline-flex;
flex-direction: column;
flex-grow: 1;
min-width: 400px;
max-width: 450px;
box-sizing: content-box;
}
#git-portfolio section ul.languages {
float: right;
position: absolute;
right: 15px;
top: 0;
}
#git-portfolio h2 {
font-family: "Courier New", monospace;
} }
li.language { li.language {
display: inline-block; display: inline-block;
@@ -27,63 +175,19 @@ li.language {
margin: 5px; margin: 5px;
} }
</style> </style>
<h1>Projects</h1> $portfolio_index
</div>
EOF EOF
curl "$GIT_URL/api/v1/users/$GIT_USER/repos" \ )"
-H 'Accept: application/json' \ echo "$portfolio_index" > tmp-portfolio/index.html
-H "Authorization: $TOKEN" | jq -c ' if [ -d "$directory" ]; then
sort_by(.updated_at) | reverse | .[] | select(.private == false) | select(.empty == false) | [ if [ "$(du -sb "$directory" | cut -f1)" -gt $((1024 * 1024 * 400)) ]; then
.name, echo "Error: Directory '$directory' contains more than 400MB of data. Exiting to prevent data loss."
.description, exit 1
.languages_url, fi
.html_url, else
.clone_url, mkdir -p "$directory"
.website, fi
.updated_at, rsync -a "tmp-portfolio/" "$directory/"
.avatar_url, rm -rf repos
.licenses rm -r tmp-portfolio
]' |
while read project; do
i=0
name=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
description=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
languages_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
languages="$(curl -s "$languages_url" -H "Authorization: $TOKEN" |
jq -r 'to_entries[]|[.key,.value]|@tsv')"
total_bytes=$(echo "$languages" | awk '{sum += $2} END {print sum}')
languages_percentages=$(echo "$languages" |
awk -v total="$total_bytes" '{print $2, $1}' |
sort -n -r |
cut -d' ' -f2 | grep -v -F -w -f <(printf "%s\n" "${EXCLUDE_LANGUAGES[@]}")
)
html_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
clone_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
website=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
updated_at=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
updated_at=$(date -d "$updated_at" +"%B %d, %Y")
avatar_url=$(jq -r ".[$i]" <<< "$project"); i=$((i + 1))
licenses=$(jq -r '.['$i'] | join(", ")' <<< "$project"); i=$((i + 1))
cat <<EOF
<section>
<a href="$html_url">
<h2>$name</h2>
</a>
<a href="$html_url">
<img src="$avatar_url" alt="Avatar" width="100" height="100" alt="$name (logo)">
</a>
<p>$description</p>
<ul>
EOF
while read -r language; do
echo "<li class='language'>$language</li>"
done <<< "$languages_percentages"
cat <<EOF
</ul>
<pre>git clone $clone_url</pre>
<p>Last Updated: $updated_at</p>
<p>Licenses: $licenses</p>
</section>
EOF
done
echo '</div>'

30
project-style.css Normal file
View File

@@ -0,0 +1,30 @@
#quarto-document-content > pre:nth-child(-n+8) {
background: wheat;
border: 3px dashed pink;
padding: 5px;
}
#quarto-document-content {
text-align: center;
}
#quarto-document-content>* {
text-align: initial;
}
#quarto-document-content > ul:nth-child(-n+8) {
display: inline-block;
vertical-align: center;
list-style: none;
}
#quarto-document-content > div.quarto-figure:nth-child(-n+8) {
width: 300px;
display: inline-block;
margin: 0;
}
#quarto-document-content > div.quarto-figure:nth-child(-n+8) figcaption {
display: none;
}
#quarto-document-content > p:nth-child(-n+3) {
display: inline-block;
}
#quarto-document-content > p:first-child {
display: block !important;
}