diff --git a/package.json b/package.json index 1240a3d55..fd27dedb5 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "keploy-docs", "version": "0.0.0", "private": true, + "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", diff --git a/plugins/docusaurus-tailwindcss-loader/package.json b/plugins/docusaurus-tailwindcss-loader/package.json new file mode 100644 index 000000000..e045eed7b --- /dev/null +++ b/plugins/docusaurus-tailwindcss-loader/package.json @@ -0,0 +1,6 @@ +{ + "name": "docusaurus-tailwindcss-loader", + "version": "1.0.0", + "main": "index.js", + "private": true +} diff --git a/scripts/find_invalid_versions.js b/scripts/find_invalid_versions.js new file mode 100644 index 000000000..29bee3cee --- /dev/null +++ b/scripts/find_invalid_versions.js @@ -0,0 +1,31 @@ +const fs = require('fs'); +const path = require('path'); +function readJSON(p){ try{ return JSON.parse(fs.readFileSync(p,'utf8')); }catch(e){ return null; }} +const root = process.cwd(); +console.log('Scanning package.json...'); +const pkg = readJSON(path.join(root,'package.json')); +if(!pkg){ console.error('Could not read root package.json'); process.exit(2); } +const deps = {...pkg.dependencies, ...pkg.devDependencies}; +let found = false; +for(const [k,v] of Object.entries(deps)){ + if(typeof v !== 'string' || v.trim() === ''){ + console.log('BAD_DEP_VERSION', k, JSON.stringify(v)); found = true; + } +} +console.log('Scanning plugins for package.json files...'); +const pluginsDir = path.join(root,'plugins'); +if(fs.existsSync(pluginsDir)){ + for(const name of fs.readdirSync(pluginsDir)){ + const p = path.join(pluginsDir,name,'package.json'); + if(fs.existsSync(p)){ + const sub = readJSON(p); + if(!sub || !sub.version || sub.version.trim()===''){ + console.log('BAD_PLUGIN_VERSION', name, p, sub && sub.version); + found = true; + } + } else { + // plugins may not have package.json which is fine + } + } +} +if(!found) console.log('No obvious empty or non-string versions found.'); diff --git a/src/components/LogViewer.js b/src/components/LogViewer.js new file mode 100644 index 000000000..a3761c6a3 --- /dev/null +++ b/src/components/LogViewer.js @@ -0,0 +1,53 @@ +import React, {useState, useMemo} from 'react'; +import styles from './LogViewer.module.css'; + +// Minimal responsive log viewer component +export default function LogViewer({logs = []}) { + const [query, setQuery] = useState(''); + const [level, setLevel] = useState('all'); + + const levels = ['all','error','warn','info','debug']; + + const filtered = useMemo(()=>{ + const q = query.trim().toLowerCase(); + return logs.filter(l=> (level==='all' || l.level===level) && (!q || l.message.toLowerCase().includes(q) || (l.meta && JSON.stringify(l.meta).toLowerCase().includes(q)))); + },[logs, query, level]); + + return ( +
+
+
+ + + +
+
{filtered.length} entries
+
+ +
+ {filtered.length===0 ? ( +
No log entries match your filters.
+ ) : ( +
    + {filtered.map((l,i)=> ( +
  1. + + {l.level.toUpperCase()} + {l.message} + {l.meta &&
    {JSON.stringify(l.meta,null,2)}
    } +
  2. + ))} +
+ )} +
+
+ ); +} diff --git a/src/components/LogViewer.module.css b/src/components/LogViewer.module.css new file mode 100644 index 000000000..7b113d992 --- /dev/null +++ b/src/components/LogViewer.module.css @@ -0,0 +1,38 @@ +.wrapper { + margin: 1rem 0 2rem; +} +.header { + display:flex; + flex-wrap:wrap; + align-items:center; + gap:0.5rem 1rem; + justify-content:space-between; + margin-bottom:0.5rem; +} +.controls{ display:flex; gap:0.5rem; align-items:center; } +.search { padding:0.5rem .65rem; border-radius:6px; border:1px solid #ddd; min-width:180px; } +.selectLabel select { padding:0.45rem .5rem; border-radius:6px; border:1px solid #ddd; } +.count { color:var(--ifm-color-emphasis-300); } +.logPane { background:var(--ifm-card-background-color); border-radius:8px; padding:0.5rem; box-shadow:0 6px 15px rgba(0,0,0,0.04); max-height:50vh; overflow:auto; } +.list { list-style:none; margin:0; padding:0; } +.line { display:block; padding:.5rem .75rem; border-bottom:1px solid rgba(0,0,0,0.03); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', 'Courier New', monospace; font-size:0.95rem; } +.time { color: #777; margin-right:0.75rem; font-size:0.85rem; } +.level { font-weight:700; margin-right:0.6rem; text-transform:uppercase; font-size:0.75rem; padding:.15rem .4rem;border-radius:4px; } +.msg { color:var(--ifm-color); } +.meta { background: rgba(0,0,0,0.03); padding: .5rem; border-radius:6px; margin-top:0.5rem; overflow:auto; } +.empty { padding:1rem; color:var(--ifm-color-emphasis-300); } + +/* severity colours */ +.error .level { background:#ffe6e6; color:#b91c1c; } +.warn .level { background:#fff4e6; color:#b45309; } +.info .level { background:#e8f3ff; color:#0366d6; } +.debug .level { background:#eef2ff; color:#4338ca; } + +/* responsive tweaks */ +@media (max-width: 640px){ + .header { gap:0.5rem; } + .search { min-width:120px; } + .line { font-size:0.9rem; } +} + +.visuallyHidden { position:absolute !important; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; } diff --git a/src/css/custom.css b/src/css/custom.css index b40fda1aa..188993239 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -399,6 +399,93 @@ footer svg { /* Docs */ +/* Responsive helpers and utilities + - container, grid, responsive images, type scaling + - accessible focus, reduced-motion support + Usage: wrap content with `.container` or use `.grid` for responsive columns. +*/ +:root { + --bp-sm: 640px; + --bp-md: 768px; + --bp-lg: 1024px; + --bp-xl: 1280px; + --container-max: 1200px; + --container-padding: 1rem; +} + +.container { + width: 100%; + max-width: var(--container-max); + padding-left: var(--container-padding); + padding-right: var(--container-padding); + margin-left: auto; + margin-right: auto; + box-sizing: border-box; +} + +.grid { + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); +} + +.img-responsive, img.responsive { + max-width: 100%; + height: auto; + display: block; +} + +.lead { + font-size: 1.125rem; + line-height: 1.6; +} + +.visually-hidden { + position: absolute !important; + width: 1px; height: 1px; + padding: 0; margin: -1px; + overflow: hidden; clip: rect(0 0 0 0); + white-space: nowrap; border: 0; +} + +/* Simple two-column layout utility */ +.two-cols { + display: grid; + gap: 1rem; + grid-template-columns: 1fr; +} +@media (min-width: var(--bp-md)) { + .two-cols { grid-template-columns: 1fr 1fr; } +} + +/* Heading responsive scaling */ +h1 { font-size: clamp(1.45rem, 2.5vw + 0.5rem, 2.5rem); } +h2 { font-size: clamp(1.25rem, 2vw + 0.4rem, 1.75rem); } + +/* Focus visible for keyboard users */ +:focus-visible { + outline: 3px solid var(--ifm-color-primary); + outline-offset: 2px; +} + +/* Respect users who prefer reduced motion */ +@media (prefers-reduced-motion: reduce) { + * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } +} + +/* Small usage example (HTML) +
+
+
Brand / Title
+ +
+
+
Your main content
+ +
+
+*/ + .docusaurus-highlight-code-line { background-color: rgb(72, 77, 91); display: block; diff --git a/src/pages/logs.js b/src/pages/logs.js new file mode 100644 index 000000000..3dcb26f5e --- /dev/null +++ b/src/pages/logs.js @@ -0,0 +1,26 @@ +import React from 'react'; +import LogViewer from '../components/LogViewer'; + +const sampleLogs = [ + {time:'2025-12-16 10:00:01', level:'info', message:'Server started on http://localhost:3000'}, + {time:'2025-12-16 10:01:10', level:'warn', message:'Cache miss for key user:42'}, + {time:'2025-12-16 10:02:45', level:'error', message:'Unhandled exception in worker', meta:{err:'TypeError', trace:['file.js:42'] }}, + {time:'2025-12-16 10:03:07', level:'debug', message:'Request headers: {"user-agent":"curl/7"}'}, +]; + +export default function LogsPage(){ + return ( +
+

Log Viewer

+

A responsive log viewer component with filtering and accessible controls.

+ + +
+

Usage

+
+{``}
+        
+
+
+ ); +}