From 1143ed721960042b01d1024dc453bbab0ccddb99 Mon Sep 17 00:00:00 2001 From: Brock Whittaker Date: Fri, 2 Dec 2016 16:12:52 -0800 Subject: [PATCH] redesign: Change /#settings and /#administration to an overlay. This also adds a box-shadow to the #deactivate_self_modal so that it looks similar to the old backdrop. --- frontend_tests/casper_tests/06-settings.js | 7 +- frontend_tests/casper_tests/09-navigation.js | 8 +- frontend_tests/casper_tests/10-admin.js | 17 +- .../casper_tests/12-toggle-message-editing.js | 8 +- .../casper_tests/13-user-deactivation.js | 18 +- static/js/admin.js | 37 ++- static/js/click_handlers.js | 55 +++- static/js/gear_menu.js | 6 - static/js/hashchange.js | 70 ++++- static/js/hotkey.js | 45 ++- static/js/settings.js | 36 ++- static/styles/settings.css | 262 ++++++++++++++++++ static/styles/zulip.css | 5 - static/templates/admin_tab.handlebars | 76 ++--- static/templates/settings_tab.handlebars | 2 - .../subscription_table_body.handlebars | 2 +- static/third/bootstrap/css/bootstrap.css | 2 +- templates/zerver/index.html | 3 + templates/zerver/navbar.html | 4 +- templates/zerver/settings_overlay.html | 100 +++++++ tools/lib/find_add_class.py | 2 + zerver/tests/test_templates.py | 1 + 22 files changed, 644 insertions(+), 122 deletions(-) create mode 100644 templates/zerver/settings_overlay.html diff --git a/frontend_tests/casper_tests/06-settings.js b/frontend_tests/casper_tests/06-settings.js index 20fa172cc8..80073fad8b 100644 --- a/frontend_tests/casper_tests/06-settings.js +++ b/frontend_tests/casper_tests/06-settings.js @@ -22,9 +22,9 @@ casper.then(function () { }); casper.then(function () { - casper.waitUntilVisible("#settings-change-box", function () { + casper.waitUntilVisible("#settings_content .account-settings-form", function () { casper.test.assertUrlMatch(/^http:\/\/[^/]+\/#settings/, 'URL suggests we are on settings page'); - casper.test.assertExists('#settings.tab-pane.active', 'Settings page is active'); + casper.test.assertVisible('.account-settings-form', 'Settings page is active'); casper.test.assertNotVisible("#pw_change_controls"); @@ -56,6 +56,7 @@ casper.then(function () { casper.waitUntilVisible('#settings-status', function () { casper.test.assertSelectorHasText('#settings-status', 'Updated settings!'); + casper.click('[data-section="your-bots"]'); casper.click('#api_key_button'); }); }); @@ -196,6 +197,7 @@ casper.waitForSelector('#create_alert_word_form', function () { casper.then(function change_default_language() { casper.test.info('Changing the default language'); + casper.click('[data-section="display-settings"]'); casper.waitForSelector('#default_language'); }); @@ -236,6 +238,7 @@ casper.waitForSelector("#settings-change-box", function check_url_preference() { return document.documentElement.lang; }, 'de'); casper.test.info("English is now the default language"); + casper.click('[data-section="display-settings"]'); }); casper.thenClick('#default_language'); diff --git a/frontend_tests/casper_tests/09-navigation.js b/frontend_tests/casper_tests/09-navigation.js index f33e71e62e..d10e167ccd 100644 --- a/frontend_tests/casper_tests/09-navigation.js +++ b/frontend_tests/casper_tests/09-navigation.js @@ -17,7 +17,7 @@ function wait_for_tab(tab) { function then_navigate_to(click_target, tab) { casper.then(function () { casper.test.info('Visiting #' + click_target); - casper.click('a[href^="#' + click_target + '"]'); + casper.click("a[href='#" + click_target + "']"); wait_for_tab(tab); }); } @@ -30,7 +30,10 @@ function then_navigate_to_settings() { casper.click(menu_selector); casper.waitUntilVisible('a[href^="#settings"]', function () { casper.click('a[href^="#settings"]'); - wait_for_tab('settings'); + casper.waitForSelector('#settings_page', function () { + casper.test.assertExists('#settings_page', "Settings page is active"); + casper.click("#settings_page .exit"); + }); }); }); }); @@ -53,7 +56,6 @@ function then_navigate_to_subscriptions() { // Take a navigation tour of the app. // Entries are (click target, tab that should be active after clicking). - then_navigate_to_settings(); then_navigate_to('narrow/stream/Verona', 'home'); then_navigate_to('home', 'home'); diff --git a/frontend_tests/casper_tests/10-admin.js b/frontend_tests/casper_tests/10-admin.js index 99722bfe4d..8b39a2cc1c 100644 --- a/frontend_tests/casper_tests/10-admin.js +++ b/frontend_tests/casper_tests/10-admin.js @@ -14,7 +14,7 @@ casper.then(function () { casper.click('a[href^="#administration"]'); }); -casper.waitForSelector('#administration.tab-pane.active', function () { +casper.waitForSelector('#settings_overlay_container.show', function () { casper.test.info('Administration page is active'); casper.test.assertUrlMatch(/^http:\/\/[^/]+\/#administration/, 'URL suggests we are on administration page'); }); @@ -23,7 +23,6 @@ casper.waitForSelector('#administration.tab-pane.active', function () { casper.waitForSelector('input[type="checkbox"][id="id_realm_create_stream_by_admins_only"]', function () { casper.click('input[type="checkbox"][id="id_realm_create_stream_by_admins_only"]'); casper.click('form.admin-realm-form input.button'); - }); casper.then(function () { @@ -64,14 +63,15 @@ casper.then(function () { }); }); + casper.then(function () { // Test custom realm emoji + casper.click("li[data-section='emoji-settings']"); casper.waitForSelector('.admin-emoji-form', function () { casper.fill('form.admin-emoji-form', { name: 'MouseFace', url: 'http://zulipdev.com:9991/static/images/integrations/logos/jenkins.png', - }); - casper.click('form.admin-emoji-form input.button'); + }, true); }); }); @@ -97,6 +97,7 @@ casper.then(function () { // Test custom realm filters casper.then(function () { + casper.click("li[data-section='filter-settings']"); casper.waitForSelector('.admin-filter-form', function () { casper.fill('form.admin-filter-form', { pattern: '#(?P[0-9]+)', @@ -168,10 +169,7 @@ function select_from_suggestions(item) { // Test default stream creation and addition casper.then(function () { - casper.click('#settings-dropdown'); - casper.click('a[href^="#subscriptions"]'); - casper.click('#settings-dropdown'); - casper.click('a[href^="#administration"]'); + casper.click("li[data-section='default-streams-list']"); casper.waitUntilVisible(".create_default_stream", function () { // It matches with all the stream names which has 'O' as a substring (Rome, Scotland, Verona // etc). 'O' is used to make sure that it works even if there are multiple suggestions. @@ -201,9 +199,11 @@ casper.then(function () { }); }); + // TODO: Test stream deletion casper.then(function () { + casper.click("li[data-section='organization-settings']"); casper.waitUntilVisible('#id_realm_default_language', function () { casper.test.info("Changing realm default language"); casper.evaluate(function () { @@ -222,6 +222,7 @@ casper.then(function () { // Test authentication methods setting casper.then(function () { + casper.click("li[data-section='auth-methods']"); casper.waitForSelector(".method_row[data-method='Email'] input[type='checkbox']", function () { casper.click(".method_row[data-method='Email'] input[type='checkbox']"); casper.click('form.admin-realm-form input.button'); diff --git a/frontend_tests/casper_tests/12-toggle-message-editing.js b/frontend_tests/casper_tests/12-toggle-message-editing.js index f31127cd98..917627a9cf 100644 --- a/frontend_tests/casper_tests/12-toggle-message-editing.js +++ b/frontend_tests/casper_tests/12-toggle-message-editing.js @@ -96,7 +96,7 @@ casper.then(function () { // go back to home page casper.then(function () { - casper.click('.global-filter[data-name="home"]'); + casper.click('.settings-header .exit'); }); // Commented out due to Issue #1243 @@ -156,7 +156,7 @@ casper.waitForSelector('input[type="checkbox"][id="id_realm_allow_message_editin // Commented out due to Issue #1243 // go back home // casper.then(function () { -// casper.click('.global-filter[data-name="home"]'); +// casper.click('.settings-header .exit'); // }); // // save our edit @@ -192,8 +192,8 @@ casper.waitForSelector('input[type="checkbox"][id="id_realm_allow_message_editin casper.then(function () { casper.test.info('Administration page'); casper.click('a[href^="#administration"]'); - casper.test.assertUrlMatch(/^http:\/\/[^/]+\/#administration/, 'URL suggests we are on administration page'); - casper.test.assertExists('#administration.tab-pane.active', 'Administration page is active'); + casper.test.assertUrlMatch(/^http:\/\/[^\/]+\/#administration/, 'URL suggests we are on administration page'); + casper.test.assertExists('#settings_overlay_container.show', 'Administration page is active'); }); casper.waitForSelector('form.admin-realm-form input.button'); diff --git a/frontend_tests/casper_tests/13-user-deactivation.js b/frontend_tests/casper_tests/13-user-deactivation.js index d4be3f2902..c9c88b86f4 100644 --- a/frontend_tests/casper_tests/13-user-deactivation.js +++ b/frontend_tests/casper_tests/13-user-deactivation.js @@ -10,6 +10,12 @@ casper.then(function () { }); }); +casper.then(function () { + casper.waitForSelector('#settings_overlay_container.show', function () { + casper.click("li[data-section='user-list-admin']"); + }); +}); + // Test user deactivation and reactivation casper.then(function () { casper.waitForSelector('.user_row[id="user_cordelia@zulip.com"]', function () { @@ -52,8 +58,8 @@ casper.then(function () { casper.click('#settings-dropdown'); casper.click('a[href^="#administration"]'); - casper.test.assertSelectorHasText("#administration a[aria-controls='deactivated-users']", "Deactivated users"); - casper.click("#administration a[aria-controls='deactivated-users']"); + casper.test.assertSelectorHasText("li[data-section='deactivated-users-admin']", "Deactivated users"); + casper.click("li[data-section='deactivated-users-admin']"); casper.waitForSelector('#admin_deactivated_users_table .user_row[id="user_cordelia@zulip.com"] .reactivate', function () { @@ -66,13 +72,15 @@ casper.then(function () { casper.waitForSelector('#admin_deactivated_users_table .user_row[id="user_cordelia@zulip.com"] button:not(.reactivate)', function () { casper.test.assertSelectorHasText('#admin_deactivated_users_table .user_row[id="user_cordelia@zulip.com"]', 'Deactivate'); }); +}); - casper.test.assertSelectorHasText("#administration a[aria-controls='organization']", "Organization"); - casper.click("#administration a[aria-controls='organization']"); +// Test bot deactivation and reactivation +casper.then(function () { + casper.test.assertSelectorHasText("li[data-section='organization-settings']", "Organization settings"); + casper.click("li[data-section='bot-list-admin']"); }); casper.then(function () { - // Test bot deactivation and reactivation casper.waitForSelector('.user_row[id="user_new-user-bot@zulip.com"]', function () { casper.test.assertSelectorHasText('.user_row[id="user_new-user-bot@zulip.com"]', 'Deactivate'); casper.click('.user_row[id="user_new-user-bot@zulip.com"] .deactivate'); diff --git a/static/js/admin.js b/static/js/admin.js index 9cae4caff9..fa2682411f 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -12,6 +12,8 @@ exports.show_or_hide_menu_item = function () { item.show(); } else { item.hide(); + $(".ind-tab[data-name='admin']").addClass("disabled"); + $(".settings-list li.admin").hide(); } }; @@ -136,11 +138,8 @@ function get_non_default_streams_names(streams_data) { } exports.update_default_streams_table = function () { - if (!meta.loaded) { - return; - } - - if ($('#administration').hasClass('active')) { + if (/#*administration/.test(window.location.hash) || + /#*settings/.test(window.location.hash)) { $("#admin_default_streams_table").expectOne().find("tr.default_stream_row").remove(); populate_default_streams(page_params.realm_default_streams); } @@ -270,8 +269,9 @@ function _setup_page() { realm_default_language: page_params.realm_default_language, realm_waiting_period_threshold: page_params.realm_waiting_period_threshold, }; + var admin_tab = templates.render('admin_tab', options); - $("#administration").html(admin_tab); + $("#settings_content .administration-box").html(admin_tab); $("#administration-status").expectOne().hide(); $("#admin-realm-name-status").expectOne().hide(); $("#admin-realm-restricted-to-domain-status").expectOne().hide(); @@ -288,6 +288,20 @@ function _setup_page() { $('#admin-filter-pattern-status').expectOne().hide(); $('#admin-filter-format-status').expectOne().hide(); + var tab = (function () { + var tab = false; + var hash_sequence = window.location.hash.split(/\//); + if (/#*(administration)/.test(hash_sequence[0])) { + tab = hash_sequence[1]; + return tab || "organization-settings"; + } + return tab; + }()); + + if (tab) { + exports.launch_page(tab); + } + $("#id_realm_default_language").val(page_params.realm_default_language); // create loading indicators @@ -1014,6 +1028,17 @@ function _setup_page() { } +exports.launch_page = function (tab) { + var $active_tab = $("#settings_overlay_container li[data-section='" + tab + "']"); + + if ($active_tab.hasClass("admin")) { + $(".sidebar .ind-tab[data-name='admin']").click(); + } + + $("#settings_overlay_container").addClass("show"); + $active_tab.click(); +}; + exports.setup_page = function () { i18n.ensure_i18n(_setup_page); }; diff --git a/static/js/click_handlers.js b/static/js/click_handlers.js index b6fe2035c4..7f93c4ef56 100644 --- a/static/js/click_handlers.js +++ b/static/js/click_handlers.js @@ -294,9 +294,10 @@ $(function () { popovers.register_click_handlers(); notifications.register_click_handlers(); - $('.logout_button').click(function () { + $('body').on('click', '.logout_button', function () { $('#logout_form').submit(); }); + $('.restart_get_events_button').click(function () { server_events.restart_get_events({dont_block: true}); }); @@ -558,6 +559,58 @@ $(function () { $('a.dropdown-toggle, .dropdown-menu a').on('touchstart', function (e) { e.stopPropagation(); }); + + $("#settings_overlay_container .sidebar").on("click", "li[data-section]", function () { + var $this = $(this); + + $("#settings_overlay_container .sidebar li").removeClass("active no-border"); + $this.addClass("active"); + $this.prev().addClass("no-border"); + }); + + $("#settings_overlay_container .sidebar").on("click", "li[data-section]", function () { + var $this = $(this); + var section = $this.data("section"); + var sel = "[data-name='" + section + "']"; + + $("#settings_overlay_container .sidebar li").removeClass("active no-border"); + $this.addClass("active"); + $this.prev().addClass("no-border"); + + if ($this.hasClass("admin")) { + window.location.hash = "administration/" + section; + } else { + window.location.hash = "settings/" + section; + } + + $(".settings-section, .settings-wrapper").removeClass("show"); + $(".settings-section" + sel + ", .settings-wrapper" + sel).addClass("show"); + }); + + $("#settings_overlay_container").on("click", function (e) { + var $target = $(e.target); + if ($target.is(".exit-sign, .exit")) { + hashchange.exit_settings(); + } + }); + + (function () { + var $parent = $("#settings_overlay_container .sidebar .tab-switcher"); + var $tabs = $parent.find(".ind-tab"); + $tabs.click(function () { + $tabs.removeClass("selected"); + $(this).addClass("selected"); + + $(".sidebar li").hide(); + if ($(this).data("name") === "admin") { + $("li.admin").show(); + $("li[data-section='organization-settings']").click(); + } else { + $("li:not(.admin)").show(); + $("li[data-section='your-account']").click(); + } + }); + }()); }); return exports; diff --git a/static/js/gear_menu.js b/static/js/gear_menu.js index 164d55230b..13a01783a6 100644 --- a/static/js/gear_menu.js +++ b/static/js/gear_menu.js @@ -48,12 +48,6 @@ exports.initialize = function () { // The admin and settings pages are generated client-side through // templates. - - var admin_link = $('#gear-menu a[href="#administration"]'); - admin_link.on('shown', admin.setup_page); - - var settings_link = $('#gear-menu a[href="#settings"]'); - settings_link.on('shown', settings.setup_page); }; return exports; diff --git a/static/js/hashchange.js b/static/js/hashchange.js index 19db1f495f..71eb514aa1 100644 --- a/static/js/hashchange.js +++ b/static/js/hashchange.js @@ -199,9 +199,9 @@ function do_hashchange(from_reload) { // When going from a normal view (eg. `narrow/is/private`) to a settings panel // (eg. `settings/your-bots`) it should trigger the `should_ignore` function and // return `true` for the current state -- we want to ignore hash changes from -// within the settings page, as they will be handled by the settings page itself. -// -// There is then an `exit_settings` function that allows the hash to change exactly +// within the settings page. The previous hash however should return `false` as it +// was outside of the scope of settings. +// there is then an `exit_settings` function that allows the hash to change exactly // once without triggering any events. This allows the hash to reset back from // a settings page to the previous view available before the settings page // (eg. narrow/is/private). This saves the state, scroll position, and makes the @@ -211,24 +211,44 @@ var ignore = { flag: false, prev: null, old_hash: typeof window !== "undefined" ? window.location.hash : "#", + group: null, }; function get_main_hash(hash) { - return hash.replace(/^#/, "").split(/\//)[0]; + return hash ? hash.replace(/^#/, "").split(/\//)[0] : ""; } +// different groups require different reloads. The grouped elements don't +// require a reload or overlay change to run. +var get_hash_group = (function () { + var groups = [ + ["subscriptions"], + ["settings", "administration"], + ]; + + return function (value) { + var idx = null; + + _.find(groups, function (o, i) { + if (o.indexOf(value) !== -1) { + idx = i; + return true; + } + return false; + }); + + return idx; + }; +}()); + function should_ignore(hash) { // an array of hashes to ignore (eg. ["subscriptions", "settings", "administration"]). - var ignore_list = ["subscriptions"]; + var ignore_list = ["subscriptions", "settings", "administration"]; var main_hash = get_main_hash(hash); return (ignore_list.indexOf(main_hash) > -1); } -function hide_overlays() { - subs.close(); -} - function hashchanged(from_reload, e) { var old_hash; if (e) { @@ -238,16 +258,32 @@ function hashchanged(from_reload, e) { } var base = get_main_hash(window.location.hash); + if (should_ignore(window.location.hash)) { - if (!should_ignore(old_hash || "#")) { - if (base === "subscriptions") { - subs.launch(); + // if the old has was a standard non-ignore hash OR the ignore hash + // base has changed, something needs to run again. + + if (!should_ignore(old_hash || "#") || ignore.group !== get_hash_group(base)) { + if (ignore.group !== get_hash_group(base)) { + exports.close_modals(); } - ignore.prev = old_hash; + // now only if the previous one should not have been ignored. + if (!should_ignore(old_hash || "#")) { + ignore.prev = old_hash; + } + + if (base === "subscriptions") { + subs.launch(); + } else if (/settings|administration/.test(base)) { + settings.setup_page(); + admin.setup_page(); + } + + ignore.group = get_hash_group(base); } } else if (!should_ignore(window.location.hash) && !ignore.flag) { - hide_overlays(); + exports.close_modals(); changing_hash = true; var ret = do_hashchange(from_reload); changing_hash = false; @@ -270,6 +306,10 @@ exports.initialize = function () { hashchanged(true); }; +exports.close_modals = function () { + $("[data-overlay]").removeClass("show"); +}; + exports.exit_settings = function (callback) { if (should_ignore(window.location.hash)) { ui.blur_active_element(); @@ -278,6 +318,8 @@ exports.exit_settings = function (callback) { if (typeof callback === "function") { callback(); } + + exports.close_modals(); } }; diff --git a/static/js/hotkey.js b/static/js/hotkey.js index 30ffcb49de..7172cd0349 100644 --- a/static/js/hotkey.js +++ b/static/js/hotkey.js @@ -7,6 +7,10 @@ function do_narrow_action(action) { return true; } +function is_settings_page() { + return (/^#*(settings|administration)/g).test(window.location.hash); +} + var actions_dropdown_hotkeys = [ 'down_arrow', 'up_arrow', @@ -213,6 +217,28 @@ function process_hotkey(e) { } } + if (is_settings_page()) { + if (event_name === 'up_arrow') { + var prev = e.target.previousElementSibling; + + if ($(prev).css("display") !== "none") { + $(prev).focus().click(); + } + return true; + } else if (event_name === 'down_arrow') { + var next = e.target.nextElementSibling; + + if ($(next).css("display") !== "none") { + $(next).focus().click(); + } + return true; + } else if (event_name === 'escape') { + $("#settings_overlay_container .exit").click(); + return true; + } + return false; + } + // Process hotkeys specially when in an input, select, textarea, or send button if ($('input:focus,select:focus,textarea:focus,#compose-send-button:focus').length > 0) { if (event_name === 'escape') { @@ -256,7 +282,10 @@ function process_hotkey(e) { } if (event_name === 'enter') { - if (activity.searching()) { + if (is_settings_page()) { + $(e.target).click(); + return true; + } else if (activity.searching()) { activity.blur_search(); return true; } else if (stream_list.searching()) { @@ -353,11 +382,17 @@ function process_hotkey(e) { navigate.to_end(); return true; case 'page_up': - navigate.page_up(); - return true; + if (!is_settings_page()) { + navigate.page_up(); + return true; + } + break; case 'page_down': - navigate.page_down(); - return true; + if (!is_settings_page()) { + navigate.page_down(); + return true; + } + break; } // Shortcuts that operate on a message diff --git a/static/js/settings.js b/static/js/settings.js index 16e8859f44..6c010dd61c 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -149,6 +149,17 @@ function _setup_page() { // at page load. This promise will be resolved with a list of streams after // the first settings page load. build_stream_list then adds a callback to // the promise, which in most cases will already be resolved. + + var tab = (function () { + var tab = false; + var hash_sequence = window.location.hash.split(/\//); + if (/#*(settings)/.test(hash_sequence[0])) { + tab = hash_sequence[1]; + return tab || "your-account"; + } + return tab; + }()); + if (_streams_deferred.state() !== "resolved") { channel.get({ url: '/json/streams', @@ -173,7 +184,7 @@ function _setup_page() { zuliprc: 'zuliprc', }); - $("#settings").html(settings_tab); + $(".settings-box").html(settings_tab); $("#settings-status").hide(); $("#notify-settings-status").hide(); $("#display-settings-status").hide(); @@ -186,6 +197,10 @@ function _setup_page() { $("#show_api_key_box").hide(); $("#api_key_button_box").show(); + if (tab) { + exports.launch_page(tab); + } + function clear_password_change() { // Clear the password boxes so that passwords don't linger in the DOM // for an XSS attacker to find. @@ -463,10 +478,14 @@ function _setup_page() { }); }); + $("#default_language_modal [data-dismiss]").click(function () { + $("#default_language_modal").fadeOut(300); + }); + $("#default_language_modal .language").click(function (e) { e.preventDefault(); e.stopPropagation(); - $('#default_language_modal').modal('hide'); + $('#default_language_modal').fadeOut(300); var data = {}; var $link = $(e.target).closest("a[data-code]"); @@ -495,7 +514,7 @@ function _setup_page() { $('#default_language').on('click', function (e) { e.preventDefault(); e.stopPropagation(); - $('#default_language_modal').modal('show'); + $('#default_language_modal').show().attr('aria-hidden', false); }); $("#user_deactivate_account_button").on('click', function (e) { @@ -835,6 +854,17 @@ exports.update_page = function () { i18n.ensure_i18n(_update_page); }; +exports.launch_page = function (tab) { + var $active_tab = $("#settings_overlay_container li[data-section='" + tab + "']"); + + if (!$active_tab.hasClass("admin")) { + $(".sidebar .ind-tab[data-name='settings']").click(); + } + + $("#settings_overlay_container").addClass("show"); + $active_tab.click(); +}; + return exports; }()); diff --git a/static/styles/settings.css b/static/styles/settings.css index f848dbf08b..4d4ac4e023 100644 --- a/static/styles/settings.css +++ b/static/styles/settings.css @@ -111,6 +111,7 @@ td .button { } .settings-section { + display: none; background-color: #fafafa; border-radius: 2px; margin: 20px; @@ -119,6 +120,20 @@ td .button { border-top: 5px solid #dfdfdf; } +#administration .settings-section { + display: block; +} + +.settings-wrapper { + display: none; +} + +.settings-section.show, +.settings-wrapper.show, +.settings-wrapper.show .settings-section { + display: block; +} + .settings-section .settings-section-title { font-size: 1.2em; font-weight: 300; @@ -485,6 +500,247 @@ input[type=checkbox].inline-block { height: 200px; } +/* -- new settings overlay -- */ +#settings_overlay_container { + pointer-events: none; + opacity: 0; + + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + overflow: auto; + + background-color: rgba(32,32,32,0.8); + z-index: 105; + + transition: all 0.3s ease; +} + +#settings_overlay_container.show { + pointer-events: all; + opacity: 1; +} + +#settings_overlay_container.show #settings_page { + -webkit-transform: scale(1); + transform: scale(1); +} + +#settings_page { + -webkit-transform: scale(0.5); + transform: scale(0.5); + + background-color: rgba(0,0,0,0.8); + z-index: 102; + min-height: 550px; +} + +#settings_page { + height: 95vh; + width: 97vw; + margin: 2.5vh 1.5vw; + background-color: #fff; + overflow: hidden; + border-radius: 4px; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + transition: transform 0.2s ease; +} + +#settings_page .sidebar { + float: left; + position: relative; + width: 250px; + height: 100%; + min-height: 550px; + overflow-y: auto; + border-top-left-radius: 4px; + border-right: 1px solid #eee; +} + +#settings_page .sidebar .tab-container { + background-color: #fff; + padding: 6px; + border-bottom: 1px solid #ddd; +} + +#settings_page .sidebar .settings-list { + position: relative; + z-index: 3; +} + +#settings_page .content-wrapper { + position: relative; + float: left; + width: calc(100% - 250px - 1px); + height: 100%; +} + +#settings_page .content-wrapper .settings-header { + width: 100%; + height: 43px; + border-bottom: 1px solid #ddd; +} + +#settings_page .content-wrapper #settings_content { + width: 100%; + height: calc(100% - 60px); + + float: left; + overflow-y: auto; +} + +#settings_page .sidebar .header { + height: auto; + position: relative; + width: calc(100% - 20px); + padding: 10px; + text-align: center; + text-transform: uppercase; + + background-color: #edefef; + border-bottom: 1px solid #DDD; +} + +#settings_page .settings-header { + padding-top: 1px; +} + +#settings_page .settings-header h1 { + text-align: center; + font-size: 1.1em; + line-height: 1; + margin: 15px; + text-transform: uppercase; +} + +#settings_page .settings-header .exit { + font-weight: 400; + position: absolute; + top: 10px; + right: 10px; + color: #AAA; + cursor: pointer; +} + +#settings_page .settings-header .exit-sign { + float: right; + position: relative; + top: 3px; + margin-left: 3px; + font-size: 1.7em; + font-weight: 500; + cursor: pointer; +} + + +#deactivation_user_modal.fade.in { + top: calc(50% - 120px); +} + +#deactivate_self_modal { + box-shadow: 0px 0px 75px rgba(0,0,0,0.5); + outline: 10000px solid rgba(0,0,0,0.3); + border: none; + border-radius: 0px; +} + +input[type=text]#settings_search { + width: calc(100% - 10px - 2px); + margin: 0px; + + color: #555; + font-size: 0.9rem; + padding: 3px 5px; + outline: none; + border: 1px solid #DDD; + border-radius: 4px; +} + +input[type=text]:focus#settings_search { + box-shadow: none; + border: 1px solid #BBB; + + border-bottom: 1px solid #DDD; +} + +input[type=text]#settings_search { + width: calc(100% - 10px - 2px); + margin: 0px; +} + +#settings_page .sidebar ul { + list-style: none; + margin: 0; + padding: 0; +} + +#settings_page .sidebar li { + padding: 5px 0px; + outline: none; + cursor: pointer; + transition: all 0.2s ease; + border-bottom: 1px solid #eee; +} + +#settings_page .sidebar li.no-border { + border-color: transparent; +} + +#settings_page .sidebar li.active { + background-color: #eee; +} + +#settings_page .sidebar li.active { + border-bottom: 1px solid transparent; +} + +#settings_page .sidebar li .text, +#settings_page .sidebar li .icon { + display: inline-block; + vertical-align: top; +} + +#settings_page .sidebar li .text { + width: calc(100% - 55px); + padding: 10px 12px 10px 0px; +} + +#settings_page .sidebar li .icon { + width: 18px; + height: 18px; + margin: 10px 10px; + + font-size: 1.4em; + color: #888; + + background-size: cover; + background-repeat: no-repeat; +} + +#settings_page .sidebar li.admin { + display: none; +} + +#settings_page .sidebar li.admin .icon { + text-align: center; +} + +#settings_page .sidebar li:last-of-type .text { + border-bottom: none; +} + +#settings_page .sidebar .sidebar-bottom-anchor { + width: 100%; + position: absolute; + bottom: 0px; +} +/* -- end new settings overlay -- */ + @media (max-width: 1215px) { .user-avatar-section { float: none; @@ -505,6 +761,12 @@ input[type=checkbox].inline-block { } } +@media (max-width: 953px) { + #settings_content .warning { + display: none; + } +} + #show_api_key_box { padding-bottom: 20px; } diff --git a/static/styles/zulip.css b/static/styles/zulip.css index fe6447c06c..451f6702b4 100644 --- a/static/styles/zulip.css +++ b/static/styles/zulip.css @@ -1962,11 +1962,6 @@ div.floating_recipient { table-layout: fixed; } -.administration { - margin-top: 55px; - padding-left: 15px; -} - .conversation-partners { display: block; line-height: 1.2em; diff --git a/static/templates/admin_tab.handlebars b/static/templates/admin_tab.handlebars index 5cbb29fea5..322483c7a3 100644 --- a/static/templates/admin_tab.handlebars +++ b/static/templates/admin_tab.handlebars @@ -1,55 +1,23 @@ -
-
-
-
-

