Skip to content
Open
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
45 changes: 8 additions & 37 deletions app/components/Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@

<script setup>
import { ref, toRefs, watch, nextTick, computed, onMounted } from 'vue';
import { v4 as uuid } from 'uuid';
import { createEditor } from '~/lib/project';
import useSplitView from '@/composables/useSplitView';
import useEditorUtils from '~/composables/useEditorUtils';
import { useWindowSize, useResizeObserver } from '@vueuse/core';
import usePreferencesStore from '@/composables/usePreferencesStore';
import { last, range, defaults } from 'lodash';
import { last, range } from 'lodash';

const props = defineProps({
project: { type: Object, required: true },
Expand All @@ -95,13 +95,7 @@ const { width } = useWindowSize();

const hasSmallScreen = computed(() => width.value <= 1024);

const page = defaults(props.project.page, {
editors: [],
sizes: [40, 60],
editorSizes: [],
previousOrientation: null,
orientation: hasSmallScreen.value ? 'top' : 'left',
});
const page = props.project.page;

const { sizes, editorSizes, editors, orientation, previousOrientation } = toRefs(page);

Expand Down Expand Up @@ -200,28 +194,14 @@ function removeEditor(id) {
$bus.$emit('editors:refresh');
}

function makeEditor() {
const language = last(editors.value)?.language ?? preferences.editorLanguage;

return {
id: uuid(),
added: [],
removed: [],
focused: [],
language: language,
tabSize: preferences.editorTabSize,
value: preferences.editorInitialValue,
};
}

function addEditor() {
if (editors.value.length === 0) {
orientation.value = hasSmallScreen.value ? 'top' : preferences.editorOrientation;
}

destroyEditorSplitView();

editors.value.push(makeEditor());
editors.value.push(
createEditor(preferences, {
language: last(editors.value)?.language ?? preferences.editorLanguage,
})
);

$bus.$emit('editors:refresh');
}
Expand Down Expand Up @@ -278,18 +258,9 @@ watch(orientation, async () => {
refreshEditorsLayout();
});

// Here we are ensuring all editors that have been restored
// from localstorage have any additional properties
// that may have been added with future updates.
editors.value = editors.value.map((editor) => defaults(editor, makeEditor()));

watch(page, () => emit('update:touched'), { deep: true, flush: 'sync' });

onMounted(() => {
if (editors.value.length === 0) {
addEditor();
}

initPageSplitView();
initEditorSplitView();
});
Expand Down
11 changes: 2 additions & 9 deletions app/components/Preview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,8 @@ const { scenes, applyScene } = useScenes();

const { name, code, languages } = toRefs(props);

const {
settings,
setWidth,
setHeight,
setAspectRatio,
resetWindowSize,
settingsDefaults,
setDefaultBackground,
} = usePreview(props, { emit, pane });
const { settings, setWidth, setHeight, setAspectRatio, resetWindowSize, setDefaultBackground } =
usePreview(props, { emit, pane });

const {
title,
Expand Down
7 changes: 2 additions & 5 deletions app/composables/usePreview.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import useSettings from '@/composables/useSettings';
import useAspectRatios from '@/composables/useAspectRatios';
import { DEFAULT_BACKGROUND } from './useBackgrounds';
import { watch, nextTick } from 'vue';
import { cloneDeep, defaults, isEqual, omit } from 'lodash';
import { cloneDeep, isEqual, omit } from 'lodash';

export default function (props, { emit, pane }) {
const { calculateAspectRatio } = useAspectRatios();

const { settingsDefaults } = useSettings();
const settings = defaults(props.settings, cloneDeep(settingsDefaults));
const settings = props.settings;

watch(
() => cloneDeep(omit(settings, ['image', 'themeType', 'themeBackground'])),
Expand Down Expand Up @@ -112,7 +110,6 @@ export default function (props, { emit, pane }) {

return {
settings,
settingsDefaults,
setWidth,
setHeight,
resetWindowSize,
Expand Down
21 changes: 3 additions & 18 deletions app/composables/useProjectStoreFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,13 @@ import { v4 as uuid } from 'uuid';
import { defineStore } from 'pinia';
import { namespace } from './useProjectStores';
import useTemplateStore from './useTemplateStore';
import usePreferencesStore from './usePreferencesStore';
import { createProject } from '~/lib/project';
import { cloneDeep, replace, omit } from 'lodash';

export default function (id) {
return defineStore(id, {
state: () => ({
version: '1.26.1',
modified: false,
page: {},
settings: {},
viewport: {
x: 0,
y: -150,
zoom: 1,
},
tab: {
kind: 'project',
order: 0,
name: null,
created_at: new Date(),
id: replace(id, namespace, ''),
},
}),
state: () => createProject(usePreferencesStore(), replace(id, namespace, '')),

actions: {
/**
Expand Down
74 changes: 29 additions & 45 deletions app/composables/useProjectStores.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import { fileDialog } from 'file-select-dialog';
import useCurrentTab from './useCurrentTab';
import useProjectStoreFactory from './useProjectStoreFactory';
import { computed, nextTick, ref } from 'vue';
import { has, head, sortBy, debounce, startsWith, cloneDeep } from 'lodash';
import { head, sortBy, debounce, startsWith, cloneDeep } from 'lodash';
import usePreferencesStore from './usePreferencesStore';
import { createProject, normalizeProject } from '~/lib/project';
import { toast } from 'vue-sonner';

export const namespace = 'pages/';

const maxRecentlyClosedProjects = 20;

export default function () {
const { $bus } = useNuxtApp();
const preferences = usePreferencesStore();

const { currentTab, setTabFromProject } = useCurrentTab();

Expand Down Expand Up @@ -62,31 +65,14 @@ export default function () {
* @param {*} data
*/
function syncProjectStateWithData(project, data) {
const normalized = normalizeProject(data, preferences);

project.$patch((state) => {
state.page = data.page;
state.settings = data.settings;
state.tab.name = data.tab.name;
state.tab.saved_project_id = data.tab.saved_project_id;
state.tab.kind = data.tab.kind ?? 'project';

// Here we will port old editors that don't contain the newly added
// properties from the new v1.9.0 update. v1.9.0 has also added a
// new "version" property to projects, so we can target this
// property to determine if we need to add these attributes.
if (!data.hasOwnProperty('version')) {
state.page.editors.map((editor) => {
editor.added = [];
editor.removed = [];
editor.focused = [];
});
}

// Here we will port the old orientation setting,
// so templates that were saved in an older
// version can be restored properly.
if (['portrait', 'landscape'].includes(state.page.orientation)) {
state.page.orientation = 'left';
}
state.page = normalized.page;
state.settings = normalized.settings;
state.tab.name = normalized.tab.name;
state.tab.saved_project_id = normalized.tab.saved_project_id;
state.tab.kind = normalized.tab.kind;
});
}

Expand All @@ -98,7 +84,14 @@ export default function () {
* @returns {Store}
*/
function startProjectFromScratch(project) {
project.$patch((state) => (state.tab.kind = 'project'));
const initial = createProject(preferences, project.tab.id);

project.$patch((state) => {
state.page = initial.page;
state.settings = initial.settings;
state.modified = true;
state.tab.kind = 'project';
});

return project;
}
Expand All @@ -112,7 +105,7 @@ export default function () {
* @returns {Store}
*/
function startProjectFromTemplate(project, template) {
syncProjectStateWithData(project, cloneDeep(template));
syncProjectStateWithData(project, template);

project.$patch((state) => {
state.tab.kind = 'project';
Expand All @@ -134,25 +127,16 @@ export default function () {
return;
}

const data = await new Response(file).json();

['tab', 'page', 'settings'].forEach((requiredKey) => {
if (!has(data, requiredKey)) {
$bus.$emit(
'alert',
'danger',
'Error importing configuration. Required data is missing.'
);

console.error(`The configuration file is missing the data key [${requiredKey}].`);
}
});

const project = addNewProject();
let data;

if (project) {
syncProjectStateWithData(project, data);
try {
data = normalizeProject(await new Response(file).json(), preferences);
} catch (error) {
toast.error(`Unable to import project. ${error.message}`);
return;
}

syncProjectStateWithData(addNewProject(), data);
}

/**
Expand Down
98 changes: 2 additions & 96 deletions app/composables/useSettings.js
Original file line number Diff line number Diff line change
@@ -1,104 +1,10 @@
import { reactive } from 'vue';
import { cloneDeep, defaults as applyDefaults, pick } from 'lodash';
import { DEFAULT_BACKGROUND } from '~/composables/useBackgrounds';
import { createSettings } from '~/lib/settings';
import usePreferencesStore from '~/composables/usePreferencesStore';

export default function (defaults = {}) {
const preferences = usePreferencesStore();

const settingsDefaults = {
title: '',
width: 500,
height: 300,
position: 'center',
landscape: false,
showHeader: true,
showHeaderAccent: false,
showTitle: true,
showMenu: true,
showDividers: true,
showColorMenu: false,
headerTitleColor: {
red: 156,
green: 163,
blue: 175,
alpha: 1,
},
showLineNumbers: false,
scene: 'none',
background: DEFAULT_BACKGROUND,
backgroundColor: null,

themeType: 'dark',
themeOpacity: 1.0,
themeName: preferences.previewThemeName,
themeBackground: '#fff',
aspectRatio: null,

lockWindowSize: preferences.previewLockToWindow,
lockWindowPaddingX: preferences.previewLockToWindowPaddingX,
lockWindowPaddingY: preferences.previewLockToWindowPaddingY,

fontSize: preferences.previewFontSize,
fontFamily: preferences.previewFontFamily,
lineHeight: preferences.previewLineHeight,

padding: 16,
paddingLocked: true,
paddingTop: 16,
paddingBottom: 16,
paddingLeft: 16,
paddingRight: 16,

marginTop: 0,
marginBottom: 0,
marginLeft: 0,
marginRight: 0,

image: null,
scale: 1.0,

showBorder: false,

borderRadius: 12,
borderRadiusLocked: true,
borderRadiusTopLeft: 12,
borderRadiusTopRight: 12,
borderRadiusBottomLeft: 12,
borderRadiusBottomRight: 12,
borderWidth: 2,
borderColor: {
red: 0,
green: 0,
blue: 0,
alpha: 1,
},

showShadow: true,
shadowX: 0,
shadowY: 10,
shadowBlur: 10,
shadowSpread: -5,
shadowColor: {
red: 0,
green: 0,
blue: 0,
alpha: 0.3,
},

showShine: false,
shineWidth: 50,
shineHeight: 172,
shineOpacity: 0.03,

showSocialBadge: preferences.showSocialBadge,
socialType: preferences.socialType,
socialUsername: preferences.socialUsername,
socialDisplayName: preferences.socialDisplayName,
socialPosition: preferences.socialPosition,
socialBorderRadius: 25,
socialLocation: 'outside',
};
const settingsDefaults = createSettings(usePreferencesStore());

const settings = reactive(
pick(applyDefaults(cloneDeep(defaults), settingsDefaults), Object.keys(settingsDefaults))
Expand Down
Loading
Loading