PageSourceSearch

https://cristiangabriel.dev/chrome.js?v=f66801fc

js cristiangabriel.dev collected 2026-10-02 01:52:18 UTC 11,221 bytes, 338 lines download raw bytes

1(function () {
2  /* global React */
3  // ─────────────────────────────────────────────────────────────
4  // Chrome — Sidebar, TopNav, BotanicalAnchor, Footer
5  // Persistent across all pages
6  // ─────────────────────────────────────────────────────────────
7
8  const {
9    useEffect,
10    useState
11  } = React;
12
13  // ###### THEME (LIGHT / DARK) ######
14  // Drives [data-theme="dark"] on <html>. theme-dark.css picks it up.
15  // Persisted in localStorage so the choice sticks across reloads.
16  const THEME_KEY = "cg.theme";
17  function readStoredTheme() {
18    try {
19      return localStorage.getItem(THEME_KEY) === "dark" ? "dark" : "light";
20    } catch (e) {
21      return "light";
22    }
23  }
24  function applyTheme(theme) {
25    if (theme === "dark") document.documentElement.setAttribute("data-theme", "dark");else document.documentElement.removeAttribute("data-theme");
26    try {
27      localStorage.setItem(THEME_KEY, theme);
28    } catch (e) {}
29  }
30
31  // ###### SVG ICON SET ######
32  // Stroke-based, forest green
33  function Ico({
34    name
35  }) {
36    const common = {
37      width: 18,
38      height: 18,
39      viewBox: "0 0 24 24",
40      fill: "none",
41      stroke: "currentColor",
42      strokeWidth: 1.6,
43      strokeLinecap: "round",
44      strokeLinejoin: "round",
45      "aria-hidden": true,
46      focusable: false
47    };
48    if (name === "github") return /*#__PURE__*/React.createElement("svg", common, /*#__PURE__*/React.createElement("path", {
49      d: "M9 19c-4.3 1.4-4.3-2.5-6-3M15 22v-4a3 3 0 0 0-.9-2.4c3-.3 6-1.5 6-6.7A5.2 5.2 0 0 0 18.7 5a4.8 4.8 0 0 0-.1-3.6S17.3 1 15 2.7a13.4 13.4 0 0 0-7 0C5.7 1 4.4 
491.4 4.4 1.4A4.8 4.8 0 0 0 4.3 5a5.2 5.2 0 0 0-1.4 3.6c0 5.2 3 6.4 6 6.7A3 3 0 0 0 8 18v4"
50    }));
51    if (name === "linkedin") return /*#__PURE__*/React.createElement("svg", common, /*#__PURE__*/React.createElement("path", {
52      d: "M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z"
53    }), /*#__PURE__*/React.createElement("rect", {
54      x: 2,
55      y: 9,
56      width: 4,
57      height: 12
58    }), /*#__PURE__*/React.createElement("circle", {
59      cx: 4,
60      cy: 4,
61      r: 2
62    }));
63    if (name === "stack") return /*#__PURE__*/React.createElement("svg", common, /*#__PURE__*/React.createElement("path", {
64      d: "M3 12h14M3 16h14M3 8l13 2M5 4l11 4M17 18v3H3v-3"
65    }));
66    if (name === "pin") return /*#__PURE__*/React.createElement("svg", common, /*#__PURE__*/React.createElement("path", {
67      d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"
68    }), /*#__PURE__*/React.createElement("circle", {
69      cx: 12,
70      cy: 10,
71      r: 3
72    }));
73    if (name === "mail") return /*#__PURE__*/React.createElement("svg", common, /*#__PURE__*/React.createElement("path", {
74      d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"
75    }), /*#__PURE__*/React.createElement("path", {
76      d: "M22 6l-10 7L2 6"
77    }));
78    return null;
79  }
80
81  // ###### SIDEBAR ######
82  function Sidebar({
83    onNav
84  }) {
85    const [theme, setTheme] = useState(readStoredTheme);
86    useEffect(() => {
87      applyTheme(theme);
88    }, [theme]);
89    const toggleTheme = () => setTheme(t => t === "dark" ? "light" : "dark");
90    return /*#__PURE__*/React.createElement("aside", {
91      className: "sidebar"
92    }, /*#__PURE__*/React.createElement("a", {
93      className: "brand",
94      href: "#",
95      onClick: e => {
96        e.preventDefault();
97        if (onNav) onNav("home");
98      },
99      "aria-label": "Cristian Gabriel, Home",
100      title: "Home"
101    }, /*#__PURE__*/React.createElement("span", {
102      className: "brand-mark"
103    }, /*#__PURE__*/React.createElement("svg", {
104      viewBox: "0 0 40 56",
105      width: 44,
106      height: 60,
107      fill: "none"
108    }, /*#__PURE__*/React.createElement("path", {
109      d: "M 20 54 C 20 44 18 36 18 28",
110      stroke: "var(--forest)",
111      strokeWidth: 1.4,
112      strokeLinecap: "round"
113    }), /*#__PURE__*/React.createElement("path", {
114      d: "M 18 28 C 4 22 2 10 6 2 C 18 4 22 18 18 28 Z",
115      fill: "var(--forest)"
116    }), /*#__PURE__*/React.createElement("path", {
117      d: "M 19 36 C 30 32 34 24 32 16 C 22 18 18 28 19 36 Z",
118      stroke: "var(--forest)",
119      strokeWidth: 1.3
120    }), /*#__PURE__*/React.createElement("circle", {
121      cx: 20,
122      cy: 54,
123      r: 1.4,
124      fill: "var(--forest)"
125    }))), /*#__PURE__*/React.createElement("div", {
126      className: "brand-rule"
127    }), /*#__PURE__*/React.createElement("div", {
128      className: "brand-name"
129    }, /*#__PURE__*/React.createElement("span", null, "Cristian"), /*#__PURE__*/React.createElement("span", null, "Gabriel")), /*#__PURE__*/React.createElement("div", {
130      className: "brand-role"
131    }, "Software Developer")), /*#__PURE__*/React.createElement("nav", {
132      className: "sidebar-socials",
133      "aria-label": "Social and contact links"
134    }, /*#__PURE__*/React.createElement("a", {
135      className: "social",
136      href: "https://github.com/cristiangabriel88",
137      target: "_blank",
138      rel: "noopener"
139    }, /*#__PURE__*/React.createElement("span", {
140      className: "social-ico"
141    }, /*#__PURE__*/React.createElement(Ico, {
142      name: "github"
143    })), /*#__PURE__*/React.createElement("span", {
144      className: "social-label"
145    }, "GitHub")), /*#__PURE__*/React.createElement("a", {
146      className: "social",
147      href: "https://www.linkedin.com/in/cristian-gabriel-constantinescu-781a6b237",
148      target: "_blank",
149      rel: "noopener"
150    }, /*#__PURE__*/React.createElement("span", {
151      className: "social-ico"
152    }, /*#__PURE__*/React.createElement(Ico, {
153      name: "linkedin"
154    })), /*#__PURE__*/React.createElement("span", {
155      className: "social-label"
156    }, "LinkedIn")), /*#__PURE__*/React.createElement("a", {
157      className: "social",
158      href: "https://stackoverflow.com/users/18754276/cristiangabriel",
159      target: "_blank",
160      rel: "noopener"
161    }, /*#__PURE__*/React.createElement("span", {
162      className: "social-ico"
163    }, /*#__PURE__*/React.createElement(Ico, {
164      name: "stack"
165    })), /*#__PURE__*/React.createElement("span", {
166      className: "social-label"
167    }, "Stack Overflow")), /*#__PURE__*/React.createElement("a", {
168      className: "social",
169      href: "https://www.google.com/maps/search/?api=1&query=Bucharest%2C+Romania",
170      target: "_blank",
171      rel: "noopener noreferrer"
172    }, /*#__PURE__*/React.createElement("span", {
173      className: "social-ico"
174    }, /*#__PURE__*/React.createElement(Ico, {
175      name: "pin"
176    })), /*#__PURE__*/React.createElement("span", {
177      className: "social-label"
178    }, "Bucharest, RO")), /*#__PURE__*/React.createElement("a", {
179      className: "social",
180      href: "mailto:[email protected]"
181    }, /*#__PURE__*/React.createElement("span", {
182      className: "social-ico"
183    }, /*#__PURE__*/React.createElement(Ico, {
184      name: "mail"
185    })), /*#__PURE__*/React.createElement("span", {
186      className: "social-label"
187    }, "Email me"))), /*#__PURE__*/React.createElement("div", {
188      className: "sidebar-footer"
189    }, /*#__PURE__*/React.createElement("span", null, "\xA9", " ", /*#__PURE__*/React.createElement("span", {
190      style: {
191        fontFamily: "var(--serif)",
192        fontStyle: "italic",
193        textTransform: "none",
194        fontSize: 12,
195        letterSpacing: 0
196      }
197    }, new Date().getFullYear())), /*#__PURE__*/React.createElement("button", {
198      className: "theme-toggle",
199      onClick: toggleTheme,
200      title: theme === "dark" ? "Light mode" : "Dark mode",
201      "aria-label": "Toggle theme"
202    }, theme === "dark" ? /*#__PURE__*/React.createElement("svg", {
203      viewBox: "0 0 16 16",
204      width: 13,
205      height: 13,
206      fill: "currentColor",
207      "aria-hidden": "true"
208    }, /*#__PURE__*/React.createElement("circle", {
209      cx: 8,
210      cy: 8,
211      r: 3
212    }), /*#__PURE__*/React.createElement("g", {
213      stroke: "currentColor",
214      strokeWidth: 1.2,
215      strokeLinecap: "round"
216    }, /*#__PURE__*/React.createElement("line", {
217      x1: 8,
218      y1: 1,
219      x2: 8,
220      y2: 3
221    }), /*#__PURE__*/React.createElement("line", {
222      x1: 8,
223      y1: 13,
224      x2: 8,
225      y2: 15
226    }), /*#__PURE__*/React.createElement("line", {
227      x1: 1,
228      y1: 8,
229      x2: 3,
230      y2: 8
231    }), /*#__PURE__*/React.createElement("line", {
232      x1: 13,
233      y1: 8,
234      x2: 15,
235      y2: 8
236    }), /*#__PURE__*/React.createElement("line", {
237      x1: 3,
238      y1: 3,
239      x2: 4.4,
240      y2: 4.4
241    }), /*#__PURE__*/React.createElement("line", {
242      x1: 11.6,
243      y1: 11.6,
244      x2: 13,
245      y2: 13
246    }), /*#__PURE__*/React.createElement("line", {
247      x1: 3,
248      y1: 13,
249      x2: 4.4,
250      y2: 11.6
251    }), /*#__PURE__*/React.createElement("line", {
252      x1: 11.6,
253      y1: 4.4,
254      x2: 13,
255      y2: 3
256    }))) : /*#__PURE__*/React.createElement("svg", {
257      viewBox: "0 0 16 16",
258      width: 13,
259      height: 13,
260      fill: "currentColor",
261      "aria-hidden": "true"
262    }, /*#__PURE__*/React.createElement("path", {
263      d: "M 8 1 A 7 7 0 1 0 15 8 A 5 5 0 0 1 8 1 Z"
264    })))));
265  }
266
267  // ###### TOP NAV ######
268  function TopNav({
269    page,
270    onNav
271  }) {
272    const pages = [{
273      id: "home",
274      label: "Home"
275    }, {
276      id: "about",
277      label: "About"
278    }, {
279      id: "projects",
280      label: "Projects"
281    }];
282    return /*#__PURE__*/React.createElement("nav", {
283      className: "topnav",
284      "aria-label": "Primary"
285    }, pages.map(p => /*#__PURE__*/React.createElement("button", {
286      key: p.id,
287      className: "nav-btn" + (page === p.id ? " active" : ""),
288      onClick: () => onNav(p.id),
289      "aria-current": page === p.id ? "page" : undefined
290    }, p.label)));
291  }
292
293  // ###### BOTANICAL ANCHOR ######
294  // Decorative plant photo per page. home.png and about.png have black/colored
295  // backgrounds and render as-is; the projects anchor is a white-bg PNG that
296  // uses mix-blend-multiply (see styles.css) to drop the white cleanly.
297  const BOTANICAL_SRC = {
298    home: "resources/images/home.webp",
299    about: "resources/images/about.webp",
300    projects: "resources/images/contact2.webp"
301  };
302  function BotanicalAnchor({
303    page
304  }) {
305    return /*#__PURE__*/React.createElement("img", {
306      key: page,
307      className: `botanical ${page} fade-in`,
308      src: BOTANICAL_SRC[page],
309      alt: "",
310      "aria-hidden": "true",
311      draggable: "false"
312    });
313  }
314
315  // ###### FOOTER ######
316  function PageFooter({
317    page
318  }) {
319    return /*#__PURE__*/React.createElement("div", {
320      className: "footer"
321    }, /*#__PURE__*/React.createElement("span", {
322      className: "ssh-hint",
323      style: {
324        color: "var(--forest)",
325        letterSpacing: "0.22em"
326      }
327    }, "Type ", /*#__PURE__*/React.createElement("span", {
328      className: "ssh-word"
329    }, "ssh"), " to open a shell"));
330  }
331  Object.assign(window, {
332    Sidebar,
333    TopNav,
334    BotanicalAnchor,
335    PageFooter,
336    Ico
337  });
338})();

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.