From cefacbdd4fef2ad8446eabbb67674016f65eeee3 Mon Sep 17 00:00:00 2001 From: sharon Date: Fri, 12 Apr 2024 15:33:29 -0400 Subject: [PATCH] Interactions for selecting project type in project wizard (#2746) * connect select project type to project state - add ProjectType and ProjectTypeGroup (based on RadioButton and RadioButtonGroup) - store the user's project type selection in the project state * add localization for default project name prefix * add icons from runtimes to project type button * add styling and keyboard navigation support * add python, r and jupyter logos to project type selection * refactor project type step to not use runtime info * focus selected project type on navigate back * remove unused css * move logo licenses to ThirdPartyNotices.txt * update project type default/hover/selected colours * update project type button colours - make border colour the same as the background colour for regular light and dark mode - make onhover and onselected similarly styled --- ThirdPartyNotices.txt | 476 +++++++++++++++++- .../lib/stylelint/vscode-known-variables.json | 9 + .../components/logos/logoJupyter.svg | 364 ++++++++++++++ .../components/logos/logoJupyter.tsx | 212 ++++++++ .../components/logos/logoPython.tsx | 76 +++ .../components/logos/logoR.svg | 14 + .../components/logos/logoR.tsx | 58 +++ .../components/logos/projectTypeLogo.css | 8 + .../components/projectType.css | 61 +++ .../components/projectType.tsx | 72 +++ .../components/projectTypeGroup.css | 10 + .../components/projectTypeGroup.tsx | 69 +++ .../components/steps/projectTypeStep.css | 13 - .../components/steps/projectTypeStep.tsx | 70 +-- src/vs/workbench/common/theme.ts | 76 ++- 15 files changed, 1541 insertions(+), 47 deletions(-) create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.svg create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.tsx create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoPython.tsx create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.svg create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.tsx create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/logos/projectTypeLogo.css create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/projectType.css create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/projectType.tsx create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.css create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.tsx diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index e667f812a76..ddd05229f29 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -2806,4 +2806,478 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---------------------------------------------------------- \ No newline at end of file +--------------------------------------------------------- + +--------------------------------------------------------- + +Jupyter logo from jupyter/notebook - BSD 3-Clause License +https://github.com/jupyter/notebook + +BSD 3-Clause License + +- Copyright (c) 2001-2015, IPython Development Team +- Copyright (c) 2015-, Jupyter Development Team + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------- + +--------------------------------------------------------- + +The R logo is © 2016 The R Foundation - CC-BY-SA 4.0 +https://www.r-project.org/logo/ + +======================================================================= + +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. +======================================================================= diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index ec6c48d1182..671f676f7c0 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -577,6 +577,15 @@ "--vscode-positronModalDialog-defaultButtonForeground", "--vscode-positronModalDialog-defaultButtonHoverBackground", "--vscode-positronModalDialog-foreground", + "--vscode-positronModalDialog-projectTypeBackground", + "--vscode-positronModalDialog-projectTypeBackgroundHover", + "--vscode-positronModalDialog-projectTypeBackgroundSelected", + "--vscode-positronModalDialog-projectTypeBorder", + "--vscode-positronModalDialog-projectTypeBorderHover", + "--vscode-positronModalDialog-projectTypeBorderSelected", + "--vscode-positronModalDialog-projectTypeForeground", + "--vscode-positronModalDialog-projectTypeForegroundHover", + "--vscode-positronModalDialog-projectTypeForegroundSelected", "--vscode-positronModalDialog-radioButtonBackground", "--vscode-positronModalDialog-radioButtonBorder", "--vscode-positronModalDialog-radioButtonForeground", diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.svg b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.svg new file mode 100644 index 00000000000..42918a70737 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.svg @@ -0,0 +1,364 @@ + + + + + + image/svg+xml + + Group.svg + + + + + Group.svg + Created using Figma 0.90 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.tsx new file mode 100644 index 00000000000..3a6a55a94ce --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.tsx @@ -0,0 +1,212 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./projectTypeLogo'; + +// React. +import * as React from 'react'; + +export const JupyterLogo = () => ( + // The below SVG React code was generated by using https://github.com/gregberge/svgr on the + // Jupyter logo svg file located at src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter.svg, + // and then adapted for sizing and unique ids to avoid conflicts with other logos. + // Please see the corresponding license for the original Jupyter logo svg file in the top-level ThirdPartyNotices.txt. + + {'Group.svg'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoPython.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoPython.tsx new file mode 100644 index 00000000000..dd976275401 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoPython.tsx @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./projectTypeLogo'; + +// React. +import * as React from 'react'; + +export const PythonLogo = () => ( + // The below SVG React code was generated using https://github.com/gregberge/svgr on the + // Python logo svg file located at extensions/positron-python/resources/branding/python-icon.svg + // and then adapted for sizing and unique ids to avoid conflicts with other logos. + // Please see the corresponding license for the original Python logo file in + // extensions/positron-python/LICENSE. + + + + + + + + + + + + +); diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.svg b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.svg new file mode 100644 index 00000000000..389b03c113e --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.tsx new file mode 100644 index 00000000000..77410d9eff4 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.tsx @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./projectTypeLogo'; + +// React. +import * as React from 'react'; + +export const RLogo = () => ( + // The below SVG React code was generated by using https://github.com/gregberge/svgr on the + // R logo svg file located at src/vs/workbench/browser/positronNewProjectWizard/components/logos/logoR.svg + // and then adapted for sizing and unique ids to avoid conflicts with other logos. + // Please see the corresponding license for the original Jupyter logo svg file in the top-level ThirdPartyNotices.txt. + + + + + + + + + + + + + + +); diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/logos/projectTypeLogo.css b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/projectTypeLogo.css new file mode 100644 index 00000000000..4d3586677ba --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/logos/projectTypeLogo.css @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +.project-type-logo { + width: 100%; + height: 100%; +} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.css b/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.css new file mode 100644 index 00000000000..5aa1e4eb29a --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.css @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +.project-type-selection-step +.project-type-group +.project-type { + height: 54px; + display: flex; + flex-direction: row; + align-items: center; + gap: 6px; + cursor: pointer; + background-color: var(--vscode-positronModalDialog-projectTypeBackground); + color: var(--vscode-positronModalDialog-projectTypeForeground); + border: 1px solid var(--vscode-positronModalDialog-projectTypeBorder); + border-radius: 6px; + padding: 0px 12px; +} + +.project-type-selection-step +.project-type-group +.project-type:hover { + background-color: var(--vscode-positronModalDialog-projectTypeBackgroundHover); + color: var(--vscode-positronModalDialog-projectTypeForegroundHover); + border-color: var(--vscode-positronModalDialog-projectTypeBorderHover); +} + +.project-type-selection-step +.project-type-group +.project-type-selected { + background-color: var(--vscode-positronModalDialog-projectTypeBackgroundSelected); + color: var(--vscode-positronModalDialog-projectTypeForegroundSelected); + border-color: var(--vscode-positronModalDialog-projectTypeBorderSelected); +} + +/* Include outline when project type is focused during keyboard navigation */ +.project-type-selection-step +.project-type-group +.project-type:has(:focus-visible) { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: 2px; +} + +.project-type-selection-step +.project-type-group +.project-type +.project-type-icon { + width: 36px; + height: 36px; +} + +/* Hide the default input circle */ +.positron-modal-dialog-box +.project-type-group +.project-type +.project-type-input { + cursor: pointer; + appearance: none; + margin: 0; +} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.tsx new file mode 100644 index 00000000000..6a9a5186636 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/projectType.tsx @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./projectType'; + +// React. +import * as React from 'react'; +import { useRef } from 'react'; // eslint-disable-line no-duplicate-imports + +// Other dependencies. +import { NewProjectType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; +import { PythonLogo } from 'vs/workbench/browser/positronNewProjectWizard/components/logos/logoPython'; +import { JupyterLogo } from 'vs/workbench/browser/positronNewProjectWizard/components/logos/logoJupyter'; +import { RLogo } from 'vs/workbench/browser/positronNewProjectWizard/components/logos/logoR'; +import { useNewProjectWizardContext } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardContext'; + +/** + * ProjectTypeProps interface. + */ +interface ProjectTypeProps { + identifier: NewProjectType; + selected: boolean; + groupName: string; + activeTabIndex: boolean; + onSelected: () => void; +} + +/** + * ProjectType component. + * @param props The component properties. + * @returns The rendered component. + */ +export const ProjectType = (props: ProjectTypeProps) => { + const projectTypeSelected = useNewProjectWizardContext().projectConfig.projectType !== undefined; + const inputRef = useRef(null); + + // On project type selected, set the focus to the input element and notify the parent. + const onSelected = () => { + inputRef.current?.focus(); + props.onSelected(); + }; + + // Render. + return ( +
+
+ { + props.identifier === NewProjectType.PythonProject ? : + props.identifier === NewProjectType.JupyterNotebook ? : + props.identifier === NewProjectType.RProject ? : + null + } +
+ + +
+ ); +}; diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.css b/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.css new file mode 100644 index 00000000000..f8afd4694ed --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.css @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +.project-type-selection-step +.project-type-group { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 18px; +} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.tsx new file mode 100644 index 00000000000..ce8d558bb76 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup.tsx @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./projectTypeGroup'; + +// React. +import * as React from 'react'; +import { PropsWithChildren, useState } from 'react'; // eslint-disable-line no-duplicate-imports + +// Other dependencies. +import { ProjectType } from 'vs/workbench/browser/positronNewProjectWizard/components/projectType'; +import { NewProjectType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; + +/** + * ProjectTypeProps interface. + */ +interface ProjectTypeProps { + name: string; + selectedProjectId?: string; + labelledBy?: string; + describedBy?: string; + onSelectionChanged: (projectType: NewProjectType) => void; +} + +/** + * ProjectTypeGroup component. + * @param props The component properties. + * @returns The rendered component. + * @see https://www.w3.org/WAI/ARIA/apg/patterns/radio/ for accessibility guidelines. + */ +export const ProjectTypeGroup = (props: PropsWithChildren) => { + const projectTypes = Object.values(NewProjectType); + + // Hooks. + const [currentSelection, setCurrentSelection] = useState(props.selectedProjectId); + const [activeIndexId, setActiveIndexId] = useState(props.selectedProjectId ?? projectTypes[0] ?? ''); + + // On project type selected, update the current selection and notify the parent. + const onSelectionChanged = (projectType: NewProjectType) => { + setCurrentSelection(projectType); + setActiveIndexId(projectType); + props.onSelectionChanged(projectType); + }; + + // Render. + return ( +
+ {projectTypes.map((projectType, index) => { + return ( + onSelectionChanged(projectType)} + /> + ); + })} +
+ ); +}; diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.css b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.css index b93e150c6c7..c562d3b6f13 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.css +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.css @@ -23,16 +23,3 @@ .project-type-selection-step-description { margin-bottom: 8px; } - -.project-type-selection-step -.project-type-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - grid-gap: 10px; -} - -.project-type-selection-step -.project-type-grid -.project-type-button { - color: var(--vscode-positronModalDialog-foreground); -} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx index 056456cbfc6..51205576f2b 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx @@ -2,15 +2,20 @@ * Copyright (C) 2024 Posit Software, PBC. All rights reserved. *--------------------------------------------------------------------------------------------*/ +// CSS. import 'vs/css!./projectTypeStep'; + +// React. import * as React from 'react'; -import { PropsWithChildren } from 'react'; // eslint-disable-line no-duplicate-imports -import { Button } from 'vs/base/browser/ui/positronComponents/button/button'; +import { PropsWithChildren, useState } from 'react'; // eslint-disable-line no-duplicate-imports + +// Other dependencies. import { localize } from 'vs/nls'; import { useNewProjectWizardContext } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardContext'; import { NewProjectType, NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { NewProjectWizardStepProps } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardStepProps'; import { OKCancelBackNextActionBar } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/okCancelBackNextActionBar'; +import { ProjectTypeGroup } from 'vs/workbench/browser/positronNewProjectWizard/components/projectTypeGroup'; /** * The ProjectTypeStep component is the first step in the new project wizard, used to @@ -19,52 +24,53 @@ import { OKCancelBackNextActionBar } from 'vs/workbench/browser/positronComponen * @returns The rendered component */ export const ProjectTypeStep = (props: PropsWithChildren) => { + // Retrieve the wizard state and project configuration. const newProjectWizardState = useNewProjectWizardContext(); + const setProjectConfig = newProjectWizardState.setProjectConfig; + const projectConfig = newProjectWizardState.projectConfig; - // Set the projectType and initialize the default project name, + // Hooks. + const [selectedProjectType, setSelectedProjectType] = useState(projectConfig.projectType); + + // Set the projectType and initialize the default project name if applicable, // then navigate to the ProjectNameLocation step. const nextStep = () => { - // TODO: set the projectType according to the selected button - const projectType = NewProjectType.PythonProject; - + // TODO: once we have input validation, the user should not be able to proceed until a + // project type is selected, so we won't have to check that the selectedProjectType is not null. + const projectType = selectedProjectType ?? NewProjectType.PythonProject; // If the project type has changed or the project name is empty, initialize the project name. - if (newProjectWizardState.projectConfig.projectType !== projectType || newProjectWizardState.projectConfig.projectName === '') { - // The default project name is 'my' + projectType without spaces. - const defaultProjectName = 'my' + projectType.replace(/\s/g, ''); - newProjectWizardState.setProjectConfig({ - ...newProjectWizardState.projectConfig, + if (projectConfig.projectType !== projectType || projectConfig.projectName === '') { + // The default project name is 'my' + projectType without spaces, eg. 'myPythonProject'. + const defaultProjectName = + localize( + "positron.newProjectWizard.projectTypeStep.defaultProjectNamePrefix", + "my" + ) + projectType.replace(/\s/g, ''); + setProjectConfig({ + ...projectConfig, projectType, projectName: defaultProjectName }); } - props.next(NewProjectWizardStep.ProjectNameLocation); }; + // Render. return (
-
- {localize('positronNewProjectWizard.projectTypeStepTitle', 'Project Type')} -
-
- {localize('positronNewProjectWizard.projectTypeStepDescription', 'Select the type of project to create.')} +
+ {(() => localize('positronNewProjectWizard.projectTypeStepTitle', 'Project Type'))()}
-
- {/* TODO: convert from buttons to radio buttons or checkboxes */} - {/* radio buttons support the single-selection we expect now */} - {/* checkboxes would open up multi-lang projects for the future, but would need - custom handling implemented to ensure only one is selected for now. */} - {/* Write tsx that creates a Button with className project-type-button for each project type in NewProjectType */} - - - +
+ {(() => localize('positronNewProjectWizard.projectTypeStepDescription', 'Select the type of project to create.'))()}
+ setSelectedProjectType(projectType)} + /> + +// Positron modal dialog project type background color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BACKGROUND = registerColor('positronModalDialog.projectTypeBackground', { + dark: buttonSecondaryBackground, + light: darken(editorBackground, 0.05), + hcDark: editorBackground, + hcLight: editorBackground +}, localize('positronModalDialog.projectTypeBackground', "Positron modal dialog project type background color.")); + +// Positron modal dialog project type hover background color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BACKGROUND_HOVER = registerColor('positronModalDialog.projectTypeBackgroundHover', { + dark: listInactiveSelectionBackground, + light: listInactiveSelectionBackground, + hcDark: listHoverBackground, + hcLight: listHoverBackground +}, localize('positronModalDialog.projectTypeBackgroundHover', "Positron modal dialog project type background hover color.")); + +// Positron modal dialog project type background selected color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BACKGROUND_SELECTED = registerColor('positronModalDialog.projectTypeBackgroundSelected', { + dark: listInactiveSelectionBackground, + light: listInactiveSelectionBackground, + hcDark: listHoverBackground, + hcLight: listHoverBackground +}, localize('positronModalDialog.projectTypeBackgroundSelected', "Positron modal dialog project type background selected color.")); + +// Positron modal dialog project type foreground color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_FOREGROUND = registerColor('positronModalDialog.projectTypeForeground', { + dark: editorForeground, + light: editorForeground, + hcDark: editorForeground, + hcLight: editorForeground +}, localize('positronModalDialog.projectTypeForeground', "Positron modal dialog project type foreground color.")); + +// Positron modal dialog project type foreground hover color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_FOREGROUND_HOVER = registerColor('positronModalDialog.projectTypeForegroundHover', { + dark: listHoverForeground, + light: listHoverForeground, + hcDark: listHoverForeground, + hcLight: listHoverForeground +}, localize('positronModalDialog.projectTypeForegroundHover', "Positron modal dialog project type foreground hover color.")); + +// Positron modal dialog project type foreground selected color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_FOREGROUND_SELECTED = registerColor('positronModalDialog.projectTypeForegroundSelected', { + dark: listInactiveSelectionForeground, + light: listInactiveSelectionForeground, + hcDark: listHoverForeground, + hcLight: listHoverForeground +}, localize('positronModalDialog.projectTypeForegroundSelected', "Positron modal dialog project type foreground selected color.")); + +// Positron modal dialog project type border color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BORDER = registerColor('positronModalDialog.projectTypeBorder', { + dark: buttonSecondaryBackground, + light: darken(editorBackground, 0.05), + hcDark: contrastBorder, + hcLight: contrastBorder +}, localize('positronModalDialog.projectTypeBorder', "Positron modal dialog project type border color.")); + +// Positron modal dialog project type border color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BORDER_HOVER = registerColor('positronModalDialog.projectTypeBorderHover', { + dark: darken(editorForeground, 0.25), + light: focusBorder, + hcDark: activeContrastBorder, + hcLight: activeContrastBorder +}, localize('positronModalDialog.projectTypeBorderHover', "Positron modal dialog project type border hover color.")); + +// Positron modal dialog project type border selected color. +export const POSITRON_MODAL_DIALOG_PROJECT_TYPE_BORDER_SELECTED = registerColor('positronModalDialog.projectTypeBorderSelected', { + dark: darken(editorForeground, 0.25), + light: focusBorder, + hcDark: activeContrastBorder, + hcLight: activeContrastBorder +}, localize('positronModalDialog.projectTypeBorderSelected', "Positron modal dialog project type border selected color.")); + // < --- Positron Drop Down --- > // Positron drop down border color.