Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Syntax Highlighting Themes and Add Theme Switch #3

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

Web tool for visualization and analysis of the AST and its source code.

For more details, see the [LARA Framework repository](https://github.com/specs-feup/lara-framework).

## Integration

Internally, the tool follows a system for interaction with the compiler, to be able to apply code linkage and correction, among others, while still being independent of the specific compiler. This system is an implementation of the Factory Method pattern, and the integration with Clava is illustrated in the following diagram:
Internally, the tool follows a system for interaction with the compiler, to be able to apply code linkage and correction, among others, while still being independent of the specific compiler. This system is an implementation of the Factory Method pattern, and the [integration with Clava](https://github.com/specs-feup/clava-visualization) is illustrated in the following diagram:

![Compiler Abstracted System](./compiler-abstracted-system.svg)

Expand Down Expand Up @@ -41,4 +43,6 @@ VisualizationTool.port; // port to which the server is listening
VisualizationTool.hostname; // hostname to which the server is listening
```

For more details, refer to the `GenericVisualizationTool` documentation.
For more details, refer to the `GenericVisualizationTool` documentation.

For a more detailed example on the usage of this project, check the [Clava visualization tool repository](https://github.com/specs-feup/clava-visualization).
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@specs-feup/lara-visualization",
"version": "1.0.6",
"version": "1.1.0",
"author": "Bruno Oliveira",
"description": "LARA package for visualization of the mapping between source code and AST",
"type": "module",
Expand All @@ -18,8 +18,10 @@
"typedoc.config.js"
],
"scripts": {
"build": "tsc && copyfiles -u 1 -e \"**/*.ts\" \"src/public/**/*\" api/",
"build:watch": "tsc --watch",
"build": "tsc && copyfiles -u 1 -e '**/*.ts' 'src/public/**/*' api/",
"build:ts": "tsc",
"build:public": "copyfiles -u 1 -e '**/*.ts' 'src/public/**/*' api/",
"build:watch": "tsc --watch & npx nodemon -w 'src/public/**/*' -e 'html,css,png,ico' -x 'npm run build:public'",
"lint": "eslint .",
"docs": "typedoc",
"test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --detectOpenHandles --forceExit src",
Expand All @@ -45,6 +47,7 @@
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-tsdoc": "^0.2.17",
"jest": "^29.7.0",
"nodemon": "^3.1.9",
"ts-jest": "^29.2.2",
"typedoc": "^0.26.4",
"typescript": "^5.5.3"
Expand Down
69 changes: 36 additions & 33 deletions src/public/css/color-scheme.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
--darker-gray: #313131;
--black: #161616;
--translucid-black: #16161666;
--light-blue: #19d8ff;
--strong-translucid-light-blue: #19d8ff66;
--weak-translucid-light-blue: #19d8ff33;
--gray-blue: #004483;
--strong-translucid-gray-blue: #004483bf;
--weak-translucid-gray-blue: #0044837f;
--blue: #0000ff;
--violet: #dbb8fe;
--purple: #7d00ae;
--tangerine: #ff9e64;
--russet: #794120;
--translucid-russet: #794120aa;
--more-translucid-russet: #79412055;
--sky-blue: #7dcfff;
--translucid-sky-blue: #b2e3ffaa;
--more-translucid-sky-blue: #dbf2ff55;
--cornflower-blue: #234b90;
--violet: #b69af7;
--purple: #5a3e8e;
}

/* Light color scheme */
Expand All @@ -36,43 +37,45 @@
--button-hover-bg-color: var(--lighter-gray);
--button-disabled-bg-color: var(--lighter-gray);

--header-button-bg-color: var(--light-gray);

--tab-bg-color: var(--white);
--tab-hover-bg-color: var(--lighter-gray);
--tab-active-bg-color: var(--light-gray);

--highlight-color: var(--light-blue);
--secondary-highlight-color: var(--strong-translucid-light-blue);
--tertiary-highlight-color: var(--weak-translucid-light-blue);
--highlight-color: var(--sky-blue);
--secondary-highlight-color: var(--translucid-sky-blue);
--tertiary-highlight-color: var(--more-translucid-sky-blue);

--line-num-color: var(--dark-gray);
--secondary-code-bg-color: var(--lighter-gray);
}

/* Dark color scheme */

@media (prefers-color-scheme: dark) {
:root {
--bg-color: var(--black);
--translucid-bg-color: var(--translucid-black);
--text-color: var(--white);
--header-color: var(--darker-gray);
--border-color: var(--lighter-gray);
--icon-color: var(--white);
--disabled-icon-color: var(--gray);
:root.dark {
--bg-color: var(--black);
--translucid-bg-color: var(--translucid-black);
--text-color: var(--white);
--header-color: var(--darker-gray);
--border-color: var(--lighter-gray);
--icon-color: var(--white);
--disabled-icon-color: var(--gray);

--button-bg-color: var(--black);
--button-hover-bg-color: var(--darker-gray);
--button-disabled-bg-color: var(--dark-gray);

--button-bg-color: var(--black);
--button-hover-bg-color: var(--darker-gray);
--button-disabled-bg-color: var(--dark-gray);
--header-button-bg-color: var(--dark-gray);

--tab-bg-color: var(--black);
--tab-hover-bg-color: var(--darker-gray);
--tab-active-bg-color: var(--dark-gray);
--tab-bg-color: var(--black);
--tab-hover-bg-color: var(--darker-gray);
--tab-active-bg-color: var(--dark-gray);

--highlight-color: var(--gray-blue);
--secondary-highlight-color: var(--strong-translucid-gray-blue);
--tertiary-highlight-color: var(--weak-translucid-gray-blue);
--highlight-color: var(--russet);
--secondary-highlight-color: var(--translucid-russet);
--tertiary-highlight-color: var(--more-translucid-russet);

--line-num-color: var(--gray);
--secondary-code-bg-color: var(--darker-gray);
}
--line-num-color: var(--gray);
--secondary-code-bg-color: var(--darker-gray);
}
43 changes: 40 additions & 3 deletions src/public/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,57 @@ header {
padding: 0.5em;
background-color: var(--header-color);

display: flex;
display: grid;
grid-template-columns: auto auto 1fr auto;
align-content: center;
align-items: center;
justify-content: left;
gap: 0.5em;
}

header .specs-logo {
height: 100%;
height: 3em;
}

header h1 {
font-size: 1.5em;
}

header button {
height: 3em;
width: 3em;
padding: 0;
border: none;
border-radius: 100%;
background-color: var(--header-color);

display: flex;
align-items: center;
justify-content: center;
}

header button:hover {
background-color: var(--header-button-bg-color);
}

#theme-switch {
grid-column-start: 4;
}

#theme-switch > * {
display: none;
}

#theme-switch.light > .light-icon {
display: block;
}

#theme-switch.dark > .dark-icon {
display: block;
}

#theme-switch.auto > .auto-icon {
display: block;
}

main {
--code-container-width: calc(100% - var(--ast-container-width) - 1em);
Expand Down
18 changes: 8 additions & 10 deletions src/public/css/syntax-highlighting.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
--comment: var(--dark-gray);
--keyword: var(--purple);
--type: var(--purple);
--string: var(--blue);
--literal: var(--blue);
--string: var(--cornflower-blue);
--literal: var(--cornflower-blue);
}

@media (prefers-color-scheme: dark) {
:root {
--comment: var(--gray);
--keyword: var(--violet);
--type: var(--violet);
--string: var(--light-blue);
--literal: var(--light-blue);
}
:root.dark {
--comment: var(--gray);
--keyword: var(--violet);
--type: var(--violet);
--string: var(--tangerine);
--literal: var(--tangerine);
}

/* Syntax highlighting classes */
Expand Down
13 changes: 12 additions & 1 deletion src/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="module">
const storageTheme = localStorage.getItem('theme');
const setDark = storageTheme === 'dark' || (!storageTheme && window.matchMedia('(prefers-color-scheme: dark)').matches);

document.documentElement.classList.toggle('dark', setDark);
</script> <!-- Added inline in head to prevent FOUC -->
<link rel="stylesheet" href="/css/imports.css">
<link rel="stylesheet" href="/css/color-scheme.css">
<link rel="stylesheet" href="/css/styles.css">
Expand All @@ -11,10 +17,15 @@
<title>LARA Visualization Tool</title>
</head>
<body>
<script>0</script> <!-- To prevent FOUC (Flash Of Unstyled Content) -->
<script>0</script> <!-- To prevent Firefox FOUC-->
<header>
<img class="specs-logo" src="/img/specs-logo.png" alt="SPeCS Logo">
<h1>LARA Visualization Tool</h1>
<button id="theme-switch" title="Light/Dark Theme">
<span class="icon material-symbols-outlined light-icon">light_mode</span>
<span class="icon material-symbols-outlined dark-icon">dark_mode</span>
<span class="icon material-symbols-outlined auto-icon">brightness_6</span>
</button>
</header>
<main>
<button id="continue-button" disabled>
Expand Down
10 changes: 7 additions & 3 deletions src/public/js/communication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,20 @@ const parseMessage = (message: MessageEvent): any => {
return JSON.parse(message.data);
};

const continueButtonOnClick = (ws: WebSocket): void => {
const continueButton = getContinueButton();
const continueButtonOnClick = (continueButton: HTMLButtonElement, ws: WebSocket): void => {
continueButton.disabled = true;
sendData(ws, { message: 'continue' });
};

const addContinueButtonEventListeners = (ws: WebSocket): void => {
const continueButton = getContinueButton();
continueButton.addEventListener('click', () => continueButtonOnClick(continueButton, ws));
};

export {
getWebSocket,
sendData,
parseMessage,
webSocketOnMessage,
continueButtonOnClick,
addContinueButtonEventListeners,
};
9 changes: 9 additions & 0 deletions src/public/js/components.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
const getThemeSwitch = (() => {
const themeSwitch = document.querySelector<HTMLInputElement>('#theme-switch');
if (!themeSwitch) {
throw new Error('Could not find theme switch');
}
return (): HTMLInputElement => themeSwitch;
})();

const getAstContainer = (() => {
const astContainer = document.querySelector<HTMLDivElement>('#ast-container');
if (!astContainer) {
Expand Down Expand Up @@ -261,6 +269,7 @@ const updateFileTabsArrows = (): void => {
}

export {
getThemeSwitch,
getAstContainer,
getCodeContainer,
getNodeInfoContainer,
Expand Down
10 changes: 5 additions & 5 deletions src/public/js/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { continueButtonOnClick, getWebSocket } from "./communication.js";
import { getContinueButton } from "./components.js";
import { addThemeSwitchListener, syncThemeSwitch } from "./theme.js";
import { addContinueButtonEventListeners, getWebSocket } from "./communication.js";
import { addResizerEventListeners } from "./visualization.js";

const setupEventListeners = (ws: WebSocket): void => {
const continueButton = getContinueButton();
continueButton.addEventListener('click', () => continueButtonOnClick(ws));

addThemeSwitchListener();
addContinueButtonEventListeners(ws);
addResizerEventListeners();
}

Expand All @@ -17,5 +16,6 @@ const setupEventListeners = (ws: WebSocket): void => {
};
setupWebSocket();

syncThemeSwitch(); // Code in header does not sync theme switch
setupEventListeners(ws!);
})();
46 changes: 46 additions & 0 deletions src/public/js/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { getThemeSwitch } from "./components.js";

const syncDocumentWithTheme = () => {
let theme = localStorage.getItem('theme');
let setDark = theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches);

document.documentElement.classList.toggle('dark', setDark);
}

const syncThemeSwitch = () => {
const theme = localStorage.getItem('theme');
const themeSwitch = getThemeSwitch();

themeSwitch.classList.toggle('light', theme === 'light');
themeSwitch.classList.toggle('dark', theme === 'dark');
themeSwitch.classList.toggle('auto', !theme);
}

const toggleTheme = () => {
switch (localStorage.getItem('theme')) {
case 'light':
localStorage.setItem('theme', 'dark');
break;

case 'dark':
localStorage.removeItem('theme');
break;

default:
localStorage.setItem('theme', 'light');
break;
}

syncDocumentWithTheme();
syncThemeSwitch();
}

const addThemeSwitchListener = () => {
const themeSwitch = document.querySelector<HTMLButtonElement>('#theme-switch');
if (!themeSwitch)
return;

themeSwitch.addEventListener('click', toggleTheme);
}

export { syncDocumentWithTheme, syncThemeSwitch, addThemeSwitchListener };
3 changes: 2 additions & 1 deletion src/public/js/visualization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ const addResizerEventListeners = (): void => {

let drag = false;
let width = astContainer.offsetWidth;
const resizerWidth = resizer.offsetWidth;

const rootStyle = document.documentElement.style;

Expand All @@ -219,7 +220,7 @@ const addResizerEventListeners = (): void => {
const minWidth = continueButton.offsetWidth;
const maxWidth = codeContainer.getBoundingClientRect().right - astLeft - 160;

width = event.x - astLeft;
width = event.x - astLeft - resizerWidth / 2;
if (width < minWidth)
width = minWidth;
else if (width > maxWidth)
Expand Down