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
84 changes: 84 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,87 @@ VITE_SERVER_URL=http://localhost:9200

# If running the demo project
VITE_DEMO_PREVIEW_URL=http://localhost:3001

# Set the default user settings (user can override them in the UI)
# (Enter data in JSON format)
#VITE_DEFAULT_USER_SETTINGS={"appearanceDarkMode":false,"editorFontSize":16,"editorLiveUpdate":true,"editorUpdateTimeout":1000,"editorShowPrintMargin":false,"editorAutoSyncFrom":true,"editorAutoSyncInterval":1000,"autoCleanData":false,"editorTabSize":2,"userDataAutoFetch":true,"layoutEditorLocation":"start","layoutSitePreviewLocation":"start","layoutSitePreviewPadding":true,"layoutSitePreviewKeepRatio":true,"layoutAutoSplit":true,"blueprintsIncludeTypings":true,"blueprintsReadFromData":true,"blueprintsReadFromStructure":true,"blueprintsWriteToData":true,"blueprintsWriteToDefault":true,"blueprintsWriteToIndex":true,"blueprintsWriteToStructure":true,"blueprintsWriteToTypings":true,"blueprintsWriteToSettings":true}

# Force user settings (user won't be able to override them from the UI)
# (Enter data in JSON format)
#VITE_FORCE_USER_SETTINGS={"appearanceDarkMode":true}

# Force a structure data
#VITE_FORCE_STRUCTURE=

# Inject user data
# (Enter data in JSON format)
#VITE_USER_DATA=

# UI CONFIGURATION
# --------------------
# Use the following keys and separated them by a comma to disable many items in the UI.
#
# toolbar
# toolbar.menu
# toolbar.logo
# toolbar.project_selector
# toolbar.project_selector.new
# toolbar.project_selector.delete
# toolbar.advanced
# toolbar.site_preview
# toolbar.site_preview.refresh
# toolbar.site_preview.mobile
# toolbar.site_preview.desktop
# toolbar.site_preview.blank
# toolbar.trigger_menu
# toolbar.info
# toolbar.locale_selector
# toolbar.login
# toolbar.settings
# toolbar.settings.edit_json
# toolbar.settings.fetch_data
# toolbar.settings.download_data
# toolbar.settings.migrate_data
# toolbar.settings.clear_data
# toolbar.settings.settings
# toolbar.settings.logout
#
# sidebar
# sidebar.sections
# sidebar.tools
# sidebar.tools.file_manager
# sidebar.advanced
# sidebar.advanced.hash
# sidebar.advanced.server
# sidebar.advanced.upload
# sidebar.tutorial
# sidebar.github
# sidebar.footer
#
# structure
# structure.menu
# structure.menu.structure
# structure.menu.blueprints
# structure.menu.settings
# structure.menu.integration
# structure.trigger_menu
# structure.settings
# structure.settings.endpoint
# structure.settings.permissions_structure
# structure.settings.permissions_admin
# structure.footer
# structure.footer_local_sync
# structure.footer_save
#
# site_preview
#
# data
# data.footer
# data.footer.set_as_default
# data.footer.sync_local
# data.footer.sync_endpoint
#
# documentation
VITE_UI_DISABLE=
#VITE_UI_DISABLE=toolbar.logo,toolbar.login,toolbar.settings.edit_json,toolbar.settings.migrate_data,toolbar.settings.settings,documentation,structure,sidebar.tutorial,sidebar.github,sidebar.advanced

8 changes: 4 additions & 4 deletions docs/structure.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# YAML Interface
# YAML Structure
---
Let's get started on building your ideal admin panel with JSON.ms!

