simian 0.1.1

A command-line tool for exploring and implementing Machine Learning algorithms in Rust.
Documentation
import { useState, useEffect } from 'react'
import { Loader2, Moon, Sun } from 'lucide-react'
import { ThemeProvider, useTheme } from 'next-themes'
import { TooltipProvider } from '@/components/ui/tooltip'
import { I18nProvider } from '@/i18n/context'
import { Editor } from '@/editor'
import { title } from '@/editor/addon/title'
import { text } from '@/editor/addon/text'
import { paragraph } from '@/editor/addon/paragraph'
import { codeBlock } from '@/editor/addon/code-block'
import { root } from '@/editor/addon/root'
import { subtitle } from '@/editor/addon/subtitle'
import { heading } from '@/editor/addon/heading'
import { column } from '@/editor/addon/column'
import './App.css'

// Default fallback if loading fails
const defaultInitialValue = [
  {
    type: 'title',
    children: [{ text: 'Untitled Paper' }],
  },
  {
    type: 'code-block',
    language: 'rust',
    children: [{ text: 'println!("Hello from Simian Paper!");' }],
  },
]

declare global {
  interface Window {
    __SIMIAN_PAPER_DATA__?: any;
  }
}

let saveTimeout: ReturnType<typeof setTimeout>

function ThemeToggle() {
  const { resolvedTheme, setTheme } = useTheme()
  const [mounted, setMounted] = useState(false)
  
  useEffect(() => {
    setMounted(true)
  }, [])

  if (!mounted) return <div className="w-9 h-9" />

  return (
    <button
      onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
      className="p-2 rounded-full hover:bg-black/10 dark:hover:bg-white/10 transition-colors"
      title="Toggle Theme"
    >
      {resolvedTheme === 'dark' ? <Sun size={20} /> : <Moon size={20} />}
    </button>
  )
}

export default function App() {
  const [value, setValue] = useState<any>(defaultInitialValue)
  const [loading, setLoading] = useState(true)
  const [mode, setMode] = useState<'read' | 'write'>('write')

  useEffect(() => {
    // 1. Check for statically injected data first
    if (window.__SIMIAN_PAPER_DATA__) {
      setValue(window.__SIMIAN_PAPER_DATA__)
      setMode('read')
      setLoading(false)
      return
    }

    // 2. Fallback to API if not static
    fetch('/api/paper/content')
      .then((res) => res.json())
      .then((data) => {
        if (data && data.length > 0) {
          setValue(data)
        }
      })
      .catch((e) => console.error('Failed to load paper content', e))
      .finally(() => setLoading(false))
  }, [])

  const onChange = (newValue: any) => {
    if (saveTimeout) clearTimeout(saveTimeout)
    saveTimeout = setTimeout(() => {
      fetch('/api/paper/content', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newValue),
      }).catch((e) => console.error('Failed to save', e))
    }, 2000)
  }

  const addons = [
    root(),
    title(),
    subtitle(),
    text(),
    paragraph(),
    heading(),
    column(),
    codeBlock(),
  ]

  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      <TooltipProvider>
        <I18nProvider>
          <div className="studio-container w-full min-h-screen bg-background text-foreground flex flex-col">
            <header className="w-full flex justify-between items-center p-4 px-8 bg-transparent sticky top-0 z-50">
              <div>{/* Left side empty or placeholder for future */}</div>
              <div className="flex items-center">
                <ThemeToggle />
              </div>
            </header>

            {loading ? (
              <div className="flex items-center justify-center p-12 mt-12 text-muted-foreground">
                <Loader2 className="animate-spin mr-2" size={20} /> Loading
                workspace...
              </div>
            ) : (
              <div className="flex-1 w-full max-w-4xl mx-auto mt-12 pb-24 px-8">
                <Editor
                  addons={addons}
                  initialValue={value}
                  onContentChange={onChange}
                  mode={mode}
                />
              </div>
            )}
          </div>
        </I18nProvider>
      </TooltipProvider>
    </ThemeProvider>
  )
}