diff --git a/Jenkinsfile b/Jenkinsfile index 6749c2dfc..1290714e4 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -332,7 +332,7 @@ pipeline { def releaseUrl = "https://github.com/$GITHUB_OWNER/$GITHUB_REPO/releases/tag/$VERSION" // Post to Slack postToSlack('slack-releases-webhook', [[ - 'title': "Realm Studio $VERSION has been released!", + 'title': "Cosmic Realms $VERSION has been released!", 'title_link': releaseUrl, 'text': "Github Release and artifacts are available <${releaseUrl}|here>\n${releaseNotes}", 'mrkdwn_in': ['text'], diff --git a/package.json b/package.json index 0bb3c5b4b..f2b954e19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "realm-studio", - "productName": "Realm Studio", + "productName": "Cosmic Realms", "version": "13.0.2", "description": "A tool for everything Realm!", "author": { @@ -12,7 +12,7 @@ "license": "Apache-2.0", "main": "./build/main.bundle.js", "build": { - "appId": "com.mongodb.realm-studio", + "appId": "foundation.wabi.realm-studio", "directories": { "buildResources": "./resources" }, @@ -72,7 +72,7 @@ }, "protocols": [ { - "name": "Realm Studio", + "name": "Cosmic Realms", "schemes": [ "x-realm-cloud", "x-realm-studio" diff --git a/scripts/mac/notarize.js b/scripts/mac/notarize.js index f7c848546..b605b2c69 100644 --- a/scripts/mac/notarize.js +++ b/scripts/mac/notarize.js @@ -2,8 +2,8 @@ const fs = require("fs"); const path = require("path"); const { notarize } = require("electron-notarize"); -const appBundleId = "com.mongodb.realm-studio"; -const ascProvider = "QX5CR2FTN2"; // Apple: short team name +const appBundleId = "foundation.wabi.realm-studio"; +const ascProvider = "UQ9J5QT9DL"; // Apple: short team name exports.notarizeMacApp = async (context) => { const { APPLE_ID_APP_USERNAME, APPLE_ID_APP_PASSWORD } = process.env; diff --git a/src/main/MainMenu.ts b/src/main/MainMenu.ts index ce2a28031..811d03924 100644 --- a/src/main/MainMenu.ts +++ b/src/main/MainMenu.ts @@ -91,7 +91,7 @@ export const getDefaultMenuTemplate = ( store.toggleShowInternalFeatures(); updateMenu(); }, - }, + }, { role: 'reload', visible: showInternalFeatures }, { role: 'toggleDevTools', visible: showInternalFeatures }, { type: 'separator', visible: showInternalFeatures }, @@ -105,6 +105,17 @@ export const getDefaultMenuTemplate = ( }, }, { type: 'separator' }, + { + label: "Enable Dark Mode", + id: 'toggle-appearance', + type: 'checkbox', + checked: store.shouldShowDarkMode(), + click: () => { + store.toggleDarkMode(); + updateMenu(); + }, + }, + { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, { role: 'zoomOut' }, diff --git a/src/main/Updater.ts b/src/main/Updater.ts index 9b7aca2c0..0b5354b49 100644 --- a/src/main/Updater.ts +++ b/src/main/Updater.ts @@ -216,7 +216,7 @@ export class Updater { dialog.showMessageBoxSync({ type: 'info', message: `A new version of ${appName} is downloaded!`, - detail: `${appName} ${lastestVersion} is downloaded.\nClick "Ok" to quit and restart Realm Studio.`, + detail: `${appName} ${lastestVersion} is downloaded.\nClick "Ok" to quit and restart Cosmic Realms.`, buttons: ['Ok'], defaultId: 0, }) === 0 diff --git a/src/main/WindowManager.ts b/src/main/WindowManager.ts index e44291293..a892401fa 100644 --- a/src/main/WindowManager.ts +++ b/src/main/WindowManager.ts @@ -105,10 +105,10 @@ export class WindowManager { title: app.name, width: 800, height: 600, - vibrancy: 'light', + vibrancy: 'appearance-based', show: false, // This should be the same as the value of the SCSS variable $body-bg - backgroundColor: '#f5f5f9', + backgroundColor: '#00000000', // Accepting the first mouse event, so users dont have to focus windows before clicking them. // This improves the UX by minimizing the clicks needed to complete a task. acceptFirstMouse: true, diff --git a/src/services/schema-export/languages/swift.ts b/src/services/schema-export/languages/swift.ts index c82681fca..edc4c4102 100644 --- a/src/services/schema-export/languages/swift.ts +++ b/src/services/schema-export/languages/swift.ts @@ -38,37 +38,35 @@ export default class SwiftSchemaExporter extends SchemaExporter { } public makeSchema(schema: Realm.ObjectSchema) { - this.appendLine(`class ${schema.name}: Object {`); + this.appendLine(`class ${schema.name}: Object\n{\n`); + + // Primary key + if (schema.primaryKey) { + this.appendLine(' @Persisted(primaryKey: true)'); + this.appendLine(' var ' + schema.primaryKey + ': ObjectId\n'); + } // Properties const indexedProp: INamedObjectSchemaProperty[] = []; filteredProperties(schema.properties).forEach(prop => { - this.appendLine(' ' + this.propertyLine(prop)); + this.appendLine(' ' + this.propertyLine(prop)); if (prop.indexed && prop.name !== schema.primaryKey) { indexedProp.push(prop); } }); - // Primary key - if (schema.primaryKey) { - this.appendLine(''); - this.appendLine(' override static func primaryKey() -> String? {'); - this.appendLine(' return "' + schema.primaryKey + '"'); - this.appendLine(' }'); - } - // Indexed Properties if (indexedProp.length > 0) { this.appendLine(''); this.appendLine( - ' override static func indexedProperties() -> [String] {', + ' override static func indexedProperties() -> [String] {', ); const indexedPropsStr = indexedProp .map(prop => `"${prop.name}"`) .join(', '); - this.appendLine(` return [${indexedPropsStr}]`); - this.appendLine(' }'); + this.appendLine(` return [${indexedPropsStr}]`); + this.appendLine(' }'); } // End class @@ -109,7 +107,7 @@ export default class SwiftSchemaExporter extends SchemaExporter { if (prop.optional) { strArray += '?'; } - return `let ${prop.name} = List<${strArray}>()`; + return `@Persisted\n var ${prop.name} = [${strArray}]()\n`; } const propType = propertyType(prop.type); @@ -121,41 +119,31 @@ export default class SwiftSchemaExporter extends SchemaExporter { case 'int': case 'float': case 'double': - return `let ${prop.name} = RealmOptional<${propType}>()`; - case 'string': case 'data': case 'date': case 'objectId': case 'decimal128': - return `@objc dynamic var ${prop.name}: ${propType}? = nil`; - case 'object': - return `@objc dynamic var ${prop.name}: ${prop.objectType}?`; + return `@Persisted\n var ${prop.name}: ${propType}?\n`; default: return `ERROR - unknown type '${prop.type}'`; } } // Non Optional types - const str = `@objc dynamic var ${prop.name}: ${propType} = `; + const str = `@Persisted\n var ${prop.name}: ${propType}\n`; switch (prop.type) { case 'bool': - return str + 'false'; case 'int': case 'float': case 'double': - return str + '0'; case 'string': - return str + '""'; case 'data': - return str + 'Data()'; case 'date': - return str + 'Date()'; case 'objectId': - return str + 'ObjectId()'; case 'decimal128': - return str + 'Decimal128()'; + return str; case 'object': return 'Objects must always be optional. Something is not right in this model!'; } diff --git a/src/store.ts b/src/store.ts index 74abad24f..c9f316311 100644 --- a/src/store.ts +++ b/src/store.ts @@ -27,17 +27,20 @@ import { WindowType } from './windows/WindowOptions'; type RemovalCallback = () => void; const KEY_SHOW_SYSTEM_CLASSES = 'browser.show-system-classes'; +const KEY_SHOW_DARK_MODE = 'browser.show-dark-mode'; const KEY_SHOW_INTERNAL_FEATURES = 'general.show-internal-features'; const KEY_WINDOW_OPTIONS = 'window-options'; type StudioStore = { [KEY_SHOW_SYSTEM_CLASSES]: boolean; + [KEY_SHOW_DARK_MODE]: boolean; [KEY_SHOW_INTERNAL_FEATURES]: boolean; [key: string]: unknown; }; class RealmStudioStore { public readonly KEY_SHOW_SYSTEM_CLASSES = KEY_SHOW_SYSTEM_CLASSES; + public readonly KEY_SHOW_DARK_MODE = KEY_SHOW_DARK_MODE; public readonly KEY_SHOW_INTERNAL_FEATURES = KEY_SHOW_INTERNAL_FEATURES; public readonly KEY_WINDOW_OPTIONS = KEY_WINDOW_OPTIONS; @@ -48,6 +51,12 @@ class RealmStudioStore { this.store.set(KEY_SHOW_SYSTEM_CLASSES, !currentValue); } + public toggleDarkMode() + { + const currentValue = this.shouldShowInternalFeatures(); + this.store.set(KEY_SHOW_DARK_MODE, !currentValue); + } + public toggleShowInternalFeatures() { const currentValue = this.shouldShowInternalFeatures(); this.store.set(KEY_SHOW_INTERNAL_FEATURES, !currentValue); @@ -57,6 +66,10 @@ class RealmStudioStore { return this.store.get(KEY_SHOW_SYSTEM_CLASSES, false); } + public shouldShowDarkMode(): boolean { + return this.store.get(KEY_SHOW_DARK_MODE, false); + } + public shouldShowInternalFeatures(): boolean { return this.store.get(KEY_SHOW_INTERNAL_FEATURES, false); } diff --git a/src/testing/post-packaging/index.ts b/src/testing/post-packaging/index.ts index 6c67db072..3cab38ad8 100644 --- a/src/testing/post-packaging/index.ts +++ b/src/testing/post-packaging/index.ts @@ -116,7 +116,7 @@ assert( assert.strictEqual(typeof productName, 'string', 'Expected a product name'); -describe('Realm Studio packaged', () => { +describe('Cosmic Realms packaged', () => { let mockedS3: http.Server; let appProcess: cp.ChildProcess; let temporaryMacPath: string; @@ -130,7 +130,7 @@ describe('Realm Studio packaged', () => { buildMockedRealmStudio(); // Copy the current dist/mac folder to a different location to prevent the auto updater // from overriding the current dist/mac folder. - const originalMacPath = path.resolve(distPath, 'mac'); + const originalMacPath = path.resolve(distPath, 'mac-arm64'); temporaryMacPath = fs.mkdtempSync(originalMacPath + '-auto-update-test-'); console.log( 'Making a copy of the mac app from', diff --git a/src/testing/post-packaging/mocked-realm-studio/index.js b/src/testing/post-packaging/mocked-realm-studio/index.js index dfa6bdf2f..0b803e9bb 100644 --- a/src/testing/post-packaging/mocked-realm-studio/index.js +++ b/src/testing/post-packaging/mocked-realm-studio/index.js @@ -12,7 +12,7 @@ electron.app.once('ready', () => { message: `Writing to the ready signal: ${p}`, }); */ - fs.writeFileSync(p, 'Hello from a future Realm Studio!', { + fs.writeFileSync(p, 'Hello from a future Cosmic Realms!', { encoding: 'utf8', }); // Exit ... diff --git a/src/testing/post-packaging/mocked-realm-studio/package-lock.json b/src/testing/post-packaging/mocked-realm-studio/package-lock.json index c0a3c5b78..e63808653 100644 --- a/src/testing/post-packaging/mocked-realm-studio/package-lock.json +++ b/src/testing/post-packaging/mocked-realm-studio/package-lock.json @@ -1,13 +1,38 @@ { "name": "mocked-realm-studio", "version": "999.0.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "electron": { - "version": "file:../../../../node_modules/electron", + "packages": { + "": { + "name": "mocked-realm-studio", + "version": "999.0.0", + "license": "Apache-2.0", + "devDependencies": { + "electron": "file:../../../../node_modules/electron" + } + }, + "../../../../node_modules/electron": { + "version": "19.1.8", "integrity": "sha512-Bp1CwnYaIWXNL9ZjgEaLlEkVEGpjJMupcAnxyCe00C2ZhQT9gY+RJaPzkrZC+J/Gc4MvvLtJcy/Hvsc+MTkfNg==", - "dev": true + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^1.14.1", + "@types/node": "^16.11.26", + "extract-zip": "^1.0.3" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 8.6" + } + }, + "node_modules/electron": { + "resolved": "../../../../node_modules/electron", + "link": true } } } diff --git a/src/testing/post-packaging/mocked-realm-studio/package.json b/src/testing/post-packaging/mocked-realm-studio/package.json index f29cc6dd2..a52235f77 100644 --- a/src/testing/post-packaging/mocked-realm-studio/package.json +++ b/src/testing/post-packaging/mocked-realm-studio/package.json @@ -10,8 +10,8 @@ }, "license": "Apache-2.0", "build": { - "appId": "com.mongodb.realm-studio", - "productName": "Realm Studio", + "appId": "foundation.wabi.realm-studio", + "productName": "Cosmic Realms", "mac": { "target": [ "zip" diff --git a/src/ui/Greeting/Greeting.scss b/src/ui/Greeting/Greeting.scss index fd3bcdd95..9f06cdde0 100644 --- a/src/ui/Greeting/Greeting.scss +++ b/src/ui/Greeting/Greeting.scss @@ -31,8 +31,12 @@ $history-panel-icon-size: 20px; } &__ActionsPanel { + @include themed() { + border: 1px solid mix(t("elephant"), t("dove"), 25%); + background-color: t("base"); + background: t("base"); + } align-items: center; - background: $window-background; display: flex; flex-basis: 60%; flex-direction: column; @@ -112,13 +116,17 @@ $history-panel-icon-size: 20px; } &__HistoryPanel { - background: $charcoal; - color: $dove; + @include themed() { + background: t("charcoal"); + color: t("dove"); + } flex-grow: 1; font-size: .9rem; a { - color: $dove; + @include themed() { + color: t("dove"); + } } &__Entry { @@ -162,9 +170,11 @@ $history-panel-icon-size: 20px; } &__CloudOverlay { - background: $overlay-background; + @include themed() { + color: t("dove"); + background: rgba(t("charcoal"), .6); + } bottom: 0; - color: $dove; display: flex; flex-direction: column; left: 0; diff --git a/src/ui/Greeting/MarketingPanel/MarketingPanel.scss b/src/ui/Greeting/MarketingPanel/MarketingPanel.scss index e00c9f952..d1425efaa 100644 --- a/src/ui/Greeting/MarketingPanel/MarketingPanel.scss +++ b/src/ui/Greeting/MarketingPanel/MarketingPanel.scss @@ -18,16 +18,17 @@ @import "~realm-studio-styles/variables"; -$content-background: rgba($charcoal, .6); -$hr-color: rgba($dove, .33); - .MarketingPanel { - background: $charcoal; - color: $white; + @include themed() { + background: t("charcoal"); + color: t("text"); + } position: relative; &__PreviewToggle { - background: $content-background; + @include themed() { + background: rgba(t("charcoal"), .6); + } bottom: - $spacer / 2; font-size: .8rem; padding: $spacer / 4; @@ -55,7 +56,9 @@ $hr-color: rgba($dove, .33); &__MessageContent { // Tumbleweed - background: $content-background; + @include themed() { + background: rgba(t("charcoal"), .6); + } font-size: .8rem; overflow: auto; padding: $spacer; @@ -91,16 +94,22 @@ $hr-color: rgba($dove, .33); } a { - color: $white; + @include themed() { + color: t("text"); + } text-decoration: underline; } code { - color: $white; + @include themed() { + color: t("text"); + } } blockquote { - border-left: ($spacer / 8) solid $dove; + @include themed() { + border-left: ($spacer / 8) solid t("dove"); + } padding-left: $spacer / 2; } @@ -121,7 +130,9 @@ $hr-color: rgba($dove, .33); } hr { - border-color: $hr-color; + @include themed() { + background: rgba(t("dove"), .33); + } } } diff --git a/src/ui/RealmBrowser/Content/CreateObjectDialog/CreateObjectDialog.scss b/src/ui/RealmBrowser/Content/CreateObjectDialog/CreateObjectDialog.scss index f39d7dd26..6d7bc7f35 100644 --- a/src/ui/RealmBrowser/Content/CreateObjectDialog/CreateObjectDialog.scss +++ b/src/ui/RealmBrowser/Content/CreateObjectDialog/CreateObjectDialog.scss @@ -19,8 +19,14 @@ @import "~realm-studio-styles/variables"; .CreateObjectDialog { + @include themed() { + background: t("base") !important; + } &__PropertyRow { &__Label { + @include themed() { + background: t("base") !important; + } width: 100%; } @@ -43,10 +49,15 @@ } &__Display { + @include themed() { + background: t("base") !important; + } font-size: .8rem; &--null { - color: $elephant; + @include themed() { + color: t("text"); + } font-style: italic; } } @@ -91,13 +102,18 @@ } &__ListControl { + @include themed() { + background: t("base") !important; + } $list-control-gutter: $spacer / 2; - background: $window-background; border: $input-border-width solid $input-border-color; border-radius: $input-border-radius; padding: $input-padding-y $input-padding-x; &__Item { + @include themed() { + background: t("base") !important; + } display: inline-block; padding-bottom: $list-control-gutter; width: 100%; diff --git a/src/ui/RealmBrowser/Content/PermissionSidebar/RoleDialog/RoleDialog.scss b/src/ui/RealmBrowser/Content/PermissionSidebar/RoleDialog/RoleDialog.scss index 7febb343c..35742e630 100644 --- a/src/ui/RealmBrowser/Content/PermissionSidebar/RoleDialog/RoleDialog.scss +++ b/src/ui/RealmBrowser/Content/PermissionSidebar/RoleDialog/RoleDialog.scss @@ -37,8 +37,10 @@ } &__UserRow { + @include themed() { + border: 1px solid t("charcoal"); + } align-items: center; - border: 1px solid $cell-border-color; border-bottom-width: 0; display: flex; font-size: $font-size-sm; diff --git a/src/ui/RealmBrowser/LeftSidebar/LeftSidebar.scss b/src/ui/RealmBrowser/LeftSidebar/LeftSidebar.scss index 07f88b121..8ecb1b1d0 100644 --- a/src/ui/RealmBrowser/LeftSidebar/LeftSidebar.scss +++ b/src/ui/RealmBrowser/LeftSidebar/LeftSidebar.scss @@ -19,28 +19,35 @@ @import "~realm-studio-styles/variables"; .LeftSidebar { + @include themed() { + color: t("text"); + } display: flex; flex-direction: column; - padding: $spacer / 2; padding-bottom: 0; &__Header { + @include themed() { + background: t("indigo"); + border-bottom: 8px solid t("grape-jelly"); + color: t("elephant"); + } + padding: $spacer / 2; align-items: center; - border-bottom: 1px solid $dove; - color: $elephant; display: flex; flex-basis: 2.5rem; flex-shrink: 0; - font-size: .9rem; + font-size: 1.08rem; font-weight: bold; justify-content: space-between; margin-bottom: $spacer / 2; - padding-bottom: $spacer / 2; + padding-top: $spacer; + padding-bottom: $spacer; padding-left: $spacer; - text-transform: uppercase; } &__Classes { + padding: $spacer / 2; flex-grow: 1; margin: 0 (-$spacer / 2); overflow-x: hidden; @@ -56,7 +63,9 @@ justify-content: flex-start; &::before { - color: $elephant; + @include themed() { + color: t("indigo"); + } content: "This Realm has no classes defined"; padding: $spacer; text-align: center; @@ -87,18 +96,24 @@ &:hover, &:focus { - background: $secondary; + @include themed() { + background: t("charcoal"); + } } &--selected { - background: $secondary; + @include themed() { + background: t("charcoal"); + } } &--highlighted { cursor: inherit; &::before { - background: $primary; + @include themed() { + background: t("indigo"); + } border-radius: 2px; bottom: 5px; content: ""; @@ -112,7 +127,9 @@ } &__List { - background: $secondary; + @include themed() { + background: t("charcoal"); + } // box-shadow: inset 0 0 .4rem $realm-browser-list-box-shadow-color; padding: .75 * $spacer; padding-left: 1.5 * $spacer; @@ -149,7 +166,9 @@ } &::before { - background: $primary; + @include themed() { + background: t("indigo"); + } border-radius: 2px; bottom: 5px; content: ""; @@ -162,7 +181,9 @@ &__HiddenClassesHint, &__ReadOnlyHint { - color: $elephant; + @include themed() { + color: t("indigo"); + } font-size: .75rem; margin: $spacer / 2; overflow: hidden; diff --git a/src/ui/RealmBrowser/RealmBrowser.scss b/src/ui/RealmBrowser/RealmBrowser.scss index 75f8ff08f..c74848b7f 100644 --- a/src/ui/RealmBrowser/RealmBrowser.scss +++ b/src/ui/RealmBrowser/RealmBrowser.scss @@ -22,7 +22,6 @@ .RealmBrowser { display: flex; height: 100%; - &__Table__HeaderGrid, &__Topbar { z-index: 1; // Overlay when drag-reordering elements in lists @@ -55,8 +54,10 @@ } &__Topbar { + @include themed() { + background: t("base"); + } align-items: center; - background: $window-background; display: flex; padding: $spacer / 2; @@ -82,12 +83,16 @@ } &__Table { - background: $white; + @include themed() { + background: t("base"); + } flex: 1 0 0; position: relative; &__HeaderGrid { - background: $white; + @include themed() { + background: t("base"); + } } &__AddColumnControl { @@ -131,12 +136,16 @@ transition: background-color 200ms; &--striped { - background: $row-stripe; + @include themed() { + background: t("elephant"); + } } &--sorting { - background: mix($row-stripe, $white, 40%); - border-top: 1px solid $dove; + @include themed() { + border-top: 1px solid t("indigo"); + background: t("elephant"); + } margin-top: -1px; transition: transform 300ms; user-select: none; @@ -159,8 +168,10 @@ &__HeaderCell, &__Cell { - border-bottom: 1px solid $cell-border-color; - border-right: 1px solid $cell-border-color; + @include themed() { + border-bottom: 1px solid t("charcoal"); + border-right: 1px solid t("charcoal"); + } padding: 0; position: relative; @@ -206,14 +217,18 @@ &--primitive { &::before { - color: $elephant; + @include themed() { + color: t("indigo"); + } content: "primitive"; } } } &__HeaderType { - color: $elephant; + @include themed() { + color: t("text"); + } font-size: $font-size-sm; font-weight: normal; overflow: hidden; @@ -226,12 +241,16 @@ } &__HeaderSort { - color: $elephant; + @include themed() { + color: t("text"); + } flex-shrink: 0; font-size: 12px; &--active { - color: $charcoal; + @include themed() { + color: t("indigo"); + } } } @@ -305,7 +324,9 @@ &__StringCell, &__DataCell { &--null { - color: $elephant; + @include themed() { + color: t("text"); + } cursor: inherit; display: block; font-style: italic; @@ -314,7 +335,9 @@ &__MixedCell { &--disabled { - color: $elephant; + @include themed() { + color: t("text"); + } } } @@ -327,11 +350,15 @@ padding: $cell-padding-y $cell-padding-x; &--null { - color: $elephant; + @include themed() { + color: t("text"); + } } &--disabled { - color: $elephant; + @include themed() { + color: t("text"); + } } &--int { @@ -446,19 +473,25 @@ justify-content: center; &::before { - color: $elephant; + @include themed() { + color: t("text"); + } content: "No schema selected"; } } &__PermissionSidebar { - border-top: 1px solid $dove; + @include themed() { + border-top: 1px solid t("indigo"); + } } &__Bottombar { + @include themed() { + background: t("dove"); + color: t("dove"); + } align-items: center; - background: $ultramarine; - color: $dove; display: flex; height: 0; justify-content: space-between; diff --git a/src/ui/RealmBrowser/RealmBrowser.tsx b/src/ui/RealmBrowser/RealmBrowser.tsx index a53943c38..73ee5f3e8 100644 --- a/src/ui/RealmBrowser/RealmBrowser.tsx +++ b/src/ui/RealmBrowser/RealmBrowser.tsx @@ -48,6 +48,7 @@ export interface IRealmBrowserProps { createObjectSchema?: Realm.ObjectSchema; dataVersion: number; dataVersionAtBeginning?: number; + darkModeEnabled: boolean; allowCreate: boolean; editMode: EditMode; focus: Focus | null; @@ -94,6 +95,7 @@ export const RealmBrowser = ({ focus, getClassFocus, getSchemaLength, + darkModeEnabled, importDialog, isAddClassOpen, isAddPropertyOpen, @@ -124,7 +126,7 @@ export const RealmBrowser = ({ isEmbeddedType, }: IRealmBrowserProps) => { return ( -
+
{ + this.changeTheme(); + }, + }; + return menu.performModifications(template, [ { action: 'append', @@ -335,6 +351,11 @@ class RealmBrowserContainer id: 'select-all', items: [{ type: 'separator' }, ...transactionMenuItems, editModeMenu], }, + { + action: 'replace', + id: 'toggle-appearance', + items: [darkModeMenu, { type: 'separator' }], + }, ]); } @@ -400,7 +421,7 @@ class RealmBrowserContainer } } else if (err.message === ARCHITECTURE_MISMATCH_MESSAGE) { const improvedError = new Error( - 'The file is already opened by another process, with an incompatible lock file format. Try up- or downgrading Realm Studio or SDK to match their versions of Realm Core.\n\nSee Realm Studio changelog on GitHub for details on compatibility between versions.', + 'The file is already opened by another process, with an incompatible lock file format. Try up- or downgrading Cosmic Realms or SDK to match their versions of Realm Core.\n\nSee Cosmic Realms changelog on GitHub for details on compatibility between versions.', ); showError('Failed to open Realm', improvedError); window.close(); diff --git a/src/ui/RealmBrowser/variables.scss b/src/ui/RealmBrowser/variables.scss index a7755a532..ad3d51c1c 100644 --- a/src/ui/RealmBrowser/variables.scss +++ b/src/ui/RealmBrowser/variables.scss @@ -22,7 +22,7 @@ $realm-browser-header-handle-width: 5px; $realm-browser-header-height: 50px; $realm-browser-header-icon-space: 24px; $realm-browser-header-handle-hover-bg: rgba(0, 0, 0, .1); -$realm-browser-header-handle-dragging-bg: rgba($ultramarine, .5); +$realm-browser-header-handle-dragging-bg: rgba(#39477f, .5); $realm-browser-more-indicator-size: $spacer; $realm-browser-more-indicator-dark-color: rgba(0, 0, 0, .1); diff --git a/src/ui/reusable/LoadingOverlay/LoadingOverlay.scss b/src/ui/reusable/LoadingOverlay/LoadingOverlay.scss index 44e89115d..8912e7b0b 100644 --- a/src/ui/reusable/LoadingOverlay/LoadingOverlay.scss +++ b/src/ui/reusable/LoadingOverlay/LoadingOverlay.scss @@ -29,12 +29,14 @@ } .LoadingOverlay { + @include themed() { + background: rgba(t("charcoal"), .6); + } align-items: center; animation-delay: 0s; animation-duration: .33s; animation-fill-mode: forwards; animation-name: fade; - background: $overlay-background; bottom: 0; left: 0; opacity: 0; @@ -52,8 +54,10 @@ } &__Content { + @include themed() { + color: t("dove"); + } align-items: center; - color: $dove; display: flex; flex-direction: column; font-size: .9rem; @@ -89,7 +93,9 @@ } &__Details { - color: $dove; + @include themed() { + color: t("dove"); + } overflow: auto; text-align: left; width: 100%; diff --git a/src/ui/reusable/ReactVirtualized.scss b/src/ui/reusable/ReactVirtualized.scss index 0acddd30a..9dd1fe24a 100644 --- a/src/ui/reusable/ReactVirtualized.scss +++ b/src/ui/reusable/ReactVirtualized.scss @@ -27,11 +27,15 @@ } &__headerRow { - border-bottom: 2px solid $dove; + @include themed() { + border-bottom: 2px solid t("dove"); + } } &__row { - border-bottom: 1px solid $dove; + @include themed() { + border-bottom: 1px solid t("dove"); + } &:focus { // Disabling the default focus outline diff --git a/src/ui/reusable/Sidebar/Sidebar.scss b/src/ui/reusable/Sidebar/Sidebar.scss index 55e666b27..c0e5962f6 100644 --- a/src/ui/reusable/Sidebar/Sidebar.scss +++ b/src/ui/reusable/Sidebar/Sidebar.scss @@ -20,17 +20,23 @@ @import "./variables"; .Sidebar { - background: $sidebar-background; + @include themed() { + background: t("charcoal"); + } position: relative; transition: flex-basis $sidebar-transition-duration; z-index: 6; &--left { - border-right: 1px solid $sidebar-border-color; + @include themed() { + border-right: 1px solid t("charcoal"); + } } &--right { - border-left: 1px solid $sidebar-border-color; + @include themed() { + border-left: 1px solid t("charcoal"); + } } &--closed { @@ -91,10 +97,12 @@ } &__ToggleButton { + @include themed() { + color: t("text"); + } align-items: center; border-radius: $border-radius-lg; bottom: 1rem; - color: $elephant; cursor: pointer; // Default is not to display the toggle button, unless it's --visible display: none; @@ -113,8 +121,10 @@ } &::before { - background-color: $sidebar-background; - border: 1px solid $sidebar-border-color; + @include themed() { + border: 1px solid t("charcoal"); + background-color: t("charcoal"); + } border-radius: $border-radius-lg; box-sizing: content-box; content: ""; @@ -168,7 +178,9 @@ } &:hover { - color: $charcoal; + @include themed() { + color: t("text"); + } } } @@ -206,7 +218,9 @@ } &__EmptyExplanation { - color: $elephant; + @include themed() { + color: t("elephant"); + } font-size: .9rem; text-align: center; } diff --git a/src/ui/reusable/Sidebar/variables.scss b/src/ui/reusable/Sidebar/variables.scss index 2f0d647e7..52a117d1d 100644 --- a/src/ui/reusable/Sidebar/variables.scss +++ b/src/ui/reusable/Sidebar/variables.scss @@ -27,6 +27,4 @@ $toggle-button-overhang: $toggle-button-width / 2; $sidebar-shadow: $raised-shadow-color; $sidebar-shadow-hover: rgba($sidebar-shadow, .2); $sidebar-transition-duration: .3s; -$sidebar-background: $window-background; -$sidebar-border-color: mix($elephant, $dove, 25%); $sidebar-closed-width: $toggle-button-width / 2; diff --git a/src/windows/SentryErrorBoundary/ErrorOverlay.scss b/src/windows/SentryErrorBoundary/ErrorOverlay.scss index 14c7980d3..9b6b49ea8 100644 --- a/src/windows/SentryErrorBoundary/ErrorOverlay.scss +++ b/src/windows/SentryErrorBoundary/ErrorOverlay.scss @@ -19,7 +19,9 @@ @import "~realm-studio-styles/variables"; .ErrorOverlay { - background: $window-background; + @include themed() { + background: t("base"); + } display: flex; flex-direction: column; height: 100%; @@ -31,7 +33,9 @@ &__Introduction, &__Id, &__IdExplanation { - color: $charcoal; + @include themed() { + color: t("charcoal"); + } margin: 0; padding: $spacer / 2; text-align: center; @@ -52,7 +56,9 @@ } &__Stack { - color: $elephant; + @include themed() { + color: t("elephant"); + } font-size: 8px; overflow-y: auto; padding: $spacer; diff --git a/static/index.development.html b/static/index.development.html index 5c8abc9f7..beed0a391 100644 --- a/static/index.development.html +++ b/static/index.development.html @@ -2,7 +2,7 @@ - Realm Studio + Cosmic Realms diff --git a/static/index.html b/static/index.html index 30ab81747..54c10cfa8 100755 --- a/static/index.html +++ b/static/index.html @@ -2,7 +2,7 @@ - Realm Studio + Cosmic Realms diff --git a/styles/index.scss b/styles/index.scss index 7cc0ad5f7..33834b164 100644 --- a/styles/index.scss +++ b/styles/index.scss @@ -35,11 +35,22 @@ html { html, body, #app { + @include themed() { + background: t('base') !important; + } height: 100%; } +.modal-content { + @include themed() { + background-color: t('base') !important; + } +} + .Link { - color: $primary; + @include themed() { + color: t('indigo'); + } cursor: pointer; text-decoration: underline; } diff --git a/styles/variables/_colors.scss b/styles/variables/_colors.scss index 87fe9c5f8..9018597be 100644 --- a/styles/variables/_colors.scss +++ b/styles/variables/_colors.scss @@ -17,43 +17,112 @@ //////////////////////////////////////////////////////////////////////////// // Realm theme colors -$melon: #fcc397; -$peach: #fc9f95; -$sexy-salmon: #f77c88; -$flamingo: #f25192; -$mulberry: #d34ca3; -$grape-jelly: #9a50a5; -$indigo: #59569e; -$ultramarine: #39477f; -$charcoal: #1c233f; -$elephant: #9a9ba5; -$dove: #ebebf2; +$base--light: #ffffff; +$melon--light: #fcc397; +$peach--light: #fc9f95; +$sexy-salmon--light: #f77c88; +$flamingo--light: #f25192; +$mulberry--light: #d34ca3; +$grape-jelly--light: #A85FEA; +$indigo--light: #2B664C; +$ultramarine--light: #39477f; +$charcoal--light: #FAFBFA; +$elephant--light: #9a9ba5; +$dove--light: #ebebf2; +$text--light: #000000; + +$base--dark: #071E2A; +$melon--dark: #fcc397; +$peach--dark: #fc9f95; +$sexy-salmon--dark: #f77c88; +$flamingo--dark: #f25192; +$mulberry--dark: #d34ca3; +$grape-jelly--dark: #A85FEA; +$indigo--dark: #71F6BA; +$ultramarine--dark: #39477f; +$charcoal--dark: #162632; +$elephant--dark: #000007; +$dove--dark: #59569e; +$text--dark: #ffffff; // The default bootstrap colors will be merged into this map $colors: ( - "melon": $melon, - "peach": $peach, - "sexy-salmon": $sexy-salmon, - "flamingo": $flamingo, - "mulberry": $mulberry, - "grape-jelly": $grape-jelly, - "indigo": $indigo, - "ultramarine": $ultramarine, - "charcoal": $charcoal, - "elephant": $elephant, - "dove": $dove, + "base": $base--light, + "melon": $melon--light, + "peach": $peach--light, + "sexy-salmon": $sexy-salmon--light, + "flamingo": $flamingo--light, + "mulberry": $mulberry--light, + "grape-jelly": $grape-jelly--light, + "indigo": $indigo--light, + "ultramarine": $ultramarine--light, + "charcoal": $charcoal--light, + "elephant": $elephant--light, + "dove": $dove--light, + "text": $text--light +); + +$themes: ( + default: ( + "base": $base--light, + "melon": $melon--light, + "peach": $peach--light, + "sexy-salmon": $sexy-salmon--light, + "flamingo": $flamingo--light, + "mulberry": $mulberry--light, + "grape-jelly": $grape-jelly--light, + "indigo": $indigo--light, + "ultramarine": $ultramarine--light, + "charcoal": $charcoal--light, + "elephant": $elephant--light, + "dove": $dove--light, + "text": $text--light + ), + dark: ( + "base": $base--dark, + "melon": $melon--dark, + "peach": $peach--dark, + "sexy-salmon": $sexy-salmon--dark, + "flamingo": $flamingo--dark, + "mulberry": $mulberry--dark, + "grape-jelly": $grape-jelly--dark, + "indigo": $indigo--dark, + "ultramarine": $ultramarine--dark, + "charcoal": $charcoal--dark, + "elephant": $elephant--dark, + "dove": $dove--dark, + "text": $text--dark + ), ); +@mixin themed() { + @each $theme, $map in $themes { + .theme--#{$theme} & { + $colors: () !global; + @each $key, $submap in $map { + $value: map-get(map-get($themes, $theme), '#{$key}'); + $colors: map-merge($colors, ($key: $value)) !global; + } + @content; + $colors: null !global; + } + } +} + +@function t($key) { + @return map-get($colors, $key); +} + // Override bootstrap colors -$primary: $ultramarine; -$secondary: mix($dove, $elephant, 90%); -$danger: $sexy-salmon; -$info: $ultramarine; +$primary: t("ultramarine"); +$secondary: mix(t("dove"), t("elephant"), 90%); +$danger: t("sexy-salmon"); +$info: t("ultramarine"); -$input-placeholder-color: rgba($elephant, .6); +$input-placeholder-color: rgba(t("elephant"), .6); -$window-background: mix(#fff, $dove, 50%); -$overlay-background: rgba($charcoal, .6); +$window-background: t("base"); +$overlay-background: rgba(t("charcoal"), .6); $body-bg: $window-background;