diff --git a/app/assets/stylesheets/theme.css b/app/assets/stylesheets/theme.css index b1a311c..4a04c68 100644 --- a/app/assets/stylesheets/theme.css +++ b/app/assets/stylesheets/theme.css @@ -11,19 +11,33 @@ --border-color: #374151; /* gray-700 */ --accent-color: #eab308; /* yellow-500 */ --accent-hover: #facc15; /* yellow-400 */ + --pill-bg: #374151; /* gray-700 */ + --pill-text: #eab308; /* yellow-500 */ + --pill-bg-active: #eab308; /* yellow-500 */ + --pill-text-active: #000000; + --glass-accent-1: rgba(100, 150, 255, 0.1); + --glass-accent-2: rgba(130, 80, 220, 0.05); } /* CSS Variables - Light Theme */ :root.light-theme { - --bg-primary: #ffffff; - --bg-secondary: #f3f4f6; /* gray-100 */ - --bg-card: #f9fafb; /* gray-50 */ - --text-primary: #111827; /* gray-900 */ - --text-secondary: #4b5563; /* gray-600 */ - --text-muted: #6b7280; /* gray-500 */ - --border-color: #e5e7eb; /* gray-200 */ - --accent-color: #eab308; /* yellow-500 */ - --accent-hover: #d97706; /* yellow-600 */ + --bg-primary: #eae4cf; /* toned down from f4f1e6 */ + --bg-secondary: #e3dbc1; /* less light, more warm fade */ + --bg-card: #f2ecda; /* card paper tone */ + --text-primary: #3a372f; /* inkier, softened */ + --text-secondary: #5e5746; + --text-muted: #807b70; + --border-color: #d0c8b4; /* subtle sepia-gray */ + --accent-color: #c28b00; + --accent-hover: #a77400; + --pill-bg: #e5ddc7; + --pill-text: #a77400; + --pill-bg-active: #c28b00; + --pill-text-active: #f2ecda; + --glass-accent-1: rgba(160, 140, 100, 0.05); + --glass-accent-2: rgba(140, 110, 80, 0.03); + --sidebar-bg: #e8e1ca; + --sidebar-text: #3a372f; } /* Set dark theme as default */ @@ -37,6 +51,12 @@ --border-color: #374151; --accent-color: #eab308; --accent-hover: #facc15; + --pill-bg: #374151; + --pill-text: #eab308; + --pill-bg-active: #eab308; + --pill-text-active: #000000; + --glass-accent-1: rgba(100, 150, 255, 0.1); + --glass-accent-2: rgba(130, 80, 220, 0.05); } /* Card Styles */ @@ -75,6 +95,71 @@ text-decoration: underline; } +/* Pill Styles */ +.theme-pill { + background-color: var(--pill-bg); + color: var(--pill-text); + padding: 0.25rem 0.75rem; + border-radius: 9999px; /* rounded-full */ + font-size: 0.875rem; + transition: all 0.2s ease; +} + +.theme-pill.active { + background-color: var(--pill-bg-active); + color: var(--pill-text-active); +} + +.theme-pill:hover { + opacity: 0.9; +} + +/* Glass Effect Utilities */ +.glass-effect { + position: relative; + overflow: hidden; +} + +.glass-effect::before { + content: ''; + position: absolute; + top: -10px; + right: -10px; + width: 80px; + height: 80px; + border-radius: 50%; + background: var(--glass-accent-1); + filter: blur(15px); + animation: pulse-slow 12s infinite, float 15s ease-in-out infinite; + z-index: 0; +} + +.glass-effect::after { + content: ''; + position: absolute; + bottom: -20px; + left: -20px; + width: 100px; + height: 100px; + border-radius: 50%; + background: var(--glass-accent-2); + filter: blur(20px); + animation: pulse-slow 15s infinite reverse; + z-index: 0; +} + +@keyframes pulse-slow { + 0%, 100% { opacity: 0.5; } + 50% { opacity: 0.8; } +} + +@keyframes float { + 0%, 100% { transform: translateY(0) translateX(0); } + 25% { transform: translateY(-10px) translateX(5px); } + 50% { transform: translateY(0) translateX(10px); } + 75% { transform: translateY(10px) translateX(5px); } +} + /* Legacy classes for backward compatibility */ .dark-card { background-color: var(--bg-card); diff --git a/app/javascript/application.js b/app/javascript/application.js index a82d212..25473dd 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -12,7 +12,9 @@ import MarkdownRenderer from './components/MarkdownRenderer' import GameCard from './components/GameCard' import GamesGrid from './components/GamesGrid' import AboutMe from './components/AboutMe' -import ThemeLayout from './components/DarkModeLayout' // Renamed but kept same file +import ContactInfo from './components/ContactInfo' +import FunProjects from './components/FunProjects' +import ThemeLayout from './components/ThemeLayout' // Use the new ThemeLayout component import ThemeProvider from './components/ThemeProvider' import ThemeToggle from './components/ThemeToggle' @@ -25,6 +27,8 @@ const COMPONENTS = { 'GamesGrid': GamesGrid, 'WorkExperience': WorkExperience, 'AboutMe': AboutMe, + 'ContactInfo': ContactInfo, + 'FunProjects': FunProjects, 'ThemeLayout': ThemeLayout, // New name 'DarkModeLayout': ThemeLayout, // For backwards compatibility 'ThemeProvider': ThemeProvider, @@ -43,8 +47,32 @@ window.sidebarEvents = { // No need for margin adjustments with grid layout +// Create a global ThemeProvider instance that exists outside +// of the component lifecycle to ensure theme is applied immediately +const initializeThemeProvider = () => { + // Check if we already have a ThemeProvider + if (!window.themeProviderRoot) { + // Create a div to hold the ThemeProvider + const themeProviderContainer = document.createElement('div') + themeProviderContainer.id = 'theme-provider-root' + document.body.appendChild(themeProviderContainer) + + // Create the root and render the ThemeProvider + const themeProviderRoot = createRoot(themeProviderContainer) + themeProviderRoot.render() + window.themeProviderRoot = themeProviderRoot + console.log('Global ThemeProvider initialized') + } +} + +// Initialize ThemeProvider immediately +initializeThemeProvider() + document.addEventListener("turbo:load", () => { - const reactComponents = document.querySelectorAll("[data-react-component]") + // Ensure ThemeProvider is initialized on each page load + initializeThemeProvider() + + const reactComponents = document.querySelectorAll("[data-react-component]") reactComponents.forEach(component => { const componentName = component.dataset.reactComponent @@ -71,6 +99,12 @@ document.addEventListener("turbo:load", () => { } } + // Skip rendering another ThemeProvider since we have a global one + if (componentName === 'ThemeProvider') { + console.log('Skipping additional ThemeProvider render because we have a global one') + return + } + // Check if we already have a root for this container if (!roots.has(component)) { const root = createRoot(component) diff --git a/app/javascript/components/AboutMe.jsx b/app/javascript/components/AboutMe.jsx index e78eae8..7c163a4 100644 --- a/app/javascript/components/AboutMe.jsx +++ b/app/javascript/components/AboutMe.jsx @@ -3,18 +3,14 @@ import { ThemeContext } from './ThemeProvider'; import ResponsiveImage from './ResponsiveImage'; const AboutMe = () => { - // Get theme context if available - let theme = 'dark'; // Default to dark if context not available + // Use ThemeContext via useContext hook try { - const themeContext = useContext(ThemeContext); - if (themeContext) { - theme = themeContext.theme; - } + // This component uses CSS variables so we don't need to track theme state + // Just ensure ThemeContext is properly initialized + useContext(ThemeContext); } catch (e) { console.log('ThemeContext not available, using default theme'); } - - const isDark = theme === 'dark'; // Placeholder data - replace with your actual data const skills = [ { name: 'Full Stack Web Development' }, @@ -56,28 +52,18 @@ const AboutMe = () => {
{/* Domain name header */}
austn.net
{/* Hero Section */} -
+
{/* Decorative elements to enhance glass effect */} -
-
{ {skills.map((skill) => ( {skill.name} @@ -107,17 +92,7 @@ const AboutMe = () => {
{/* About Me Section */} -
- {/* Subtle decorative accent for glass panel */} -
-
-
+

About Me

I'm a passionate full-stack developer with expertise in React and Ruby on Rails. @@ -127,9 +102,7 @@ const AboutMe = () => {

{/* Featured Post */} -
+
{/* Decorative elements for featured post */}
{
{/* Favorite Items */} -
- {/* Subtle decorative accent for glass panel */} -
-
-
+

My Favorite Things

{favoriteItems.map((category) => ( @@ -200,11 +163,11 @@ const AboutMe = () => { href={item.url} target="_blank" rel="noopener noreferrer" - className="group flex items-start p-4 rounded-md transition-all glass-panel" + className="group flex items-start p-4 rounded-md transition-all theme-card glass-effect" >
{/* Replace with actual image */} {item.name.substring(0, 2)} diff --git a/app/javascript/components/ContactInfo.jsx b/app/javascript/components/ContactInfo.jsx new file mode 100644 index 0000000..4c534c9 --- /dev/null +++ b/app/javascript/components/ContactInfo.jsx @@ -0,0 +1,112 @@ +import React, { useContext } from 'react'; +import { ThemeContext } from './ThemeProvider'; + +const ContactInfo = () => { + // Use ThemeContext via useContext hook + try { + // This component uses CSS variables so we don't need to track theme state + // Just ensure ThemeContext is properly initialized + useContext(ThemeContext); + } catch (e) { + console.log('ThemeContext not available, using default theme'); + } + + // Contact information + const contactDetails = { + email: 'austindanielfrench at gmail.com', + github: 'github.com/frogr', + }; + + // Social media links with icons + const socialLinks = [ + { name: 'GitHub', url: `https://${contactDetails.github}`, icon: 'code' }, + ]; + + return ( +
+

Contact Me

+

+ Get in touch for collaborations, questions, or just to say hello! +

+ +
+ {/* Contact Information Card */} + + + {/* Quick Contact Form Card */} +
+ +
+

Let's Connect

+

Feel free to reach out on any of my social platforms:

+ +
+ {socialLinks.map((link) => ( + + {link.icon} + {link.name} + + ))} +
+ +
+

Business inquiries only:

+

business@example.com

+
+
+
+
+ + {/* Availability Section */} +
+ +
+

Current Availability

+

Currently employed, but feel free to reach out and say hello!

+
+
+
+ ); +}; + +export default ContactInfo; \ No newline at end of file diff --git a/app/javascript/components/DebugComponent.jsx b/app/javascript/components/DebugComponent.jsx new file mode 100644 index 0000000..002e754 --- /dev/null +++ b/app/javascript/components/DebugComponent.jsx @@ -0,0 +1,16 @@ +import React from 'react'; + +const DebugComponent = ({ name = 'Unknown', props = {} }) => { + console.log(`DebugComponent rendering: ${name}`, props); + + return ( +
+

Debug Component: {name}

+
+        {JSON.stringify(props, null, 2)}
+      
+
+ ); +}; + +export default DebugComponent; \ No newline at end of file diff --git a/app/javascript/components/FunProjects.jsx b/app/javascript/components/FunProjects.jsx new file mode 100644 index 0000000..c6bbedc --- /dev/null +++ b/app/javascript/components/FunProjects.jsx @@ -0,0 +1,47 @@ +import React, { useContext } from 'react'; +import ResponsiveImage from './ResponsiveImage'; +import { ThemeContext } from './ThemeProvider'; + +const FunProjects = () => { + // Use ThemeContext via useContext hook + try { + // This component uses CSS variables so we don't need to track theme state + // Just ensure ThemeContext is properly initialized + useContext(ThemeContext); + } catch (e) { + console.log('ThemeContext not available, using default theme'); + } + + return ( +
+

Fun Stuff

+

+ A collection of personal projects, hobbies, and interests outside of my professional work. +

+ + {/* What I'm Learning Section */} +
+ +
+

What I'm Learning Right Now

+
+
+

WebGL & Three.js

+

Exploring 3D graphics in the browser for interactive visualizations.

+
+
+

Advanced Rails

+

Diving deeper into Rails internals and performance optimization.

+
+
+

Machine Learning

+

Getting started with ML fundamentals for potential future projects.

+
+
+
+
+
+ ); +}; + +export default FunProjects; \ No newline at end of file diff --git a/app/javascript/components/Sidebar.jsx b/app/javascript/components/Sidebar.jsx index f52220c..d09f676 100644 --- a/app/javascript/components/Sidebar.jsx +++ b/app/javascript/components/Sidebar.jsx @@ -73,15 +73,15 @@ const Sidebar = () => {

Austn