Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/docs/features/display-modes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ export const simpleConfig = {

<LiveCodes config={simpleConfig} height="400px"></LiveCodes>

## `console`

This mode is mainly useful for embedded playgrounds.
It shows a single editor together with the [console](./console.mdx) maximized (filling the output area), with the result page collapsed.
The [tools pane](./tools-pane.mdx) is fixed to show only the console; it cannot be resized or closed.
The console input is hidden, and the code can be run from the editor.
This mode is particularly useful for [WASM-based languages](../languages/index.mdx) (e.g. Python, Ruby, PHP, C, ...) whose output is mainly text-based (sent to the console).

Demo: Python with console

<LiveCodes
params={{ mode: 'console', py: "print('hello world')" }}
></LiveCodes>

## `lite`

Loads a light-weight, minimal code editor, with limited playground features.
Expand Down
2 changes: 1 addition & 1 deletion src/livecodes/config/build-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export const loadParamConfig = (config: Config, params: UrlQueryParams): Partial
paramsConfig.languages = params.languages
.split(',')
.map((lang) => lang.trim())
.map(getLanguageByAlias)
.map((lang) => getLanguageByAlias(lang))
.filter(Boolean) as Language[];
}

Expand Down
1 change: 1 addition & 0 deletions src/livecodes/config/validate-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const validateConfig = (config: Partial<Config>): Partial<Config> => {
'focus',
'lite',
'simple',
'console',
'editor',
'codeblock',
'result',
Expand Down
28 changes: 26 additions & 2 deletions src/livecodes/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ const showMode = (mode?: Config['mode'], view?: Config['view']) => {
focus: '111',
simple: '111',
lite: '111',
console: '111',
editor: '110',
codeblock: '010',
result: '001',
Expand Down Expand Up @@ -693,14 +694,21 @@ const showMode = (mode?: Config['mode'], view?: Config['view']) => {
document.body.classList.toggle('simple-mode', mode === 'simple');
document.body.classList.toggle('focus-mode', mode === 'focus');
document.body.classList.toggle('lite-mode', mode === 'lite');
document.body.classList.toggle('console-mode', mode === 'console');
document.body.classList.toggle('result', mode === 'result');
document.body.classList.toggle('no-result', mode === 'editor' || mode === 'codeblock');
if ((mode === 'full' || mode === 'simple') && !split) {
if ((mode === 'full' || mode === 'simple' || mode === 'console') && !split) {
split = createSplitPanes();
}
if (mode === 'focus') {
toolsPane?.setActiveTool('console');
}
if (mode === 'console') {
toolsPane?.setActiveTool('console');
if (!['open', 'full'].includes(toolsPane?.getStatus() || '')) {
toolsPane?.maximize();
}
}
window.dispatchEvent(new Event(customEvents.resizeEditor));
};

Expand Down Expand Up @@ -5105,6 +5113,17 @@ const configureSimpleMode = (config: Config) => {
});
};

const configureConsoleMode = (config: Config) => {
setConfig({
...config,
tools: {
enabled: Array.isArray(config.tools?.enabled) ? config.tools.enabled : ['console'],
active: config.tools?.active || 'console',
status: config.tools?.status || 'full',
},
});
};

const configureModes = ({
config,
isEmbed,
Expand All @@ -5129,6 +5148,9 @@ const configureModes = ({
if (config.mode === 'simple') {
configureSimpleMode(config);
}
if (config.mode === 'console') {
configureConsoleMode(config);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
};

const importExternalContent = async (options: {
Expand Down Expand Up @@ -5331,7 +5353,9 @@ const initializePlayground = async (
isLite ||
(options?.isEmbed ?? false) ||
initialConfig.mode === 'simple' ||
params.mode === 'simple';
params.mode === 'simple' ||
initialConfig.mode === 'console' ||
params.mode === 'console';

window.history.replaceState(null, '', './'); // fix URL from "/app" to "/"
await initializeStores(stores, isEmbed);
Expand Down
34 changes: 33 additions & 1 deletion src/livecodes/languages/__tests__/languages.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { getLanguageByAlias, getLanguageEditorId, getLanguageExtension, mapLanguage } from '..';
import {
getLanguageByAlias,
getLanguageEditorId,
getLanguageExtension,
languageIsEnabled,
mapLanguage,
} from '..';

describe('languages', () => {
test('getLanguageByAlias', () => {
Expand Down Expand Up @@ -35,4 +41,30 @@ describe('languages', () => {
expect(mapLanguage('ruby')).toBe('ruby');
expect(mapLanguage('html')).toBe('html');
});

describe('deprecation warnings', () => {
let warn: jest.SpyInstance;

beforeEach(() => {
(window as any).deps.loggedDeprecations = [];
warn = jest.spyOn(console, 'warn').mockImplementation(() => {
//
});
});

afterEach(() => {
warn.mockRestore();
});

test('warns when a deprecated language name is used', () => {
expect(getLanguageByAlias('ocaml')).toBe('ocaml');
expect(warn).toHaveBeenCalled();
});

test('does not warn while enumerating languages', () => {
languageIsEnabled('ocaml', { languages: undefined } as any);
languageIsEnabled('ocaml', { languages: ['html', 'css', 'javascript'] } as any);
expect(warn).not.toHaveBeenCalled();
});
});
});
53 changes: 35 additions & 18 deletions src/livecodes/languages/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
import type { Compiler, Config, CustomSettings, Language, Processor } from '../models';
import type {
Compiler,
Config,
CustomSettings,
Language,
LanguageSpecs,
Processor,
} from '../models';
import { getDocsUrl, getLanguageCustomSettings } from '../utils/utils';
import { highlightjsUrl } from '../vendors';

export const getLanguageByAlias = (alias: string = ''): Language | undefined => {
const logDeprecation = (alias: string, language?: LanguageSpecs) => {
if (!globalThis.window?.deps) return;
window.deps.loggedDeprecations ??= [];
const deprecation = language?.deprecation?.(alias.toLowerCase() as Language);
if (!deprecation || window.deps.loggedDeprecations.includes(deprecation.old)) return;
// eslint-disable-next-line no-console
console.warn(
`Deprecation warning: The language name "${alias}" will use the compiler "${deprecation.new}" in the future.`,
`If you want to continue using the current compiler, use the language name "${deprecation.old}" instead.`,
language?.name ? `Docs: ${getDocsUrl()}languages/${language.name}` : '',
);
window.deps.loggedDeprecations.push(deprecation.old);
};

export const getLanguageByAlias = (
alias: string = '',
options: { warn?: boolean } = {},
): Language | undefined => {
if (!alias) return;
const aliasLowerCase = alias?.toLowerCase();
const language = window.deps.languages.find(
Expand All @@ -11,20 +35,10 @@ export const getLanguageByAlias = (alias: string = ''): Language | undefined =>
lang.title.toLowerCase() === aliasLowerCase ||
lang.extensions.map((ext) => ext.toLowerCase()).includes(aliasLowerCase),
);
if (globalThis.window?.deps) window.deps.loggedDeprecations ??= [];
const deprecation = language?.deprecation?.(aliasLowerCase as Language);
if (
deprecation &&
window.deps.loggedDeprecations &&
!window.deps.loggedDeprecations.includes(deprecation.old)
) {
// eslint-disable-next-line no-console
console.warn(
`Deprecation warning: The language name "${alias}" will use the compiler "${deprecation.new}" in the future.`,
`If you want to continue using the current compiler, use the language name "${deprecation.old}" instead.`,
language?.name ? `Docs: ${getDocsUrl()}languages/${language.name}` : '',
);
window.deps.loggedDeprecations?.push(deprecation.old);
// only warn when the alias is actually used (e.g. from config or user selection),
// not when enumerating languages (menus, compiler list, starter templates)
if (options.warn !== false) {
logDeprecation(alias, language);
}
return language?.name;
};
Expand Down Expand Up @@ -71,7 +85,7 @@ export const mapLanguage = (
'html';

export const languageIsEnabled = (language: Language, config: Config) => {
const lang = getLanguageByAlias(language);
const lang = getLanguageByAlias(language, { warn: false });
if (!lang) return false;
if (!config.languages) return true;
if (
Expand All @@ -80,7 +94,10 @@ export const languageIsEnabled = (language: Language, config: Config) => {
) {
return true;
}
return config.languages?.map(getLanguageByAlias).filter(Boolean).includes(lang);
return config.languages
?.map((alias) => getLanguageByAlias(alias, { warn: false }))
.filter(Boolean)
.includes(lang);
};

export const processorIsEnabled = (processor: Processor, config: Config) => {
Expand Down
26 changes: 25 additions & 1 deletion src/livecodes/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1793,7 +1793,8 @@
}
}

.simple-mode {
.simple-mode,
.console-mode {
.editor-title:not(.active),
&.embed #toolbar .toolbar-render #result-button,
&.embed #toolbar .toolbar-render #fullscreen-button,
Expand Down Expand Up @@ -1842,6 +1843,29 @@
}
}

.console-mode {
#toolbar {
margin-bottom: 0;
transform: none;
width: 100%;
}

#zoom-button,
.console-close-button,
#size-label {
display: none !important;

Check warning on line 1856 in src/livecodes/styles/app.scss

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this "!important" and resolve the specificity conflict instead.

See more on https://sonarcloud.io/project/issues?id=live-codes_livecodes&issues=AaFBK89t303bynK82j1A&open=AaFBK89t303bynK82j1A&pullRequest=1072
}

#tools-pane-bar {
cursor: default;
pointer-events: none;
}

#tools-pane-buttons {
pointer-events: auto;
}
}

.focus-mode {
#app-menu-button-project,
#app-menu-button-settings,
Expand Down
6 changes: 4 additions & 2 deletions src/livecodes/templates/get-starter-templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ const loadTemplates = async (baseUrl: string): Promise<Template[]> =>
export const getStarterTemplates = async (config: Config, baseUrl: string): Promise<Template[]> =>
(await loadTemplates(baseUrl))
.filter((template) => {
const enabledLanguages = config.languages?.map(getLanguageByAlias).filter(Boolean);
const enabledLanguages = config.languages
?.map((language) => getLanguageByAlias(language, { warn: false }))
.filter(Boolean);
if (!enabledLanguages) return true;
if (template.name === 'blank') return true;

Expand All @@ -38,7 +40,7 @@ export const getStarterTemplates = async (config: Config, baseUrl: string): Prom
template.script?.language,
];
for (const language of templateLanguages) {
const lang = getLanguageByAlias(language);
const lang = getLanguageByAlias(language, { warn: false });
if (!lang || !enabledLanguages.includes(lang)) return false;
}
return true;
Expand Down
8 changes: 8 additions & 0 deletions src/livecodes/toolspane/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ export const createToolsPane = (
buttons.id = 'tools-pane-buttons';
buttons.classList.add('tool-buttons');
toolsPaneBar.appendChild(buttons);
// prevent starting a drag when clicking the buttons
eventsManager.addEventListener(buttons, 'mousedown', (event) => event.stopPropagation(), false);
eventsManager.addEventListener(
buttons,
'touchstart',
(event) => event.stopPropagation(),
false,
);

const closeButton = document.createElement('button');
closeButton.classList.add('console-close-button');
Expand Down
2 changes: 1 addition & 1 deletion src/sdk/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ export interface AppConfig {
* Sets the [display mode](https://livecodes.io/docs/features/display-modes).
* @default "full"
*/
mode: 'full' | 'focus' | 'lite' | 'simple' | 'editor' | 'codeblock' | 'result';
mode: 'full' | 'focus' | 'lite' | 'simple' | 'console' | 'editor' | 'codeblock' | 'result';

/**
* Sets enabled and active tools and status of [tools pane](https://livecodes.io/docs/features/tools-pane).
Expand Down
Loading