Skip to content

Personal Website built in React with Tailwind CSS and Modern Minimalism Design

Notifications You must be signed in to change notification settings

Mvgnu/magnusohle

Repository files navigation

Magnus Ohle - Web & Ad Agency Website

A modern, responsive website for Magnus Ohle, a web and advertising agency serving Tübingen and Reutlingen, Germany. Built with Next.js, TypeScript, and Tailwind CSS.

Features

  • Modern Design: Clean, professional design with smooth animations and transitions
  • Responsive Layout: Optimized for all devices from mobile to desktop
  • Performance Optimized: Fast loading times and optimized assets
  • Accessibility: WCAG 2.1 AA compliant design
  • Dark Mode Support: Automatic and manual theme switching
  • SEO Friendly: Optimized for search engines with:
    • Dynamic sitemap generation
    • Customized robots.txt
    • Structured data (JSON-LD)
    • Comprehensive meta tags
    • See SEO.md for details
  • Multi-language: German content with potential for expansion

Pages

  • Home: Agency introduction and service overview
  • About: Company history, team, and values
  • Services: Detailed service offerings
  • Portfolio: Showcase of client projects
  • Blog: Articles and insights
  • Contact: Contact form and location information
  • Legal Pages: Privacy Policy, Terms & Conditions, Accessibility Statement

Tech Stack

  • Framework: Next.js 14
  • Language: TypeScript
  • Styling: Tailwind CSS
  • Animations: Framer Motion
  • State Management: React Hooks
  • Form Handling: React Hook Form (planned)
  • Deployment: Vercel (recommended)

Recent Updates

July 2023

  • Fixed funnel chart component to properly handle color picker and centered bar visualization settings
  • Improved chart rendering and responsiveness
  • Added detailed debugging logs for better troubleshooting
  • Created comprehensive documentation for statistical chart components

Getting Started

Prerequisites

  • Node.js 18.17.0 or later
  • npm or yarn

Installation

  1. Clone the repository:

    git clone https://github.com/Mvgnu/magnusohle.git
    cd byrlo-site
  2. Install dependencies:

    npm install
    # or
    yarn install
  3. Run the development server:

    npm run dev
    # or
    yarn dev
  4. Open http://localhost:3002 in your browser to see the result.

Deployment

To deploy the site to production, we recommend using Vercel:

  1. Push your code to a GitHub repository
  2. Import the project in Vercel
  3. Configure your deployment settings
  4. Deploy

Alternatively, you can use the included deploy script to run the site:

./deploy.sh

This will build and start the application on http://localhost:3002.

Project Structure

byrlo-site/
├── public/             # Static assets
├── src/
│   ├── app/            # Next.js app router pages
│   ├── components/     # Reusable UI components
│   ├── sections/       # Page sections
│   ├── lib/            # Utility functions and helpers
│   ├── styles/         # Global styles
│   └── types/          # TypeScript type definitions
├── next.config.ts      # Next.js configuration
├── tailwind.config.ts  # Tailwind CSS configuration
├── tsconfig.json       # TypeScript configuration
└── package.json        # Project dependencies and scripts

Customization

Styling

The project uses Tailwind CSS for styling. You can customize the design by modifying the tailwind.config.ts file.

Content

Most of the content is defined directly in the page components. For dynamic content, you can integrate a headless CMS like Contentful, Sanity, or Strapi.

Images

Replace the placeholder images with your own images in the appropriate components. Make sure to update the next.config.ts file if you're using external image sources.

Browser Support

The website is optimized for modern browsers:

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contact

For any questions or support, please contact:

Magnus Ohle - Interactive Blog Components

A collection of interactive and visually appealing components for enhancing blog posts with data visualizations, interactive elements, and rich media.

Recent Updates (July 2023)

We've added several new components and made significant improvements to the codebase:

  • New Components:

    • SliderElement: A responsive image slider/carousel with autoplay and touch support
    • CalloutElement: Highlighted message boxes for important information
    • CodePreview: Code snippets with syntax highlighting and live previews
    • Box Plot Element: Added a new component for visualizing statistical distributions with quartiles, medians, and outliers
  • Key Improvements:

    • Enhanced type safety across all components
    • Better error handling with graceful fallbacks
    • Consistent styling and dark mode support
    • Improved accessibility with proper ARIA attributes
    • Better mobile responsiveness
  • Bug Fixes:

    • Fixed type errors in the BlogElementsRenderer
    • Improved data handling to prevent "undefined is not an object" errors
    • Fixed component rendering with empty or incomplete data
    • Fixed Chart.js registration issue in BoxPlotElement where "bar" was not registered as an element
    • Added proper TypeScript type handling for custom Chart.js properties
    • Improved error handling throughout visualization components
  • Performance Improvements:

    • Enhanced data loading patterns across all components
    • Created reusable hooks for common data operations
    • Implemented better error boundaries for component stability

