Adding contact information, updating about page
This commit is contained in:
parent
80b1d7634a
commit
0041a48bae
11 changed files with 526 additions and 43 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
color: white;
|
color: white;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
|
.content-screen {
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
|
||||||
> .about-content {
|
> .about-content {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
@ -14,6 +18,125 @@
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.about-contact-section {
|
||||||
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-label {
|
||||||
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
color: #0f0;
|
||||||
|
text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px dotted rgba(0, 255, 0, 0.5);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-color: rgba(0, 255, 0, 0.8);
|
||||||
|
text-shadow: 0 0 10px rgba(0, 255, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pgp-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-left: 0;
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pgp-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: rgba(0, 255, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 255, 0, 0.3);
|
||||||
|
color: #0f0;
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
.button-icon {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 255, 0, 0.2);
|
||||||
|
border-color: rgba(0, 255, 0, 0.6);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 0, 0.4);
|
||||||
|
text-shadow: 0 0 10px rgba(0, 255, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-feedback {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
color: #0f0;
|
||||||
|
background: rgba(0, 255, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 255, 0, 0.3);
|
||||||
|
text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
color: #f00;
|
||||||
|
background: rgba(255, 0, 0, 0.1);
|
||||||
|
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||||
|
text-shadow: 0 0 5px rgba(255, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.about-header {
|
.about-header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -80px;
|
left: -80px;
|
||||||
|
|
@ -37,6 +160,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .about-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
> .info-badges {
|
> .info-badges {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
@ -55,6 +182,23 @@
|
||||||
transform: rotate(5deg);
|
transform: rotate(5deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.about-music {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
> .music {
|
||||||
|
scale: 1.6;
|
||||||
|
|
||||||
|
.ipod-group {
|
||||||
|
top: 50%;
|
||||||
|
left: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vu-meter {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -558,6 +558,142 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contact section styling
|
||||||
|
.blog-contact-section {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 20px;
|
||||||
|
background: rgba(0, 255, 0, 0.05);
|
||||||
|
border: 1px solid rgba(0, 255, 0, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
@include media-down(lg) {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
color: greenyellow;
|
||||||
|
text-shadow: 0 0 10px rgba(173, 255, 47, 0.5);
|
||||||
|
|
||||||
|
@include media-down(lg) {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email,
|
||||||
|
.contact-pgp {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
|
||||||
|
@include media-down(lg) {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-label {
|
||||||
|
color: greenyellow;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10px;
|
||||||
|
text-shadow: 0 0 5px rgba(173, 255, 47, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email a {
|
||||||
|
color: #0f0;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px dotted rgba(0, 255, 0, 0.5);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-color: rgba(0, 255, 0, 0.8);
|
||||||
|
text-shadow: 0 0 10px rgba(0, 255, 0, 0.8);
|
||||||
|
background: rgba(0, 255, 0, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pgp-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pgp-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 15px;
|
||||||
|
background: rgba(0, 255, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 255, 0, 0.3);
|
||||||
|
color: #0f0;
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
@include media-down(lg) {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-icon {
|
||||||
|
font-size: 1.1em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 255, 0, 0.2);
|
||||||
|
border-color: rgba(0, 255, 0, 0.6);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 0, 0.4);
|
||||||
|
text-shadow: 0 0 10px rgba(0, 255, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-feedback {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
color: #0f0;
|
||||||
|
background: rgba(0, 255, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 255, 0, 0.3);
|
||||||
|
text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
color: #f00;
|
||||||
|
background: rgba(255, 0, 0, 0.1);
|
||||||
|
border: 1px solid rgba(255, 0, 0, 0.3);
|
||||||
|
text-shadow: 0 0 5px rgba(255, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Blog image styling
|
// Blog image styling
|
||||||
.blog-img-container {
|
.blog-img-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
.whiteboard {
|
.whiteboard {
|
||||||
background: linear-gradient(135deg, #f5f5f0 0%, #e8e8dd 100%);
|
background: linear-gradient(135deg, #f5f5f0 0%, #e8e8dd 100%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 3rem 2rem;
|
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 10px 40px rgba(0, 0, 0, 0.1),
|
0 10px 40px rgba(0, 0, 0, 0.1),
|
||||||
inset 0 0 100px rgba(0, 0, 0, 0.02);
|
inset 0 0 100px rgba(0, 0, 0, 0.02);
|
||||||
|
|
@ -24,15 +24,27 @@
|
||||||
|
|
||||||
// Subtle texture overlay
|
// Subtle texture overlay
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-image:
|
background-image:
|
||||||
repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0, 0, 0, 0.01) 2px, rgba(0, 0, 0, 0.01) 4px),
|
repeating-linear-gradient(
|
||||||
repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(0, 0, 0, 0.01) 2px, rgba(0, 0, 0, 0.01) 4px);
|
0deg,
|
||||||
|
transparent,
|
||||||
|
transparent 2px,
|
||||||
|
rgba(0, 0, 0, 0.01) 2px,
|
||||||
|
rgba(0, 0, 0, 0.01) 4px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
transparent 2px,
|
||||||
|
rgba(0, 0, 0, 0.01) 2px,
|
||||||
|
rgba(0, 0, 0, 0.01) 4px
|
||||||
|
);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +89,9 @@
|
||||||
.resource-pin {
|
.resource-pin {
|
||||||
position: relative;
|
position: relative;
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
transition:
|
||||||
|
transform 0.3s ease,
|
||||||
|
box-shadow 0.3s ease;
|
||||||
|
|
||||||
// Random slight rotations for pins
|
// Random slight rotations for pins
|
||||||
&:nth-child(3n + 1) {
|
&:nth-child(3n + 1) {
|
||||||
|
|
@ -120,7 +134,7 @@
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
@ -172,7 +186,13 @@
|
||||||
|
|
||||||
// Lavalamp icon
|
// Lavalamp icon
|
||||||
&.lavalamp {
|
&.lavalamp {
|
||||||
background: linear-gradient(180deg, transparent 0%, transparent 20%, #9333ea 20%, #7c3aed 100%);
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
transparent 0%,
|
||||||
|
transparent 20%,
|
||||||
|
#9333ea 20%,
|
||||||
|
#7c3aed 100%
|
||||||
|
);
|
||||||
border-radius: 10px 10px 40px 40px;
|
border-radius: 10px 10px 40px 40px;
|
||||||
border: 3px solid #6b21a8;
|
border: 3px solid #6b21a8;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -180,7 +200,7 @@
|
||||||
|
|
||||||
// Lamp base
|
// Lamp base
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -8px;
|
bottom: -8px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
@ -193,7 +213,7 @@
|
||||||
|
|
||||||
// Lava blobs
|
// Lava blobs
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 30%;
|
top: 30%;
|
||||||
left: 30%;
|
left: 30%;
|
||||||
|
|
@ -219,7 +239,7 @@
|
||||||
// Equalizer bars
|
// Equalizer bars
|
||||||
&::before,
|
&::before,
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 15px;
|
bottom: 15px;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
|
|
@ -280,7 +300,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes float-blob {
|
@keyframes float-blob {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
transform: translateY(0) scale(1);
|
transform: translateY(0) scale(1);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
|
|
@ -289,7 +310,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes float-blob-2 {
|
@keyframes float-blob-2 {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
transform: translateY(0) scale(1);
|
transform: translateY(0) scale(1);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
|
|
@ -298,7 +320,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes equalizer-1 {
|
@keyframes equalizer-1 {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
|
|
@ -307,7 +330,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes equalizer-2 {
|
@keyframes equalizer-2 {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
height: 25px;
|
height: 25px;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
|
|
@ -316,7 +340,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes equalizer-3 {
|
@keyframes equalizer-3 {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
aspect-ratio: 300 / 245;
|
aspect-ratio: 300 / 245;
|
||||||
background: linear-gradient(145deg, #b8b8b0, #989888);
|
background: linear-gradient(145deg, #b8b8b0, #989888);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 8px 20px rgba(0, 0, 0, 0.7),
|
0 8px 20px #000000b3,
|
||||||
inset 0 2px 4px rgba(255, 255, 255, 0.3),
|
inset 0 2px 4px rgba(255, 255, 255, 0.3),
|
||||||
inset 0 -2px 4px rgba(0, 0, 0, 0.3);
|
inset 0 -2px 4px rgba(0, 0, 0, 0.3);
|
||||||
padding: 6px 8px 18px 8px;
|
padding: 6px 8px 18px 8px;
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
&::before {
|
&::before {
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
bottom: 18px;
|
bottom: 18px;
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
&::after {
|
&::after {
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
left: 8px;
|
left: 8px;
|
||||||
bottom: 18px;
|
bottom: 18px;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ footer[role="contentinfo"] {
|
||||||
border-left: 1px solid #0f0;
|
border-left: 1px solid #0f0;
|
||||||
border-top-left-radius: 5px;
|
border-top-left-radius: 5px;
|
||||||
|
|
||||||
|
> .crt {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
@include media-down(lg) {
|
@include media-down(lg) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
|
|
||||||
|
&.crt {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vu-bar {
|
.vu-bar {
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ body {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.crt {
|
.crt {
|
||||||
|
position: absolute;
|
||||||
animation: textShadow 1.6s infinite;
|
animation: textShadow 1.6s infinite;
|
||||||
background: black;
|
background: black;
|
||||||
color: greenyellow;
|
color: greenyellow;
|
||||||
|
|
@ -813,7 +814,6 @@ body {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Desk-mounted CRT - on desk left side */
|
/* Desk-mounted CRT - on desk left side */
|
||||||
.desk-monitor {
|
.desk-monitor {
|
||||||
bottom: 10%;
|
bottom: 10%;
|
||||||
|
|
@ -1036,8 +1036,6 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes pulse-slow {
|
@keyframes pulse-slow {
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ Zooming in on 2019 onwards makes it clearer:
|
||||||
|
|
||||||
StackOverflow's real decline starts in 2021, well before anyone gave a shit about AI coding. From January 2021 (140,009 questions) to December 2022 (96,767 questions), it lost 31% of its traffic while "AI coding" searches sat at baseline.
|
StackOverflow's real decline starts in 2021, well before anyone gave a shit about AI coding. From January 2021 (140,009 questions) to December 2022 (96,767 questions), it lost 31% of its traffic while "AI coding" searches sat at baseline.
|
||||||
|
|
||||||
The AI coding surge doesn't really kick off until early 2023, then explodes through 2025, peaking in August. But by then StackOverflow was already down to 5,885 questions per month.
|
The AI coding surge doesn't really kick off until early 2023, then explodes through 2025, peaking in August. By then StackOverflow was already down to 5,885 questions per month.
|
||||||
|
|
||||||
## Did the rise of GitHub contribute?
|
## Did the rise of GitHub contribute?
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ Could it be a contributing factor? Absolutely. If you had a choice between askin
|
||||||
|
|
||||||
To actually test this properly you'd need to pull years of StackOverflow comments and run sentiment analysis to see if moderation got worse over time. That's way more effort than I'm putting into this blog post. Maybe one for another day.
|
To actually test this properly you'd need to pull years of StackOverflow comments and run sentiment analysis to see if moderation got worse over time. That's way more effort than I'm putting into this blog post. Maybe one for another day.
|
||||||
|
|
||||||
## So what's actually going on?
|
## So what's was the actual cause?
|
||||||
|
|
||||||
The data suggests AI accelerated something that was already happening. A few things probably contributed:
|
The data suggests AI accelerated something that was already happening. A few things probably contributed:
|
||||||
|
|
||||||
|
|
@ -102,13 +102,13 @@ The data suggests AI accelerated something that was already happening. A few thi
|
||||||
|
|
||||||
**The collapse (2025-2026)**: By mid-2025, AI coding tools are just... everywhere. GitHub Copilot, ChatGPT, Claude, all of them baked into every IDE and workflow. The August 2025 peak in "AI coding" searches lines up with StackOverflow hitting 5,885 questions. That's a 96% decline from five years earlier.
|
**The collapse (2025-2026)**: By mid-2025, AI coding tools are just... everywhere. GitHub Copilot, ChatGPT, Claude, all of them baked into every IDE and workflow. The August 2025 peak in "AI coding" searches lines up with StackOverflow hitting 5,885 questions. That's a 96% decline from five years earlier.
|
||||||
|
|
||||||
## The bottom line
|
## Summary
|
||||||
|
|
||||||
AI didn't kill StackOverflow, but it's definitely finishing the job. The platform was already bleeding out when ChatGPT showed up: content saturation, better tooling, the ecosystem maturing. But AI coding tools changed the game completely. Why search through old forum posts when you can just ask?
|
AI didn't kill StackOverflow, but it's definitely finishing the job. The platform was already bleeding out when ChatGPT showed up: content saturation, better tooling, the ecosystem maturing. But AI coding tools changed the game completely. Why search through old forum posts when you can just ask?
|
||||||
|
|
||||||
The inverse relationship is stark: as AI coding interest hits its peak in 2025, StackOverflow craters. By December 2025 we're at 3,862 questions. That's roughly the same as September 2008, just a few months after the platform launched.
|
The inverse relationship is stark: as AI coding interest hits its peak in 2025, StackOverflow craters. By December 2025 we're at 3,862 questions. That's roughly the same as September 2008, just a few months after the platform launched.
|
||||||
|
|
||||||
Twelve years to build it. Five years to tear it down. And yeah, the last three were almost certainly AI finishing what was already started.
|
Twelve years to build it. Five years to watch it end. The last three were almost certainly AI finishing what was already started.
|
||||||
|
|
||||||
### Footnote
|
### Footnote
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ This is the hardest and longest I have thought about anything in a long time. I
|
||||||
|
|
||||||
The CSV data for this post can be found on my [GitHub](https://github.com/unbolt/ritual.sh/tree/main/content/blog/the-downfall-of-stackoverflow).
|
The CSV data for this post can be found on my [GitHub](https://github.com/unbolt/ritual.sh/tree/main/content/blog/the-downfall-of-stackoverflow).
|
||||||
|
|
||||||
I hope you found this interesting. Rock on.
|
I hope you found this interesting. Please get in touch if you have any further insights.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -135,5 +135,3 @@ I hope you found this interesting. Rock on.
|
||||||
[^5]: [Comment](https://news.ycombinator.com/item?id=46482624)
|
[^5]: [Comment](https://news.ycombinator.com/item?id=46482624)
|
||||||
|
|
||||||
[^6]: In 2013, Tim Schreiber wrote about ["StackOverlords"](https://timschreiber.com/2013/10/30/beware-the-stackoverlords/) who "ruthlessly wield" their privileges against newcomers. By 2018, StackOverflow officially acknowledged the problem in their blog post ["Stack Overflow Isn't Very Welcoming. It's Time for That to Change."](https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/)
|
[^6]: In 2013, Tim Schreiber wrote about ["StackOverlords"](https://timschreiber.com/2013/10/30/beware-the-stackoverlords/) who "ruthlessly wield" their privileges against newcomers. By 2018, StackOverflow officially acknowledged the problem in their blog post ["Stack Overflow Isn't Very Welcoming. It's Time for That to Change."](https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
{{ define "header" }}{{ partial "page-header.html" . }}{{ end }} {{ define
|
{{ define "main" }}
|
||||||
"main" }}
|
|
||||||
<article class="about-page">
|
<article class="about-page">
|
||||||
<div class="about-content">
|
<div class="about-content">
|
||||||
<div class="content-screen">
|
<div class="content-screen">
|
||||||
<div class="about-header">{{ partial "elements/lavalamp.html" . }}</div>
|
<div class="about-header">{{ partial "elements/lavalamp.html" . }}</div>
|
||||||
<div class="screen-display crt no-scroll">
|
<div class="screen-display crt no-scroll">
|
||||||
> about -v <br />
|
> about -s <br />
|
||||||
<span>Name</span> / <span class="info">Dan (He/Him)</span><br />
|
<span>Name</span> / <span class="info">Dan (He/Him)</span><br />
|
||||||
<span>Age</span> / <span class="info">40-something</span><br />
|
<span>Age</span> / <span class="info">40-something</span><br />
|
||||||
<span>Location</span> / <span class="info">UK 🇬🇧</span><br /><br />
|
<span>Location</span> / <span class="info">UK 🇬🇧</span><br /><br />
|
||||||
<span>Interests</span> /
|
<span>Interests</span> /
|
||||||
<span class="info">
|
<span class="info"> Programming. Music. Movies. Tech. Photography.</span
|
||||||
Programming. Music. Movies. Tech. Photography. </span
|
|
||||||
><br />
|
><br />
|
||||||
<span class="cursor-blink">_</span>
|
<span class="cursor-blink">_</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -23,6 +21,16 @@
|
||||||
partial "elements/lcd-screen.html" (dict "text" .) }} {{ end }}
|
partial "elements/lcd-screen.html" (dict "text" .) }} {{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="wide-item">
|
||||||
|
<div class="content-screen">
|
||||||
|
<div class="screen-display crt">
|
||||||
|
> cat manifesto
|
||||||
|
|
||||||
|
<span class="cursor-blink">_</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="wide-item manifesto-container">
|
<div class="wide-item manifesto-container">
|
||||||
<div class="content-screen">
|
<div class="content-screen">
|
||||||
<div class="screen-display crt">
|
<div class="screen-display crt">
|
||||||
|
|
@ -105,10 +113,96 @@
|
||||||
><br />
|
><br />
|
||||||
Camera / <span class="info">Fuji X-T5</span><br />
|
Camera / <span class="info">Fuji X-T5</span><br />
|
||||||
Audio / <span class="info">Hiby R4 EVA, Fiio FT-1</span> <br /><br />
|
Audio / <span class="info">Hiby R4 EVA, Fiio FT-1</span> <br /><br />
|
||||||
More info coming soon...
|
Check out my <a href="/now">/now</a> page to see more hardware and
|
||||||
<br /><span class="cursor-blink">_</span>
|
software information. <br /><span class="cursor-blink">_</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="about-music hidden-xxl-down">
|
||||||
|
<div class="music">
|
||||||
|
{{ partial "elements/ipod.html" . }}
|
||||||
|
|
||||||
|
<div class="">{{ partial "elements/vu-meter.html" . }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-screen wide-item">
|
||||||
|
<div class="screen-display crt">
|
||||||
|
> cat contact_info<br />
|
||||||
|
<div class="about-contact-section">
|
||||||
|
<p>
|
||||||
|
If you have any comments, questions, corrections, or just fancy
|
||||||
|
saying "hello" please feel free to get in touch.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I am still debating with myself if I want to put more effort into a
|
||||||
|
mastodon/bluesky type thing, so for now email is the best way to
|
||||||
|
talk to me. PGP is available if that's your kind of thing.
|
||||||
|
</p>
|
||||||
|
<div class="contact-info">
|
||||||
|
<div class="contact-item">
|
||||||
|
<span class="contact-label">Email</span> /
|
||||||
|
<a href="mailto:dan@ritual.sh" class="info">dan@ritual.sh</a>
|
||||||
|
</div>
|
||||||
|
<div class="contact-item">
|
||||||
|
<span class="contact-label">PGP Public Key</span> /
|
||||||
|
<div class="pgp-actions">
|
||||||
|
<a href="/publickey.asc" download class="pgp-button">
|
||||||
|
<span class="button-icon">↓</span> Download
|
||||||
|
</a>
|
||||||
|
<button id="copy-pgp-key-about" class="pgp-button">
|
||||||
|
<span class="button-icon">⎘</span> Copy to Clipboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="copy-feedback-about" class="copy-feedback"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre>
|
||||||
|
| .-.
|
||||||
|
| / \ .-.
|
||||||
|
| / \ / \ .-. .-. _ _
|
||||||
|
+--/-------\-----/-----\-----/---\---/---\---/-\-/-\/\/---
|
||||||
|
| / \ / \ / '-' '-'
|
||||||
|
|/ '-' '-'
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<span class="cursor-blink">_</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const copyButton = document.getElementById("copy-pgp-key-about");
|
||||||
|
const feedback = document.getElementById("copy-feedback-about");
|
||||||
|
|
||||||
|
if (copyButton) {
|
||||||
|
copyButton.addEventListener("click", async function () {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/publickey.asc");
|
||||||
|
const pgpKey = await response.text();
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(pgpKey);
|
||||||
|
|
||||||
|
feedback.textContent = "PGP key copied to clipboard!";
|
||||||
|
feedback.classList.add("show", "success");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
feedback.classList.remove("show");
|
||||||
|
}, 3000);
|
||||||
|
} catch (err) {
|
||||||
|
feedback.textContent = "Failed to copy key";
|
||||||
|
feedback.classList.add("show", "error");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
feedback.classList.remove("show");
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,37 @@
|
||||||
<div class="blog-summary">{{ .Content }}</div>
|
<div class="blog-summary">{{ .Content }}</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<section class="blog-contact-section">
|
||||||
|
<h2 class="contact-title">Contact</h2>
|
||||||
|
<div class="contact-content">
|
||||||
|
<p>
|
||||||
|
If you found this interesting, have any comments, questions,
|
||||||
|
corrections, or just fancy saying "hello" please feel free to get
|
||||||
|
in touch.
|
||||||
|
</p>
|
||||||
|
<div class="contact-email">
|
||||||
|
<span class="contact-label">Email:</span>
|
||||||
|
<a href="mailto:dan@ritual.sh">dan@ritual.sh</a>
|
||||||
|
</div>
|
||||||
|
<div class="contact-pgp">
|
||||||
|
<span class="contact-label">PGP Public Key:</span>
|
||||||
|
<div class="pgp-actions">
|
||||||
|
<a
|
||||||
|
href="/publickey.asc"
|
||||||
|
download
|
||||||
|
class="pgp-button download-key"
|
||||||
|
>
|
||||||
|
<span class="button-icon">↓</span> Download
|
||||||
|
</a>
|
||||||
|
<button id="copy-pgp-key" class="pgp-button copy-key">
|
||||||
|
<span class="button-icon">⎘</span> Copy to Clipboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="copy-feedback" class="copy-feedback"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<nav class="blog-post-navigation">
|
<nav class="blog-post-navigation">
|
||||||
<div class="post-nav-links">
|
<div class="post-nav-links">
|
||||||
{{ with .PrevInSection }}
|
{{ with .PrevInSection }}
|
||||||
|
|
@ -49,4 +80,36 @@
|
||||||
|
|
||||||
<script src="/js/footnote-scroll.js"></script>
|
<script src="/js/footnote-scroll.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const copyButton = document.getElementById("copy-pgp-key");
|
||||||
|
const feedback = document.getElementById("copy-feedback");
|
||||||
|
|
||||||
|
if (copyButton) {
|
||||||
|
copyButton.addEventListener("click", async function () {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/publickey.asc");
|
||||||
|
const pgpKey = await response.text();
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(pgpKey);
|
||||||
|
|
||||||
|
feedback.textContent = "PGP key copied to clipboard!";
|
||||||
|
feedback.classList.add("show", "success");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
feedback.classList.remove("show");
|
||||||
|
}, 3000);
|
||||||
|
} catch (err) {
|
||||||
|
feedback.textContent = "Failed to copy key";
|
||||||
|
feedback.classList.add("show", "error");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
feedback.classList.remove("show");
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
17
static/publickey.asc
Normal file
17
static/publickey.asc
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
xjMEaVzgdxYJKwYBBAHaRw8BAQdADvLcBAhz3La0tovwPlJ2Z5uKHufb9MS9
|
||||||
|
6CGKBIgssOfNHWRhbkByaXR1YWwuc2ggPGRhbkByaXR1YWwuc2g+wsARBBMW
|
||||||
|
CgCDBYJpXOB3AwsJBwkQhk08tBmPAUJFFAAAAAAAHAAgc2FsdEBub3RhdGlv
|
||||||
|
bnMub3BlbnBncGpzLm9yZ2lm/k+MdxoNH3+THDnkaLgtXLiV1AuTGyJ0ZlAe
|
||||||
|
4ngSAxUKCAQWAAIBAhkBApsDAh4BFiEEFv8cu2aJ5iyvXhJ0hk08tBmPAUIA
|
||||||
|
ABB0AP0ZvUva/yf6ZR8T7Zwp8+RtqyYfiDlJbpqt3hEGALw0EgD6AxO3O4tm
|
||||||
|
f2IguB2kuUfrH223xGEzIOHYz1Ciwt6haAPOOARpXOB3EgorBgEEAZdVAQUB
|
||||||
|
AQdAjllaNe/Z1No5rRxVz6SBsSN4o2xDHPWb0PnGxZAsT3EDAQgHwr4EGBYK
|
||||||
|
AHAFgmlc4HcJEIZNPLQZjwFCRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9w
|
||||||
|
ZW5wZ3Bqcy5vcmfxjGz++fxlZxuZLgSTOTjWRrtwvPuLEFJSN1VxonqqcQKb
|
||||||
|
DBYhBBb/HLtmieYsr14SdIZNPLQZjwFCAABdiAD8Cz5dxfHSm1mBwQ0jKjZd
|
||||||
|
sktUeaa3Ksw2NsMFU3sbnoIBAMBoAaQVq+q5RoLn1ZOT/DIeDU+1o5HVAL0k
|
||||||
|
sb/b4NYN
|
||||||
|
=EIiw
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
Loading…
Add table
Add a link
Reference in a new issue