PageSourceSearch

https://portfolio.lovesahaj1225.workers.dev/src/chrome.jsx

js portfolio.lovesahaj1225.workers.dev collected 2026-10-03 05:53:31 UTC 8,641 bytes, 268 lines download raw bytes

1// ─────── CHROME: tabline, winbar, tree, statusline, cmdline ───────
2
3function Tabline({ buffers, active, onSelect, modified, onSimpleView }) {
4  return (
5    <div className="tabline">
6      {buffers.map((b, i) => (
7        <div
8          key={b.id}
9          className={'tab ' + (b.id === active ? 'active' : '')}
10          onClick={() => onSelect(b.id)}
11        >
12          <span className="tab-idx">{i + 1}</span>
13          <span>{b.file}</span>
14          {modified[b.id] && <span className="tab-dot">●</span>}
15        </div>
16      ))}
17      <div className="tab-spacer" />
18      <div className="tab-meta">
19        <span>~/portfolio</span>
20        <span style={{ color: 'var(--green)' }}>● main</span>
21        {onSimpleView && (
22          <button
23            type="button"
24            className="view-switch tab-switch"
25            onClick={onSimpleView}
26            data-comment-anchor="8344181b30-button-335-7"
27          >
28            <span className="tab-switch-glyph">◳</span>
29            simple view
30          </button>
31        )}
32      </div>
33    </div>
34  );
35}
36
37function Winbar({ buffer }) {
38  const crumbs = ['~', 'portfolio', buffer.file];
39  return (
40    <div className="winbar">
41      {crumbs.map((c, i) => (
42        <React.Fragment key={i}>
43          <span className={'crumb' + (i === crumbs.length - 1 ? ' accent' : '')}>{c}</span>
44          {i < crumbs.length - 1 && <span className="sep">›</span>}
45        </React.Fragment>
46      ))}
47    </div>
48  );
49}
50
51function FileTree({ buffers, active, onSelect, deps, theme, effTheme, onToggleTheme }) {
52  const data = deps.data;
53  const themeGlyph = theme === 'system' ? '◐' : (effTheme || theme) === 'light' ? '☀' : '☾';
54  const themeLabel = theme === 'system' ? 'system' : theme === 'light' ? 'light' : 'dark';
55  return (
56    <div className="tree">
57      <div className="tree-header">NETRW — ~/portfolio</div>
58
59      <div className="tree-group">── buffers ──</div>
60      {buffers.map((b) => (
61        <div
62          key={b.id}
63          className={'tree-item' + (b.id === active ? ' active' : '')}
64          onClick={() => onSelect(b.id)}
65        >
66          <span className="glyph">▸</span>
67          <span>{b.file}</span>
68          <span className="key">{b.key}</span>
69        </div>
70      ))}
71
72      <div className="tree-group">── links ──</div>
73      <a className="tree-item" href={`https://${data.github}`} target="_blank" rel="noreferrer">
74        <span className="glyph">↗</span>
75        <span>github</span>
76      </a>
77      <a className="tree-item" href={`https://${data.linkedin}`} target="_blank" rel="noreferrer">
78        <span className="glyph">↗</span>
79        <span>linkedin</span>
80      </a>
81      <a className="tree-item" href={`mailto:${data.email}`}>
82        <span className="glyph">↗</span>
83        <span>email</span>
84      </a>
85
86      <div className="tree-group">── shortcuts ──</div>
87      <div className="tree-item" style={{ cursor: 'default' }}>
88        <span className="glyph"></span>
89        <span>which-key</span>
90        <span className="key">?</span>
91      </div>
92      <div className="tree-item" style={{ cursor: 'default' }}>
93        <span className="glyph"></span>
94        <span>command</span>
95        <span className="key">:</span>
96      </div>
97      <div className="tree-item" style={{ cursor: 'default' }}>
98        <span className="glyph"></span>
99        <span>search</span>
100        <span className="key">/</span>
101      </div>
102      <div className="tree-item" style={{ cursor: 'default' }}>
103        <span className="glyph"></span>
104        <span>find files</span>
105        <span className="key">⌃p</span>
106      </div>
107
108      <div className="tree-group">── theme ──</div>
109      <button type="button" className="tree-item tree-theme" onClick={onToggleTheme}>
110        <span className="glyph">{themeGlyph}</span>
111        <span>{themeLabel} theme</span>
112        <span className="key">t</span>
113      </button>
114    </div>
115  );
116}
117
118function Statusline({ mode, buffer, line, total, search, match }) {
119  const modeLabel =
120    {
121      NORMAL: 'NORMAL',
122      INSERT: 'INSERT',
123      VISUAL: 'VISUAL',
124      COMMAND: 'COMMAND',
125      SEARCH: 'SEARCH',
126    }[mode] || 'NORMAL';
127  const modeColor = {
128    NORMAL: 'var(--blue)',
129    INSERT: 'var(--green)',
130    VISUAL: 'var(--purple)',
131    COMMAND: 'var(--yellow)',
132    SEARCH: 'var(--orange)',
133  }[mode];
134  const pct = total > 0 ? Math.round((line / total) * 100) : 0;
135  const hasMatches = match && match.count > 0;
136  return (
137    <div className="statusline">
138      <div className="sl-mode" style={{ background: modeColor }}>
139        {modeLabel}
140      </div>
141      <div className="sl-seg git"> main</div>
142      <div className="sl-seg">{buffer.file}</div>
143      {search &&
144        <div className="sl-seg diag">
145          /{search}{hasMatches ? ` [${match.idx}/${match.count}]` : ' [0/0]'}
146        </div>
147      }
148      <div className="sl-spacer" />
149      <div className="sl-right">
150        <span className="sl-ft"> markdown</span>
151        <span className="sep">│</span>
152        <span>utf-8</span>
153        <span className="sep">│</span>
154        <span>LF</span>
155        <span className="sep">│</span>
156        <span>{line}:1</span>
157        <span className="sep">│</span>
158        <span>{pct}%</span>
159      </div>
160    </div>
161  );
162}
163
164function Cmdline({ mode, cmd, setCmd, onSubmit, onCancel, hint, completions = [] }) {
165  const inputRef = React.useRef(null);
166  const [wildItems, setWildItems] = React.useState([]);
167  const compList = React.useRef([]);
168  const compIdx = React.useRef(-1);
169
170  function resetComp() {
171    compList.current = [];
172    compIdx.current = -1;
173    setWildItems([]);
174  }
175
176  React.useEffect(() => {
177    if ((mode === 'COMMAND' || mode === 'SEARCH') && inputRef.current) {
178      inputRef.current.focus();
179    }
180    resetComp();
181  }, [mode]);
182
183  if (mode === 'COMMAND' || mode === 'SEARCH') {
184    const prefix = mode === 'COMMAND' ? ':' : '/';
185    return (
186      <div className="cmdline active">
187        {wildItems.length > 0 && (
188          <div className="cmd-wildmenu">
189            {wildItems.map((item, i) => (
190              <span
191                key={item}
192                className={'cmd-wm-item' + (i === compIdx.current ? ' on' : '')}
193              >
194                {item}
195              </span>
196            ))}
197          </div>
198        )}
199        <span className="prefix">{prefix}</span>
200        <input
201          ref={inputRef}
202          value={cmd}
203          onChange={(e) => {
204            resetComp();
205            setCmd(e.target.value);
206          }}
207          onKeyDown={(e) => {
208            if (e.key === 'Enter') {
209              e.preventDefault();
210              resetComp();
211              onSubmit();
212            } else if (e.key === 'Escape') {
213              e.preventDefault();
214              resetComp();
215              onCancel();
216            } else if (e.key === 'Tab' && mode === 'COMMAND') {
217              e.preventDefault();
218              let list = compList.current;
219              if (!list.length) {
220                const base = cmd.trim().toLowerCase();
221                list = completions.filter((c) => c.startsWith(base));
222                if (!list.length) return;
223                compList.current = list;
224              }
225              const dir = e.shiftKey ? -1 : 1;
226              const len = list.length;
227              compIdx.current = ((compIdx.current + dir) % len + len) % len;
228              setCmd(list[compIdx.current]);
229              setWildItems([...list]);
230            }
231          }}
232          placeholder={mode === 'COMMAND' ? 'command — Tab to complete' : 'search buffer…'}
233        />
234      </div>
235    );
236  }
237
238  return (
239    <div className="cmdline">
240      <span className="hint">
241        {hint ||
242          '-- ? which-key · : command · / search · ⌃p find files · hjkl move · gg/G jump --'}
243      </span>
244    </div>
245  );
246}
247
248function Splash() {
249  const ascii = `   ▄▄▄       ▄▄▄·  ▄• ▄▌
250   ▀▄ █·    ▐█ ▀█ █▪██▌
251   ▐▀▀▄ ██▌ ▐█▀▀█ █▌▐█▌
252   ▐█•█▌███▪▐█ ▪▐▌▐█▄█▌
253   .▀  ▀·▀▀·  ▀  ▀  ▀▀▀
254   love.sahaj - portfolio v26.04`;
255  return (
256    <div className="splash">
257      <div className="splash-inner">
258        <div className="logo">{ascii}</div>
259        <div className="ver">a portfolio by Love Sahajbir Singh</div>
260        <div className="tip">
261          press <kbd>?</kbd> any time to learn the keys
262        </div>
263      </div>
264    </div>
265  );
266}
267
268Object.assign(window, { Tabline, Winbar, FileTree, Statusline, Cmdline, Splash });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.