{{t "Administration" }}

- -
-
- {{ partial "organization-settings-admin" }} - {{ partial "emoji-settings-admin" }} - {{ partial "realm-filter-settings-admin" }} - {{ partial "auth-methods-settings-admin" }} -
-
- {{ partial "user-list-admin" }} -
-
- {{ partial "deactivated-users-admin" }} -
-
- {{ partial "bot-list-admin" }} -
-
- {{ partial "streams-list-admin" }} -
-
- {{ partial "default-streams-list-admin" }} -
-
+
- {{ partial "deactivation-user-modal" }} - {{ partial "deactivation-stream-modal" }} - {{ partial "realm-domains-modal" }} -
-
-
+{{ partial "deactivation-user-modal" }} +{{ partial "deactivation-stream-modal" }} +{{ partial "realm-domains-modal" }} + +{{ partial "organization-settings-admin" }} + +{{ partial "emoji-settings-admin" }} + +{{ partial "user-list-admin" }} + +{{ partial "deactivated-users-admin" }} + +{{ partial "bot-list-admin" }} + +{{ partial "streams-list-admin" }} + +{{ partial "default-streams-list-admin" }} + +{{ partial "auth-methods-settings-admin" }} + +{{ partial "realm-filter-settings-admin" }} diff --git a/static/templates/settings_tab.handlebars b/static/templates/settings_tab.handlebars index c1fad30ff7..77a6d5e984 100644 --- a/static/templates/settings_tab.handlebars +++ b/static/templates/settings_tab.handlebars @@ -1,5 +1,3 @@ -