## Global Configuration
Let's start with the global configuration. You can copy paste and adjust the following code in your _YAML_ interface:
Let's start with the global configuration. You can copy paste and adjust the following code in your _YAML_ structure:
```yaml
global:

Expand All @@ -20,7 +20,7 @@ These settings allows to create an admin panel that aligns with your brand and u

## Locales

JSON.ms allows you to manage locales for translating the fields that will be saved in your application. You can easily define multiple locales in a customizable list of key/value pairs within the YAML interface. If no locales are provided, JSON.ms will default to "`en-US`." This feature enables you to ensure that the data fields are accurately translated, accommodating users who speak different languages and enhancing the overall usability of your application.
JSON.ms allows you to manage locales for translating the fields that will be saved in your application. You can easily define multiple locales in a customizable list of key/value pairs within the YAML structure. If no locales are provided, JSON.ms will default to "`en-US`." This feature enables you to ensure that the data fields are accurately translated, accommodating users who speak different languages and enhancing the overall usability of your application.

```yaml
locales:
Expand Down Expand Up @@ -404,7 +404,7 @@ Here's an example of a field using an enum:

## Schemas

Reusable schemas (fieldset) are a powerful feature that allows you to define a set of predefined fields that can be referenced multiple times throughout your interface. This promotes consistency in your data definitions and reduces redundancy, making your code cleaner and easier to maintain.
Reusable schemas (fieldset) are a powerful feature that allows you to define a set of predefined fields that can be referenced multiple times throughout your structure. This promotes consistency in your data definitions and reduces redundancy, making your code cleaner and easier to maintain.

