From 0753d0794de2b2bffeba89a08bf47032f8154ada Mon Sep 17 00:00:00 2001
From: Paul Kaplan <pkaplan@media.mit.edu>
Date: Tue, 3 Apr 2018 15:36:25 -0400
Subject: [PATCH] Update design for editor tabs with icons, changing blocks to
 code.

Resolves https://github.com/LLK/scratch-gui/issues/1713
---
 src/components/gui/gui.css            |  51 +++++++++++++++++++++++---
 src/components/gui/gui.jsx            |  41 +++++++++++++++++++--
 src/components/gui/icon--code.svg     | Bin 0 -> 1571 bytes
 src/components/gui/icon--costumes.svg | Bin 0 -> 2120 bytes
 src/components/gui/icon--sounds.svg   | Bin 0 -> 2015 bytes
 test/integration/blocks.test.js       |   4 +-
 test/integration/localization.test.js |   2 +-
 7 files changed, 85 insertions(+), 13 deletions(-)
 create mode 100644 src/components/gui/icon--code.svg
 create mode 100644 src/components/gui/icon--costumes.svg
 create mode 100644 src/components/gui/icon--sounds.svg

diff --git a/src/components/gui/gui.css b/src/components/gui/gui.css
index 5132af685..fa6c4ce1a 100644
--- a/src/components/gui/gui.css
+++ b/src/components/gui/gui.css
@@ -57,10 +57,13 @@
 .tab {
     flex-grow: 1;
     height: 80%;
-    margin-left: 1px;
+    margin-left: -0.5rem;
 
-    border-radius: $space $space 0 0;
-    border: none;
+    border-radius: 1rem 1rem 0 0;
+    border: $ui-pane-border 1px solid;
+
+    padding: 0.125rem 1rem 0;
+    font-size: 0.7rem;
 
     background-color: #F6F8FA;
     color: #9AA1B5;
@@ -72,13 +75,49 @@
     user-select: none;
 }
 