Table of Contents

  1. Introduction
  2. Components
  3. Usage
  4. Installation
  5. Development

Introduction

The Magnus Ohle blog components are designed to enhance blog posts with interactive data visualizations. Each component is built to be:

  • Responsive: Works across all device sizes
  • Interactive: Supports user interaction like hovering, clicking, and filtering
  • Accessible: Follows accessibility guidelines for all users
  • Customizable: Provides multiple options for styling and behavior
  • Dark Mode Compatible: Looks great in both light and dark themes

Components

NodeDiagramElement

An interactive force-directed graph component with customizable nodes and links, supports different layouts and interactive features.

Features:

  • Force-directed, hierarchical, and circular layouts
  • Node highlighting and selection
  • Interactive zooming and panning
  • Pros/cons display for selected nodes
  • Draggable nodes
  • Customizable colors and sizes

Props:

interface NodeDiagramProps {
  title?: string;
  description?: string;
  nodes: Node[];  // Nodes with id, label, group, size, color, pros, cons
  links: Link[];  // Links between nodes with optional strength and labels
  width?: number;
  height?: number;
  layout?: 'force' | 'hierarchical' | 'circular';
  showLabels?: boolean;
  interactive?: boolean;
  onNodeClick?: (node: Node) => void;
}

Usage Example:

import { NodeDiagramElement } from '@/components/blog-elements';

const MyComponent = () => {
  const nodes = [
    { id: '1', label: 'Node 1', group: 'A', pros: ['Fast', 'Reliable'], cons: ['Expensive'] },
    { id: '2', label: 'Node 2', group: 'B', pros: ['Cheap'], cons: ['Slow'] },
    // ...more nodes
  ];
  
  const links = [
    { source: '1', target: '2', strength: 0.5 },
    // ...more links
  ];

  return (
    <NodeDiagramElement
      title="System Architecture"
      description="Diagram showing components and their relationships"
      nodes={nodes}
      links={links}
      layout="force"
      interactive={true}
      showLabels={true}
    />
  );
};

FunnelChartElement

A component for visualizing conversion funnels with abandonment reasons and optional comparison data.

Features:

  • Visualization of conversion stages
  • Detailed abandonment reasons with recommendations
  • Comparison between different scenarios (e.g., mobile vs desktop)
  • Interactive tooltips with additional information
  • Tabular data view

Props:

interface FunnelChartElementProps {
  title?: string;
  description?: string;
  data: {
    stages: {
      label: string;
      value: number;
      abandonmentReasons?: {
        reason: string;
        count: number;
        percentage: number;
        details?: string;
        recommendations?: string[];
      }[];
      tooltip?: {
        title: string;
        content: string;
        action?: {
          label: string;
          onClick: () => void;
        };
      };
    }[];
    comparison?: {
      label: string;
      stages: {
        label: string;
        value: number;
      }[];
    };
  };
  onLoad?: () => void;
}

Usage Example:

import { FunnelChartElement } from '@/components/blog-elements';

const MyComponent = () => {
  const funnelData = {
    stages: [
      {
        label: 'Website Visits',
        value: 10000,
        tooltip: { title: 'Visits', content: 'Total number of website visits' }
      },
      {
        label: 'Product Views',
        value: 6000,
        abandonmentReasons: [
          { reason: 'Navigation issues', count: 2000, percentage: 50, 
            recommendations: ['Improve site navigation', 'Add search functionality'] },
          { reason: 'Content quality', count: 2000, percentage: 50 }
        ]
      },
      // ...more stages
    ],
    comparison: {
      label: 'Last Month',
      stages: [
        { label: 'Website Visits', value: 8000 },
        { label: 'Product Views', value: 4800 },
        // ...more stages
      ]
    }
  };

  return <FunnelChartElement 
    title="Conversion Funnel" 
    description="Analysis of customer journey through the sales funnel"
    data={funnelData} 
  />;
};

WordCloudElement

A component for displaying word clouds with various customization options and interactive features.

Features:

  • Various word shapes (circle, square, diamond, star, triangle)
  • Category filtering
  • Animated timeframes to show word frequency changes
  • Interactive tooltips
  • Customizable colors and sizes