```yaml
schemas:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@json.ms/www",
"private": true,
"type": "module",
"version": "1.3.1",
"version": "1.3.3",
"scripts": {
"dev": "vite --host",
"build": "run-p type-check \"build-only {@}\" --",
Expand Down
3 changes: 3 additions & 0 deletions src/components/ActionBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,17 +192,20 @@ const reset = () => {
</template>
<v-list>
<v-list-item
v-if="globalStore.uiConfig.data_footer_set_as_default"
title="Set as default values"
prepend-icon="mdi-text-box-check-outline"
@click="onSetAsDefaultValues"
/>
<v-list-item
v-if="globalStore.uiConfig.data_footer_sync_local"
title="Sync with local file only"
prepend-icon="mdi-sync-circle"
:disabled="!canInteractWithSyncedFolder || !canSave"
@click="onSyncWithLocalOnly"
/>
<v-list-item
v-if="globalStore.uiConfig.data_footer_sync_endpoint"
title="Sync with endpoint only"
prepend-icon="mdi-webhook"
:disabled="!canInteractWithServer || !canSave"
Expand Down
41 changes: 30 additions & 11 deletions src/components/JSONms.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,22 @@ const { sendMessageToIframe } = useIframe();
const { isFolderSynced, syncFromFolder, autoAskToSyncFolder, syncToFolder, unSyncFolder, stopWatchSnapshotDirectory, watchSnapshotDirectory } = useSyncing();

globalStore.initUserSettings();
globalStore.initUIConfig();

const splitTabs = computed((): boolean => globalStore.admin.structure && globalStore.userSettings.data.layoutAutoSplit && layoutSize.value.data >= (mobileFrameWidth.value * 2));
const splitTabs = computed((): boolean => {
if (![globalStore.uiConfig.data, globalStore.uiConfig.documentation].every(item => item)) {
return false;
}
return globalStore.admin.structure && globalStore.userSettings.data.layoutAutoSplit && layoutSize.value.data >= (mobileFrameWidth.value * 2);
});
const tab = computed({
get: () => {
if (globalStore.uiConfig.data && !globalStore.uiConfig.documentation) {
return 'data';
}
if (!globalStore.uiConfig.data && globalStore.uiConfig.documentation) {
return 'docs';
}
const advancedMode = globalStore.admin.structure && windowWidth.value > 900;
if (advancedMode && splitTabs.value) {
return globalStore.admin.dataTab === 'data'
Expand Down Expand Up @@ -316,12 +328,14 @@ useShortcut({
}).listen();
initLayout();

setUserData({}, true);
const envInitialUserData = import.meta.env.VITE_USER_DATA;
const initialUserData = JSON.parse(envInitialUserData || '{}') || {};
setUserData(initialUserData, true);
onMounted(() => {
sitePreview.value?.structureEditor?.scrollToSection(getAvailableSection());
structureEditor.value?.scrollToSection(getAvailableSection());
})
if (globalStore.userSettings.data.userDataAutoFetch) {
if (!envInitialUserData && globalStore.userSettings.data.userDataAutoFetch) {
refreshUserData();
}
if (globalStore.session.loggedIn) {
Expand All @@ -333,6 +347,7 @@ if (globalStore.session.loggedIn) {

<!-- TOOLBAR -->
<Toolbar
v-if="globalStore.uiConfig.toolbar"
v-model="structure"
:structures="structures"
:structure-data="structureParsedData"
Expand All @@ -357,13 +372,15 @@ if (globalStore.session.loggedIn) {

<!-- SIDEBAR -->
<Sidebar
v-if="globalStore.uiConfig.sidebar"
:structure-data="structureParsedData"
:user-data="modelStore.userData"
:server-settings="serverSettings"
/>

<!-- EDITOR -->
<v-navigation-drawer
v-if="globalStore.uiConfig.structure"
v-model="showEditor"
:width="layoutSize.editor.width"
:temporary="layoutSize.editor.temporary"
Expand Down Expand Up @@ -394,6 +411,7 @@ if (globalStore.session.loggedIn) {

<!-- PREVIEW -->
<SitePreview
v-if="globalStore.uiConfig.site_preview"
ref="sitePreview"
v-model="structure"
:structure-data="structureParsedData"
Expand All @@ -409,15 +427,15 @@ if (globalStore.session.loggedIn) {
ref="form"
class="fill-height"
>
<template v-if="!splitTabs">
<template v-if="!splitTabs && (globalStore.uiConfig.data && globalStore.uiConfig.documentation)">
<v-expand-transition group>
<div v-if="globalStore.admin.structure && windowWidth > 900">
<v-tabs v-model="tab" height="44" grow>
<v-tab value="data">
<v-tab v-if="globalStore.uiConfig.data" value="data">
<v-icon icon="mdi-pencil" start />
Data
</v-tab>
<v-tab value="docs">
<v-tab v-if="globalStore.uiConfig.documentation" value="docs">
<v-icon start icon="mdi-book" />
Docs
</v-tab>
Expand All @@ -426,7 +444,7 @@ if (globalStore.session.loggedIn) {
</v-expand-transition>
</template>
<v-tabs-window v-model="tab" class="fill-height" style="flex: 1">
<v-tabs-window-item value="data" class="fill-height">
<v-tabs-window-item v-if="globalStore.uiConfig.data" value="data" class="fill-height">
<DataEditor
ref="dataEditor"
v-model="structure"
Expand All @@ -436,7 +454,7 @@ if (globalStore.session.loggedIn) {
:loading="userDataLoading"
/>
</v-tabs-window-item>
<v-tabs-window-item value="docs">
<v-tabs-window-item v-if="globalStore.uiConfig.documentation" value="docs">
<v-card tile flat>
<v-card-text>
<Docs v-model="structureMd" />
Expand All @@ -448,13 +466,13 @@ if (globalStore.session.loggedIn) {
</v-card>

<v-navigation-drawer
v-if="splitTabs"
v-if="globalStore.uiConfig.data && splitTabs"
:width="layoutSize.data / 2"
location="start"
disable-resize-watcher
disable-route-watcher
>
<template #append>
<template v-if="globalStore.uiConfig.data && globalStore.uiConfig.data_footer" #append>
<v-divider />
<div class="d-flex align-center justify-space-between pl-3" style="height: 4rem">
<ActionBar
Expand All @@ -466,6 +484,7 @@ if (globalStore.session.loggedIn) {
</template>

<DataEditor
v-if="globalStore.uiConfig.data"
ref="dataEditor"
v-model="structure"
:structure-data="structureParsedData"
Expand All @@ -478,7 +497,7 @@ if (globalStore.session.loggedIn) {
<!-- ACTIONS -->
<v-expand-transition>
<v-app-bar
v-if="showActionBar"
v-if="globalStore.uiConfig.data && globalStore.uiConfig.data_footer && showActionBar"
flat
location="bottom"
color="background"
Expand Down
Loading