-.tab.is-selected {
+/* Use z-indices to force left-on-top for tabs */
+.tab:nth-of-type(1) {
+    margin-left: 0;
+    z-index: 3;
+}
+.tab:nth-of-type(2) {
+    z-index: 2;
+}
+.tab:nth-of-type(3) {
     z-index: 1;
-    color: #40B9F5;
+}
+
+.tab.is-selected {
+    color: $motion-primary;
     background-color: #FFFFFF;
-    border-bottom: $ui-background-blue 1px solid;
+    z-index: 4; /* Make sure selected is always above */
+}
+
+.tab img {
+    margin-right: 0.125rem;
+    filter: grayscale(100%);
+}
+
+.tab.is-selected img {
+    filter: none;
+}
+
+/* Tab style overrides from react-tabs */
+.tab.is-selected:after {
+    display: none;
+}
+
+.tab.is-selected:focus {
+    outline: none;
+    box-shadow: none;
+    border-color: $ui-pane-border;
+}
+
+.tab.is-selected:focus:after {
+    display: none;
 }
 
+/* Body of the tabs */
 .tabs {
     position: relative;
     flex-grow: 1;
diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx
index 2ec53402b..37a66c308 100644
--- a/src/components/gui/gui.jsx
+++ b/src/components/gui/gui.jsx
@@ -1,7 +1,7 @@
 import classNames from 'classnames';
 import PropTypes from 'prop-types';
 import React from 'react';
-import {defineMessages, injectIntl, intlShape} from 'react-intl';
+import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
 import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
 import MediaQuery from 'react-responsive';
 import tabStyles from 'react-tabs/style/react-tabs.css';
@@ -25,6 +25,9 @@ import WebGlModal from '../../containers/webgl-modal.jsx';
 import layout from '../../lib/layout-constants.js';
 import styles from './gui.css';
 import addExtensionIcon from './icon--extensions.svg';
+import codeIcon from './icon--code.svg';
+import costumesIcon from './icon--costumes.svg';
+import soundsIcon from './icon--sounds.svg';
 
 const messages = defineMessages({
     addExtension: {
@@ -110,9 +113,39 @@ const GUIComponent = props => {
                             onSelect={onActivateTab}
                         >
                             <TabList className={tabClassNames.tabList}>
-                                <Tab className={tabClassNames.tab}>Blocks</Tab>
-                                <Tab className={tabClassNames.tab}>Costumes</Tab>
-                                <Tab className={tabClassNames.tab}>Sounds</Tab>
+                                <Tab className={tabClassNames.tab}>
+                                    <img
+                                        draggable={false}
+                                        src={codeIcon}
+                                    />
+                                    <FormattedMessage
+                                        defaultMessage="Code"
+                                        description="Button to get to the code panel"
+                                        id="gui.gui.codeTab"
+                                    />
+                                </Tab>
+                                <Tab className={tabClassNames.tab}>
+                                    <img
+                                        draggable={false}
+                                        src={costumesIcon}
+                                    />
+                                    <FormattedMessage
+                                        defaultMessage="Costumes"
+                                        description="Button to get to the costumes panel"
+                                        id="gui.gui.costumesTab"
+                                    />
+                                </Tab>
+                                <Tab className={tabClassNames.tab}>
+                                    <img
+                                        draggable={false}
+                                        src={soundsIcon}
+                                    />
+                                    <FormattedMessage
+                                        defaultMessage="Sounds"
+                                        description="Button to get to the sounds panel"
+                                        id="gui.gui.soundsTab"
+                                    />
+                                </Tab>
                             </TabList>
                             <TabPanel className={tabClassNames.tabPanel}>
                                 <Box className={styles.blocksWrapper}>
diff --git a/src/components/gui/icon--code.svg b/src/components/gui/icon--code.svg
new file mode 100644
index 0000000000000000000000000000000000000000..390e683b16da01b13bbe8a2df0a0ac0711d9451e
GIT binary patch
literal 1571
zcmcDqugJ|&C`&CW&dkrVRWj5wP*O<EOU_Tp%uBab3Jr17wNSFR<FY9(OIIk*Oex8*
zRWdRts8CYKNX<;oD1q_HGE>W)@+)kW3=|9$j6g^U*-%3zg^Jvqykc9WjFOT9D}DX)
z@^Za$W4-*MbbTWO0|WiyvUI2ttBRb=yliX=4J|D#^}(`Ac3cVy3JNxgy1EMPsd=eI
zi6!|(Rtmw{sU^u73MQ6%MhY6HhK6PanhLrKNH!+rXQbw4CPKZZmz<xgUkuTss|z)<
zB(o$Z)y_FTB~>BJ$VMN+h1iyoTAXa>T$GwvlA5AWo>`IswNTGSA1nn^l~!yA5=kqD
z8kw$;nPRI1GEz6pNJ*i%q$oc-)mAAlKQ9%=(}f1Dp^`#cW=;-F62#UmD$Pl?RZ1;O
z&C5?of%+Wm`+~%h422Y1C0|2R9YYg6Q$q!32+Q2UOu^7Z&)nQh$Iw*Iz!1bSg))6C
z^$ab|p&VyRJp(fnD91w2(ikFPW~5-DXJG=CFf=t&@UhS{Gy$7sVQQk_Y@ughY7Ek3
zX=1Kmu4idvrekQPV6JCwX$)fcnCTfAn1fi(W_kwZCLorno}~%cY>*aHJquH?*&x$=
zO!W*+!DfSOayHd7Ff#&~ZD3}kV4`Pf43;u5R4~!AFaTR>V5s0@tOxUsv$39$5!f&T
zLj_|{Fn~M{W|)E$>KGd8nJPFNgJ>fo69uSpLj|xAh6+9=5N8`IIGaFxVyIvW@t+}x
zQZR*h-4H}6_&}X*2=ak~Gt^gxAkQg4{c5BD^}dmU4>U-O6r7=<1PWJh*g>>FgB4<$
zj|Iq3kUI@c%s_z*4l#%$EFs}&s9*^RT0;dNP=xCkf}$K6(S{13$TtK92b5*1-~$o@
zr;I2CUqf>pOGqLCF+jm&Xa-3m2H-Se1`1R#6P8B699S9wbD(L&02E8GG-3dXKzJH4
z0Qmyse6T+az(E7`y&)`(7%IThh@k>3jevq3>|=-)Xh1_ugQXFOO|UcqaRfAtfL#Yo
zBVaZpjewc3Gy>)r>sac6{0^caDZ~ttK+M1)2T31h;N)QjOC4sg#9;<a8)isJ!wflP
zm_d9GNf>5e&qLCMIW$?A!%~GgEK!&%K=KnrH6%$ujDe;Ihy~6TAk%apHbc^b88kVV
zDfk$IBF{|085*Nz3Wnx75D$SFpp*cLbW=lxC?$Al1S@NlO`I*w-Q1MyZ1h1z3bfSH
MPq*W;0hP;k0MfH&O#lD@

literal 0
HcmV?d00001

diff --git a/src/components/gui/icon--costumes.svg b/src/components/gui/icon--costumes.svg
new file mode 100644
index 0000000000000000000000000000000000000000..de50ce39b013b123e5c94364aad49b80e6a14d32
GIT binary patch
literal 2120
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
UHu|7?23n=*r`vJafGTf00CJhzIRF3v

literal 0
HcmV?d00001

diff --git a/src/components/gui/icon--sounds.svg b/src/components/gui/icon--sounds.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0de67c53780e9305d76d09363d349146222c0a87
GIT binary patch
literal 2015
zcmcDqugJ|&C`&CW&dkrVRWj5wP*O<EOU_Tp%uBab3Jr17wNSFR<FY9(OIIk*Oex8*
zRWdRts8CYKNX<;oD1q_HGE>W)@+)kW3=|9$j6g^U*-%3zg^Jvqykc9WjFOT9D}DX)
z@^Za$W4-*MbbTWO0|WiyvUI2ttBRb=yliX=4J|D#^}(`Ac3cVy3JNxgy1EMPsd=eI
zi6!|(Rtmw{sU^u73MQ6%MhY6HhK6PanhLrKNH!+rXQbw4CPKZZmz<xgUkuTss|z)<
zB(o$Z)h;-{G%uxCA<WQ5A0hy;FD11&+0MBrHL)Z$MWH;iBm-)to{c_O3Z^Qp*bXF;
zRtz;XT_H2YRtaLLZkVBxLUBn^es-#@QeJ*uDvYNK4PHYfg|y6^9GE1Cty@%@lWMD!
zT9%rZpOOOgJvamk5=$}^Qf!rc4UP27j19~!3=DM)jrGio%?(YA6r2r>^h_)aj4Vu$
z1PzV!jEzi9%^-rNmgc4==H?29MtX)8CYFZg79gdjh9-uFW|j)hhK73PX6A+#re+{v
zBQsMYV+&ISLqk0?BXdg=Lo*#iBRz8?V>1&|Bao<txv7bT8CcZVz}U>p80-XN6EicA
zprM|rfq{vci5bW?n4p24sey^5sUeDfOFeS~V?#4DOGB^|V3t|x8Ce*bn;V!~f-HkM
z%tFuH#K6$p+}IdoF3cAedM1{JMwS+qW?(m%8JJm^S(@rt=oy)q8kty_n<*F?>lvDu
z7@C@x>saU+TNqmyK}C%%EG#U{K%y1~M#h$AmY|R{(KEC#Gd4Fh(J?g8Gc>idG&D6<
zFhmkH)Uz-#H8n5*8w@kT&{)sNz}Udh0u+|UdPYX3=Eg>#pfs^CHZU+Z1i9GK*wEbE
z$QUFFjW?{38KvNBXsTyqYG!6^W~^gqs%KzoYHVa;qTp<3s%L0mW@utyge+`mqGxGp
zU|?tg7Bn<9H#RT?IoQI`z}(zK2PAE5WMpXxiX#&}V@qQL6OdXHJu?eq6C<!vBU58@
zOLKFOT0;{<3nNfEG0`(MFf=wXG6%WW+{h5*X|NMaEX<7!K%O(wGcYkRH!(3+Ff`SJ
ziCXGeni&{dSQwju+yFDeLeI#;#N5Ep4CD(FJ(zvwdKP9T=7yFgAhj@;nd=!F8JZg!
zfdbe>59$kZJp*$i3u9w&S~b-J`Nz=6Ovg;m!pOqV(%cm622et=G`G+()3Y=)H8wLg
zu~aZL(=#wMF*h-?&@l(ay`{0CnW=)aA;=O76GKZw9ZNkkLsMf@Pyi!|f-;YVrMU&j
z5eOp;P4vu+42=v7LEbRcvoJL<v;gG|6Fo}<LqiKoQ&32lnwpy#S(t)j0~&MK;}aCo
z271Qk7N$lPAg`F2TbNpyo0};37$SrXP4$e83=B*RK(0m-Hq$dUF}5%^HB+$EGc-3e
zH!(9e(=jyDvj9b;k*R`(o{6EQk(rs12}sn?!qVKpz+Az{OwZiX#N5;flnhPu%q-0<
zOiauaoXzx%3@uG84NZ)|X~5jT*wV;Q!Bo%0%+kWh*b-dUSeToenVTCcfV3Hy8G-`Z
z&{z*9>SLm3Vqj)!U}^>~gJ8nWpfbw9(9pybobF-5V2+WAsi}pLg@Q4ta4|76HnlW0
zQ}8j?vD7m)H88a>H&t*p*0IntH#aaaG%+z%Kr+fg&(IiTnT4eSlD$ZxJ|=o*=B9=w
z7Dh%oNW#vhdM2hO#->Kbpb`RZhMAs`fr){krG=S}xt@iIvALyzrKN(Ip1HZDk%fU7
zNYvQS%-Gn%)KtL-DP&DS$<x@x5LEslMT4oHp^<@+nWcpSQbd~SnVFgy8JL+HBa52p
z!DBs230!+P=jSG6=B1|S24^G|q{8Y5WfNyhb2m37I~#paRRFDT^waIQY(RCY9ROtt
B#*qL3

literal 0
HcmV?d00001

diff --git a/test/integration/blocks.test.js b/test/integration/blocks.test.js
index 9f0736488..4f3411d55 100644
--- a/test/integration/blocks.test.js
+++ b/test/integration/blocks.test.js
@@ -29,7 +29,7 @@ describe('Working with the blocks', () => {
     test('Blocks report when clicked in the toolbox', async () => {
         await loadUri(uri);
         await clickXpath('//button[@title="tryit"]');
-        await clickText('Blocks');
+        await clickText('Code');
         await clickText('Operators', scope.blocksTab);
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
         await clickText('join', scope.blocksTab); // Click "join <hello> <world>" block
@@ -58,7 +58,7 @@ describe('Working with the blocks', () => {
     test('Creating variables', async () => {
         await loadUri(uri);
         await clickXpath('//button[@title="tryit"]');
-        await clickText('Blocks');
+        await clickText('Code');
         await clickText('Variables', scope.blocksTab);
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
 
diff --git a/test/integration/localization.test.js b/test/integration/localization.test.js
index 7c90b3221..deaf1a788 100644
--- a/test/integration/localization.test.js
+++ b/test/integration/localization.test.js
@@ -29,7 +29,7 @@ describe('Localization', () => {
     test.skip('Localization', async () => {
         await loadUri(uri);
         await clickXpath('//button[@title="tryit"]');
-        await clickText('Blocks');
+        await clickText('Code');
         await clickXpath('//button[@title="Add Extension"]');
         await clickText('Pen', scope.modal); // Modal closes
         await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation
-- 
GitLab