Props:

interface WordCloudElementProps {
  title?: string;
  data: {
    words: {
      text: string;
      value: number;
      category?: string;
      color?: string;
      shape?: 'circle' | 'square' | 'diamond' | 'star' | 'triangle';
      tooltip?: {
        title: string;
        content: string;
        action?: {
          label: string;
          onClick: () => void;
        };
      };
    }[];
    timeframes?: {
      label: string;
      words: Word[];
    }[];
  };
  shape?: 'circle' | 'rectangle' | 'custom';
  onLoad?: () => void;
}

Usage Example:

import { WordCloudElement } from '@/components/blog-elements';

const MyComponent = () => {
  const wordCloudData = {
    words: [
      { text: 'React', value: 100, category: 'Frontend', shape: 'circle' },
      { text: 'Node.js', value: 80, category: 'Backend', shape: 'square' },
      { text: 'TypeScript', value: 90, category: 'Language', shape: 'diamond' },
      // ...more words
    ],
    timeframes: [
      {
        label: '2020',
        words: [
          { text: 'React', value: 70, category: 'Frontend' },
          { text: 'Node.js', value: 60, category: 'Backend' },
          // ...more words
        ]
      },
      {
        label: '2021',
        words: [
          { text: 'React', value: 85, category: 'Frontend' },
          { text: 'Node.js', value: 70, category: 'Backend' },
          // ...more words
        ]
      },
      // ...more timeframes
    ]
  };

  return <WordCloudElement title="Technology Trends" data={wordCloudData} />;
};

HeatmapElement

A component for displaying heatmaps with various interactive features and customization options.

Features:

  • Multiple color schemes
  • Interactive zooming and panning
  • Time-based animation for data changes
  • Cell selection with highlighting
  • Optional overlay images
  • Detailed tooltips

Props:

interface HeatmapElementProps {
  title?: string;
  data: {
    data: number[][];
    xLabels: string[];
    yLabels: string[];
    title?: string;
    xAxisLabel?: string;
    yAxisLabel?: string;
    timeframes?: {
      label: string;
      data: number[][];
    }[];
    overlayImage?: string;
    colorScheme?: 'reds' | 'blues' | 'greens' | 'viridis' | 'custom';
    customColors?: string[];
    cellLabels?: string[][];
    cellTooltips?: {
      title: string;
      content: string;
      action?: {
        label: string;
        onClick: () => void;
      };
    }[][];
  };
  onLoad?: () => void;
}

Usage Example:

import { HeatmapElement } from '@/components/blog-elements';

const MyComponent = () => {
  const heatmapData = {
    data: [
      [10, 20, 30, 40],
      [15, 25, 35, 45],
      [5, 15, 25, 35]
    ],
    xLabels: ['Q1', 'Q2', 'Q3', 'Q4'],
    yLabels: ['Product A', 'Product B', 'Product C'],
    colorScheme: 'blues',
    cellTooltips: [
      [
        { title: 'Q1 - Product A', content: '10 units sold' },
        { title: 'Q2 - Product A', content: '20 units sold' },
        // ...more tooltips
      ],
      // ...more rows
    ],
    timeframes: [
      {
        label: '2020',
        data: [
          [8, 16, 24, 32],
          [12, 20, 28, 36],
          [4, 12, 20, 28]
        ]
      },
      {
        label: '2021',
        data: [
          [10, 20, 30, 40],
          [15, 25, 35, 45],
          [5, 15, 25, 35]
        ]
      },
      // ...more timeframes
    ]
  };

  return <HeatmapElement title="Quarterly Sales" data={heatmapData} />;
};

AlluvialDiagramElement

A component for visualizing flows between nodes in different categories, similar to a Sankey diagram. Perfect for showing relationships and transitions between distinct groups.

Features:

  • Interactive nodes and links with tooltips
  • Zoom and pan capability for exploring large diagrams
  • Gradient-colored flows between nodes
  • Responsive design that adapts to container width
  • Customizable node widths, padding, and colors
  • Error boundary protection against rendering failures

Props:

interface AlluvialDiagramElementProps {
  data: AlluvialDiagramData;
  title?: string;
  description?: string;
  width?: number;
  height?: number;
  textColor?: string;
  backgroundColor?: string;
  enableZoom?: boolean;
  minZoom?: number;
  maxZoom?: number;
}