{{t "Settings" }}

-
diff --git a/static/templates/subscription_table_body.handlebars b/static/templates/subscription_table_body.handlebars index b58e8da9aa..9f14be12af 100644 --- a/static/templates/subscription_table_body.handlebars +++ b/static/templates/subscription_table_body.handlebars @@ -1,4 +1,4 @@ -
+
diff --git a/static/third/bootstrap/css/bootstrap.css b/static/third/bootstrap/css/bootstrap.css index 758e586ce9..ef4330f7db 100644 --- a/static/third/bootstrap/css/bootstrap.css +++ b/static/third/bootstrap/css/bootstrap.css @@ -3774,7 +3774,7 @@ button.close { right: 0; bottom: 0; left: 0; - z-index: 1040; + z-index: 101; background-color: #000000; } diff --git a/templates/zerver/index.html b/templates/zerver/index.html index 4a67840a7d..3f6624dd72 100644 --- a/templates/zerver/index.html +++ b/templates/zerver/index.html @@ -60,6 +60,9 @@ var page_params = {{ page_params }};
+
+ {% include "zerver/settings_overlay.html" %} +
{% include "zerver/navbar.html" %}
diff --git a/templates/zerver/navbar.html b/templates/zerver/navbar.html index 4550e13e7b..52ed3fb027 100644 --- a/templates/zerver/navbar.html +++ b/templates/zerver/navbar.html @@ -55,12 +55,12 @@
  • - + {{ _('Settings') }}
  • - + {{ _('Administration') }}
  • diff --git a/templates/zerver/settings_overlay.html b/templates/zerver/settings_overlay.html new file mode 100644 index 0000000000..5f48351cb2 --- /dev/null +++ b/templates/zerver/settings_overlay.html @@ -0,0 +1,100 @@ +
    + +
    +
    +

    {{ _('Settings') }}

    +
    + × +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    diff --git a/tools/lib/find_add_class.py b/tools/lib/find_add_class.py index 49bb976f9d..ae3f037ec2 100644 --- a/tools/lib/find_add_class.py +++ b/tools/lib/find_add_class.py @@ -18,6 +18,7 @@ GENERIC_KEYWORDS = [ 'show', 'notdisplayed', 'popover', + 'no-border', 'success', 'text-error', 'warning', @@ -25,6 +26,7 @@ GENERIC_KEYWORDS = [ 'zoom-out', 'first', 'second', + 'selected', ] def raise_error(fn, i, line): diff --git a/zerver/tests/test_templates.py b/zerver/tests/test_templates.py index f23a2fdd85..2fdfe72379 100644 --- a/zerver/tests/test_templates.py +++ b/zerver/tests/test_templates.py @@ -72,6 +72,7 @@ class TemplateTestCase(ZulipTestCase): 'zerver/navbar.html', 'zerver/right-sidebar.html', 'zerver/search_operators.html', + 'zerver/settings_overlay.html', 'zerver/stream_creation_prompt.html', 'zerver/subscriptions.html', 'zerver/tutorial_finale.html',