interface AlluvialDiagramData {
  nodes: AlluvialNode[];
  links: AlluvialLink[];
  nodeWidth?: number;
  nodePadding?: number;
  iterations?: number;
  colors?: string[];
  height?: number;
  showLabels?: boolean;
  showValues?: boolean;
  title?: string;
  subtitle?: string;
  nodeAlign?: 'justify' | 'left' | 'right' | 'center';
}

Usage Example:

import { AlluvialDiagramElement } from '@/components/blog-elements/statistics';

const MyComponent = () => {
  const diagramData = {
    nodes: [
      { id: 'client1', name: 'Indecisive Client', group: 'Clients' },
      { id: 'client2', name: 'Tech Startup', group: 'Clients' },
      { id: 'req1', name: 'Make It Pop', group: 'Requirements' },
      { id: 'req2', name: 'Like Apple But Different', group: 'Requirements' },
      { id: 'dev1', name: 'CSS Wizard', group: 'Developers' },
      { id: 'dev2', name: 'React Enthusiast', group: 'Developers' },
    ],
    links: [
      { source: 'client1', target: 'req1', value: 30 },
      { source: 'client2', target: 'req2', value: 25 },
      { source: 'req1', target: 'dev1', value: 25 },
      { source: 'req2', target: 'dev2', value: 30 },
    ],
    title: 'Web Design Project Flow',
    height: 400,
    nodeWidth: 15,
    nodePadding: 10,
    showLabels: true,
    showValues: true
  };

  return (
    <AlluvialDiagramElement 
      data={diagramData}
      enableZoom={true}
      backgroundColor="transparent"
    />
  );
};

For detailed documentation, please refer to README-ALLUVIAL-DIAGRAM.md.

Performance & Stability Improvements

The AlluvialDiagram component has been enhanced with the following improvements:

  • Flickering Prevention: Fixed issues with diagram flickering using:

    • Debounced state updates
    • Stable component keys
    • Memoized expensive calculations
    • Optimized rendering lifecycle
  • Error Handling: Enhanced error recovery with:

    • Robust error boundaries
    • Automatic retry mechanisms (up to 3 attempts)
    • Detailed error reporting
    • Fallback UI components
  • Debugging Tools: Added comprehensive debugging tools:

    • Component lifecycle logging
    • Performance measurement utilities
    • Visual debug indicators
    • State inspection helpers
  • Rendering Optimizations:

    • React.memo for preventing unnecessary re-renders
    • useMemo and useCallback for stable callbacks and values
    • Optimized D3 operations with cleanup

For detailed debugging information, see README-ALLUVIAL-DIAGRAM-DEBUGGING.md.

CodePreview

A component for displaying code snippets with syntax highlighting and optional live previews.

Features

  • Syntax highlighting for multiple programming languages
  • Tab interface to switch between code and preview
  • Copy-to-clipboard functionality
  • Dark mode compatibility
  • Loading indicator for preview content
  • Customizable styling
  • Accessible with proper ARIA attributes

Props

interface CodePreviewProps {
  code: string;
  language?: string;
  title?: string;
  previewComponent?: React.ReactNode;
  defaultPreview?: boolean;
  enablePreview?: boolean;
  className?: string;
}

Usage Example

// Basic usage with just code
<CodePreview
  code="const greeting = 'Hello, world!';"
  language="javascript"
  title="Greeting Example"
/>

// With live preview
<CodePreview
  code="<button className='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'>Click me</button>"
  language="jsx"
  title="Button Example"
  previewComponent={<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Click me</button>}
  enablePreview={true}
  defaultPreview={false}
/>

SliderElement

A responsive and accessible image slider/carousel with automatic slideshows, touch navigation, and keyboard controls.

Features

  • Smooth transitions between slides with fade effects
  • Supports autoplay with configurable intervals
  • Touch-enabled swipe gestures for mobile users
  • Keyboard navigation (arrow keys and spacebar)
  • Responsive design that works on all screen sizes
  • Accessibility features with proper ARIA attributes
  • Play/pause controls for autoplay
  • Image captions support
  • Dark mode compatibility

Props

interface SliderImage {
  src: string;
  alt: string;
  caption?: string;
}

interface SliderElementProps {
  title?: string;
  description?: string;
  images: SliderImage[];
  autoPlay?: boolean;
  interval?: number; // in milliseconds
}

Usage Example

const images = [
  {
    src: "/images/slide1.jpg",
    alt: "Product overview",
    caption: "Our flagship product in action"
  },
  {
    src: "/images/slide2.jpg",
    alt: "Product features",
    caption: "Key features highlighted"
  }
];

<SliderElement
  title="Product Gallery"
  description="Explore our product from all angles"
  images={images}
  autoPlay={true}
  interval={5000}
/>

CalloutElement

A versatile callout component for displaying important messages, warnings, tips, and other highlighted content.

Features

  • Multiple callout types (info, success, warning, error, tip, code, note)
  • Customizable icons for each callout type
  • Consistent styling with appropriate colors for each type
  • Dark mode compatibility
  • Accessible with proper ARIA attributes
  • Allows HTML content through dangerouslySetInnerHTML (use carefully)

Props

type CalloutType = 'info' | 'success' | 'warning' | 'error' | 'tip' | 'code' | 'note';

interface CalloutElementProps {
  title?: string;
  type?: CalloutType;
  content: string;
  icon?: boolean;
  className?: string;
}

Usage Example

<CalloutElement
  title="Important Note"
  type="warning"
  content="This action cannot be undone. Please make sure you want to proceed."
  icon={true}
/>

<CalloutElement
  type="tip"
  content="You can use keyboard shortcuts to navigate faster."
/>

<CalloutElement
  title="Code Example"
  type="code"
  content="const greeting = 'Hello, world!';"
/>

Usage

To use these components in your blog posts, you can import them from the @/components/blog-elements directory.

import { 
  NodeDiagramElement, 
  FunnelChartElement,
  WordCloudElement,
  HeatmapElement 
} from '@/components/blog-elements';

// Then use them in your component
const MyBlogPost = () => {
  return (
    <div>
      <h1>My Blog Post</h1>
      <p>Some text...</p>
      
      <NodeDiagramElement 
        title="System Architecture" 
        nodes={nodes} 
        links={links} 
      />
      
      {/* More content... */}
      
      <FunnelChartElement 
        title="Conversion Funnel" 
        description="Analysis of customer journey through the sales funnel"
        data={funnelData} 
      />
      
      {/* More content... */}
    </div>
  );
};

Installation

To install the project dependencies:

npm install
# or
yarn install

Development

To start the development server:

npm run dev
# or
yarn dev

This will start the development server at http://localhost:3000.

Building for Production

To build the project for production:

npm run build
# or
yarn build

Running Tests

To run tests:

npm test
# or
yarn test

Styling

All components use a consistent color scheme based on Tübingen colors defined in @/constants/colors.ts. They're designed to work seamlessly in both light and dark mode, with proper contrast ratios for accessibility.

The components are built with responsive design in mind and will adapt to different screen sizes. On mobile, some interactive features may be simplified for better touch interaction.

License

This project is proprietary and owned by Magnus Ohle. All rights reserved.

Advanced Visualizations

Completed

  • Q-Q Plot: Statistical visualization for distribution comparison
  • Cartogram: Geographic data visualization with region distortion
  • Ridgeline Plot: Distribution visualization across categories
  • 3D Plots
    • Surface plots for terrain and mathematical functions
    • 3D scatter plots for multi-dimensional data
    • Interactive rotation and zoom
    • Full theme support
    • Responsive design

In Progress

  • Contour plots for level sets and density visualization
  • Advanced 3D plot features
    • Custom color scales
    • Multiple surface layers
    • Advanced lighting and shading
    • Export to 3D formats

Planned

  • Network graphs for relationship visualization
  • Sankey diagrams for flow visualization
  • Chord diagrams for relationship matrices

Design Principles

  • Minimal modernism with clean, uncluttered interfaces
  • Consistent styling across all visualizations
  • Full theme support (light/dark/responsive)
  • Responsive design for all screen sizes
  • Interactive features for enhanced data exploration
  • Accessibility considerations for all components
  • Performance optimization for 3D rendering
  • Touch-friendly controls for mobile devices

GDPR-Compliant Components

Static Map Component

The site includes a GDPR-compliant static map component that doesn't load any external data:

  • No external map services (OpenStreetMap, Google Maps, etc.)
  • No tracking or third-party cookies
  • No consent required for displaying maps
  • Full interactivity with purely client-side code

For detailed information about this implementation, see README-STATIC-MAP.md.

Usage:

<MapComponent 
  center={[48.52, 9.05]} 
  address="Haaggasse 10, 71070 Tübingen, Deutschland"
  title="Magnus Ohle"
  description="Webdesign & Entwicklung"
/>

About

Personal Website built in React with Tailwind CSS and Modern Minimalism Design

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages