From 677f8436f7b8ac19032e7b2092b767e975b833ab Mon Sep 17 00:00:00 2001 From: Ram Modhvadia Date: Mon, 17 Aug 2026 08:26:35 +0100 Subject: [PATCH 1/3] add projects-ui sample with theme --- src/projects/projects-ui.json | 186 +++++++++++++++++++++++++++ src/projects/themes/projects-ui.css | 189 ++++++++++++++++++++++++++++ web-component.html | 27 ++++ 3 files changed, 402 insertions(+) create mode 100644 src/projects/projects-ui.json create mode 100644 src/projects/themes/projects-ui.css diff --git a/src/projects/projects-ui.json b/src/projects/projects-ui.json new file mode 100644 index 000000000..42b4b8ca6 --- /dev/null +++ b/src/projects/projects-ui.json @@ -0,0 +1,186 @@ +{ + "identifier": "projects-ui", + "project_type": "python", + "locale": "en", + "name": "Projects UI", + "user_id": null, + "instructions": [ + { + "quiz": false, + "title": "Print Hello", + "content": "

Print Hello

\n\n

โžก๏ธ Display the word โ€˜Helloโ€™ on the screen.

\n\n

In Python, print() outputs strings (words or numbers) to the screen.

\n\n

Type the code to print() Hello to the screen:

\n\n\n
\n\n# Put code to run under here.\nprint(f'Hello')\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code.

\n\n
Hello\n
\n\n
\n\n

Tip

\n

When you type an opening bracket ( the code editor will automatically add a closing bracket ).
\nThis also happens when you type an opening apostrophe '.

\n\n
\n\n
\n\n

Debugging

\n

If you get an error then check your code really carefully. Check there are single quotes around Hello so Python knows it is meant to be text.

\n\n
\n\n

Click the Run button and check that Hello appears in the output.

\n", + "position": 0, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Variables", + "content": "

Variables

\n\n

We have included some variables that store emoji characters.

\n\n
\n\n

Tip

\n

A variable is used to store values such as text or numbers. Choosing a sensible name for a variable makes it easier for you to remember what it is for.

\n\n
\n\n\n
\n\n# variables\nworld = '๐ŸŒ๐ŸŒŽ๐ŸŒ'\npython = 'Python ๐Ÿ'\nfire = '๐Ÿ”ฅ'\n\n# Function definitions\n  \n# Put code to run under here\nprint(f'Hello')\n\n
\n\n

Now run your code

\n\n

Click the Run button and check that the output still says Hello.

\n", + "position": 1, + "challenge": false, + "completion": [ + "engaged" + ], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Print variables", + "content": "

Print variables

\n\n

โžก๏ธ Print the contents of a variable.

\n\n

Change your code to also print() the contents of the world variable. You can do this by adding the variable name in curly brackets {}.

\n\n\n
\n\n# variables\nworld = '๐ŸŒ๐ŸŒŽ๐ŸŒ'\npython = 'Python ๐Ÿ'\nfire = '๐Ÿ”ฅ'\n\n# Function definitions        \n  \n# Put code to run under here\nprint(f'Hello {world}')\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\n
\n\n
\n\n

Tip

\n

The f character inside the print lets you easily print variables along with strings of text.

\n\n
\n\n
\n\n

Debugging

\n

If you get an error then check you have opened and closed all your brackets () and curly brackets {}.

\n\n
\n\n

Click the Run button and check that Hello is followed by the globe emojis.

\n", + "position": 2, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Print another variable", + "content": "

Print another variable

\n\n

Add another line to your code to print() more text and emojis:

\n\n\n
\n\n# Put code to run under here\nprint(f'Hello {world}')\nprint(f'Welcome to {python}')\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\n
\n\n

Click the Run button and check that the output has two lines: Hello with the globe emojis and Welcome to Python ๐Ÿ.

\n", + "position": 3, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Operators", + "content": "

Operators

\n\n

In Python you can work with numbers and dates.

\n\n

You can use arithmetic operators such as + and - to do calculations:

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
+add
-subtract
*multiply
/divide
**exponent
\n\n

Now run your code

\n\n

Click the Run button and check that the output is still the same as in the previous step, because you have not added any new code yet.

\n", + "position": 4, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Create a calculation", + "content": "

Create a calculation

\n\n

โžก๏ธ Print the value of a calculation.

\n\n

Add two more print() lines to your code including a multiplication for Python to calculate:

\n\n\n
\n\n# Put code to run under here\nprint(f'Hello {world}')\nprint(f'Welcome to {python}')\nprint(f'{python} is good at maths!')\nprint(f'{111111111 * 111111111}')\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\n
\n\n
\n\n

Tip

\n

Python uses the same rules for calculations as you might have learned at school. Brackets first, then Orders, Division, Multiplication, Addition, and lastly Subtraction.

\n\n
\n\n
\n\n

Debugging

\n

Donโ€™t forget that the UPPERCASE and lowercase letters are important in Python. Always check you are using the correct case.

\n\n
\n\n

Click the Run button and check that your program now prints a maths message and a large number on the next line.

\n", + "position": 5, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Using modules", + "content": "

Using modules

\n\n

โžก๏ธ Import the datetime module.

\n\n

Python has many modules that you can use in your code to help perform certain tasks. To use a module, you first need to import it.

\n\n

The datetime module helps with writing code that uses dates and times.

\n\n\n
\n\n# imports\nfrom datetime import datetime\n\n# variables\n\n
\n\n

When you run this code, nothing should change, and you should have the same output as the previous step.

\n\n
\n\n

Tip

\n

Any text you write in Python with a # in front of it becomes a comment. These lines wonโ€™t run, so they can be useful to help people read and understand your code.

\n\n
\n\n
\n\n

Debugging

\n

Check that you have spelled datetime correctly, and it is all lowercase.

\n\n
\n\n

Now run your code

\n\n

Run your code and check that the output stays the same as in the previous step after importing datetime.

\n", + "position": 6, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Print the date", + "content": "

Print the date

\n\n

โžก๏ธ Display the current date and time.

\n\n

Add another line to your code to print the current date and time.

\n\n

Get the current date and time by using the now() function from the datetime module:

\n\n\n
\n\nprint(f'{python} is good at maths!')\nprint(f'{111111111 * 111111111}')\nprint(f'The date and time is {datetime.now()}')\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code, but the date and time will be different.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 15:34:10.148000\n
\n\n
\n\n

Debugging

\n

Check all your brackets () and curly brackets {} to make sure they are all opened and closed in the correct place.

\n\n
\n\n

Click the Run button and check that the output now includes a line that starts with The date and time is, followed by the current date and time.

\n", + "position": 7, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Functions", + "content": "

Functions

\n\n

Functions are blocks of code that perform specific tasks.

\n\n

They can be used over and over again.

\n\n

Here is an example of a function:

\n\n
\n# Function definitions\ndef add_one_and_one():\n    x = 1 + 1\n    print(x)\n\n
\n\n

The name of this function is add_one_and_one.

\n\n

The code for the task you want the function to do needs to be indented, which means that you need to add four spaces before each line of code.

\n\n

Calling a function runs the code inside it. You call a function by using its name. In this case add_one_and_one().

\n\n

Now run your code

\n\n

Run your code and check that nothing new is printed yet, because the function has been defined but not called.

\n", + "position": 8, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Roll dice", + "content": "

Roll dice

\n\n

โžก๏ธ Create a function to simulate rolling a dice.

\n\n

Create a function called roll_dice() that prints out the number 4.

\n\n\n
\n\n# Function definitions        \ndef roll_dice():\n    print(f'You rolled a {4}')\n    \n# Put code to run under here\n\n
\n\n

Then, call the function at the bottom of your code.

\n\n\n
\nprint(f'The date and time is {datetime.now()}')\nroll_dice()\n\n
\n\n

Now run your code

\n\n

This is what you should see when you run your code.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 15:55:33.038000\nYou rolled a 4\n
\n\n
\n\n

Tip

\n

You can use the Tab key on your keyboard to insert 4 spaces. Pressing Shift and Tab will remove the 4 spaces.

\n\n
\n\n
\n\n

Debugging

\n

Check that you have brackets () and a colon : at the end of your function definition. Also check you are using brackets () when you call your function.

\n\n
\n\n

Click the Run button and check that the last line says You rolled a 4.

\n", + "position": 9, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Import randint", + "content": "

Import randint

\n\n

โžก๏ธ Import the randint function from the random module.

\n\n

Another module called random can be used to create random numbers.

\n\n\n
\n\n# imports\nfrom datetime import datetime\nfrom random import randint\n\n
\n\n

Your code output will not change when you run it.

\n\n

Now run your code

\n\n

Run your code and check that the output stays the same as in the previous step after importing randint.

\n", + "position": 10, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Random numbers", + "content": "

Random numbers

\n\n

โžก๏ธ Choose a random number for the dice roll.

\n\n

Use the randint function you imported to choose a random number between 1 and 6 for the dice roll.

\n\n\n
\n\n# Function definitions \ndef roll_dice():\n    print(f'You rolled a {randint(1, 6)}')\n    \n
\n\n

Now run your code

\n\n

Now when you run your code, a new random number between 1 and 6 will be chosen each time.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 16:02:12.535000\nYou rolled a 6\n
\n\n
\n\n

Tip

\n

randint is short for random integer. Integers are whole numbers.

\n\n
\n\n
\n\n

Debugging

\n

Check your brackets and curly brackets if you get an error. Take note that the same number might be chosen over and over again. Itโ€™s random!

\n\n
\n\n

Click the Run button and check that the last line says You rolled a followed by a number from 1 to 6.

\n", + "position": 11, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Multiply strings", + "content": "

Multiply strings

\n\n

โžก๏ธ Multiply the number by the ๐Ÿ”ฅ emoji to print the emoji a number of times equal to the dice roll.

\n\n

In Python you can multiply strings such as emojis or whole words by a number, so they print out several times.

\n\n

Store the random number in a variable called roll.

\n\n\n
\n\n# Function definitions        \ndef roll_dice():\n    roll = randint(1,6)\n\n
\n\n

Multiply the random number stored in roll by the ๐Ÿ”ฅ emoji, and print the result.

\n\n\n
\n\n# Function definitions        \ndef roll_dice():\n    roll = randint(1,6)\n    print(f'You rolled a {roll} {fire * roll}')\n    \n
\n\n

Now run your code

\n\n

Your output code should look something like this:

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 16:14:45.140000\nYou rolled a 4 ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ\n
\n\n
\n\n

Debugging

\n

Check all your brackets are the same as the code example above.

\n\n
\n\n

Click the Run button and check that the last line shows the dice number and the same number of fire emojis.

\n", + "position": 12, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Get input", + "content": "

Get input

\n\n

โžก๏ธ Allow the person using your program to type in some input.

\n\n

You can use input() to ask the person using your program to enter text, and save it as a variable.

\n\n\n
\n\n# Function definitions\ndef roll_dice():\n    max = input('How many sides on your dice?:')\n    print(f'That is a D {max}')\n    roll = randint(1,6)\n    print(f'You rolled a {roll} {fire * roll}')\n\n
\n\n

Now run your code

\n\n

Ensure you press the Enter key after inputting how many sides.
\nThis is what you should see when you run your code.

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 16:20:41.323000\nHow many sides on your dice?:\n20 \nThat is a D 20\nYou rolled a 1 ๐Ÿ”ฅ\n
\n\n

Click the Run button, type a number such as 20, and check that the program says That is a D 20 before showing a dice roll.

\n", + "position": 13, + "challenge": false, + "completion": [], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Change the dice", + "content": "

Change the dice

\n\n

โžก๏ธ Generate a random number between 1 and the number of sides the user typed in.

\n\n

Inputs are always stored as text, but we need to use the input stored in max to specify the largest number that could be rolled.

\n\n

max is a string, so it needs changing to an integer int().

\n\n\n
\n\n# Function definitions        \ndef roll_dice():\n    max = input('How many sides on your dice?:')\n    print(f'That is a D {max}')\n    roll = randint(1, int(max))\n    print(f'You rolled a {roll} {fire * roll}')\n    \n
\n\n

Now run your code

\n\n

This is what you should see:

\n\n
Hello ๐ŸŒ๐ŸŒŽ๐ŸŒ\nWelcome to Python ๐Ÿ\nPython ๐Ÿ is good at maths!\n12345678987654321\nThe date and time is 2023-11-21 16:27:24.101000\nHow many sides on your dice?:12\nThat is a D 12\nYou rolled a 5 ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ\n
\n\n
\n\n

Tip

\n

Changing one type of data to another type of data is called type casting.

\n\n
\n\n

Click the Run button, type a number of sides, and check that the dice roll can be any number from 1 up to the number you entered.

\n", + "position": 14, + "challenge": false, + "completion": [ + "internal" + ], + "ingredients": [], + "knowledgeQuiz": {} + }, + { + "quiz": false, + "title": "Over to you", + "content": "

Over to you

\n\n

โžก๏ธ Practice adding more print lines to your code.

\n\n

Here are some sentence starters that you can use:

\n\n\n
\n\nroll_dice()\nprint(f'I โค๏ธ ...')   \nprint(f'... makes me ๐Ÿ˜ƒ')   \nprint(f'I would like to make ... with {python}')\n\n
\n\n
\n\n

Tip

\n

Here is a list of some emojis you might like to use:

\n\n

๐ŸŽŠ ๐Ÿ™Œ ๐Ÿ™Œ๐Ÿผ ๐Ÿ™Œ๐Ÿฝ ๐Ÿ™Œ๐Ÿพ ๐Ÿ™Œ๐Ÿฟ ๐Ÿ˜ƒ ๐Ÿ•’ ๐ŸŽจ ๐ŸŽฎ ๐Ÿ”ฌ ๐ŸŽ‰ ๐Ÿ•ถ๏ธ ๐ŸŽฒ ๐Ÿ˜Š
\n๐Ÿฆ„ ๐Ÿš€ ๐Ÿ’ฏ โญ ๐Ÿ’› โค๏ธ ๐Ÿ“š โšฝ ๐Ÿ ๐Ÿ€ ๐Ÿฅ‹ ๐Ÿ† โœจ ๐Ÿฅบ ๐ŸŒˆ ๐Ÿ”ฅ โ™ป๏ธ ๐ŸŒณ
\n๐Ÿ‘ฉโ€๐Ÿฆฝ๐Ÿ‘ฉ๐Ÿผโ€๐Ÿฆฝ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿฆฝ๐Ÿ‘ฉ๐Ÿพโ€๐Ÿฆฝ๐Ÿ‘ฉ๐Ÿฟโ€๐Ÿฆฝ๐Ÿง˜ ๐Ÿง˜๐Ÿผ ๐Ÿง˜๐Ÿฝ ๐Ÿง˜๐Ÿพ ๐Ÿง˜๐Ÿฟ ๐Ÿ™‹ ๐Ÿ™‹๐Ÿผ ๐Ÿ™‹๐Ÿฝ ๐Ÿ™‹๐Ÿพ ๐Ÿ™‹๐Ÿฟ

\n\n

You can copy and paste them into your code.

\n\n
\n\n

Now run your code

\n\n

Click the Run button and check that your extra print lines show your own words and emojis after the dice roll.

\n", + "position": 15, + "challenge": false, + "completion": [ + "external" + ], + "ingredients": [], + "knowledgeQuiz": {} + } + ], + "components": [ + { + "id": "42b4cdc9-d935-4a3d-b39a-32eb44c5ebfd", + "name": "main", + "extension": "py", + "content": "print(\"Hello World\")" + } + ], + "image_list": [], + "videos": [], + "audio": [] +} diff --git a/src/projects/themes/projects-ui.css b/src/projects/themes/projects-ui.css new file mode 100644 index 000000000..275402343 --- /dev/null +++ b/src/projects/themes/projects-ui.css @@ -0,0 +1,189 @@ +#root { + --cc-blue: hsl(238deg 39% 45% / 100%); + --cc-burgundy: hsl(332deg 48% 26% / 100%); + --cc-cyan: hsl(199deg 74% 54% / 100%); + --cc-dark-green: hsl(166deg 68% 7% / 100%); + --cc-green: hsl(129deg 47% 48% / 100%); + --cc-grey: hsl(237deg 17% 26% / 100%); + --cc-light-yellow: hsl(56deg 88% 78% / 100%); + --cc-off-white: hsl(36deg 38% 95% / 100%); + --cc-orange: hsl(13deg 87% 61% / 100%); + --cc-pink: #f767ab; + --cc-raspberry: var(--rpf-brand-raspberry); + --cc-yellow: hsl(53deg 100% 50% / 100%); + --cc-light-cyan: hsl(199deg 100% 87% / 100%); + --cc-light-green: var(--cc-green-200); + --cc-light-lilac: hsl(239deg 87% 88% / 100%); + --cc-light-orange: hsl(13deg 89% 89% / 100%); + --cc-light-pink: hsl(333deg 100% 91% / 100%); + --cc-pale-cyan: hsl(198deg 91% 96% / 100%); + --cc-pale-green: hsl(127deg 100% 96% / 100%); + --cc-pale-lilac: hsl(240deg 100% 96% / 100%); + --cc-pale-orange: hsl(13deg 100% 97% / 100%); + --cc-pale-pink: hsl(332deg 100% 97% / 100%); + --cc-green-50: hsl(130deg 43% 97% / 100%); + --cc-green-100: hsl(130deg 46% 95% / 100%); + --cc-green-200: hsl(129deg 58% 83% / 100%); + --cc-green-300: hsl(129deg 44% 69% / 100%); + --cc-green-400: hsl(129deg 45% 59% / 100%); + --cc-green-500: var(--cc-green); + --cc-green-600: hsl(129deg 47% 39% / 100%); + --cc-green-700: hsl(129deg 47% 29% / 100%); + + --editor-primary-theme: var(--cc-green); + --editor-secondary-theme: var(--rpf-off-white); + + --code-syntax-1: #005818; + --code-syntax-2: #9d0808; + --code-syntax-3: rgb(153 68 0); + --code-syntax-4: rgb(119 0 136); + --code-syntax-5: rgb(0 0 255); + --code-print-color: var(--rpf-black); + --code-background-color: var(--rpf-white); + --code-block-border-color: var(--rpf-grey-300); + --code-block-line-highlight-color: #ecf8ff; + --code-block-line-highlight-border: 4px solid; + --code-block-line-highlight-border-color: var(--rpf-navy-800); + --code-block-blend-mode: multiply; + --code-text-color: var(--rpf-grey-600); + --code-block-scrollbar-color: var(--rpf-grey-400) var(--rpf-white); + --display-step-counter: flex; + --editor-color-layer-1: var(--rpf-navy-100); + --editor-color-layer-2: var(--rpf-white); + --editor-color-layer-3: var(--rpf-white); + --editor-color-outline: var(--rpf-grey-150); + --editor-color-theme: var(--rpf-black); + --editor-color-theme-secondary: var(--rpf-navy-800); + --editor-color-theme-tertiary: var(--rpf-navy-100); + --editor-color-text: var(--rpf-text-primary); + --editor-color-text-secondary: var(--rpf-text-secondary); + --editor-font-family-sans-serif: lexend, sans-serif; + --editor-htmlrunner-link-display: none; + --editor-logo-display: none; + --project-wrapper-grid-gap: var(--space-2); + --project-editor-wrapper-grid-gap: var(--space-2); + --project-instructions-padding: var(--space-0-5); + --rpf-button-primary-background-color: var(--rpf-black); + --rpf-button-primary-background-color-focus: var(--rpf-black); + --rpf-button-primary-background-color-hover: var(--rpf-grey-800); + --rpf-button-primary-background-color-active: var(--rpf-black); + --rpf-button-primary-background-color-disabled: var(--rpf-navy-200); + --rpf-button-primary-text-color: var(--rpf-white); + --rpf-button-secondary-background-color: var(--rpf-white); + --rpf-button-secondary-background-color-focus: var(--rpf-white); + --rpf-button-secondary-text-color-hover: var(--rpf-grey-600); + --rpf-button-secondary-background-color-active: var(--rpf-grey-600); + --rpf-button-secondary-background-color-disabled: var(--rpf-white); + --rpf-button-secondary-background-color-hover: var(--rpf-grey-50); + --rpf-button-secondary-text-color: var(--rpf-black); + --rpf-button-tertiary-text-color-hover: var(--rpf-grey-600); + --rpf-files-list-item-active: var(--cc-green-200); + --rpf-files-list-item-hover: var(--cc-green-100); + --rpf-input-active-border: var(--editor-color-theme); + --rpf-primary-button-radius: var(--space-10); + --rpf-secondary-button-radius: var(--space-10); + --step-buttons-radius: var(--space-2); + --progress-bar-color: var(--rpf-black); + --project-bar-button-radius: var(--space-10); + --rpf-select-buttons-tick-color: var(--rpf-white); + --rpf-tab-button-background: var(--rpf-off-white); + --rpf-tab-button-hover: var(--rpf-grey-100); + --rpf-tab-border-bottom-selected: var(--rpf-black); + --sidebar-background-selected: var(--rpf-off-white); + --sidebar-border: var(--rpf-grey-150); + --sidebar-border-obscurer-width: 2px; + --sidebar-panel-background: var(--rpf-white); + --sidebar-options-alignment: normal; + --sidebar-footer-padding: 0; + --sidebar-option-hover: var(--rpf-grey-100); + --sidebar-option-selected-border: var(--cc-green-600); + --sidebar-option-selected-background: var(--cc-green-50); + --sidebar-option-selected-background-hover: var(--cc-green-100); + --sidebar-option-selected-icon: var(--cc-green-700); + --tertiary-btn-hover-color: var(--cc-green-100); + + block-size: 100%; + flex: 1 1 auto; +} + +/* + * Theme overrides for editor-wc shadow DOM. + * + * Required since editor-ui 8d1f514: InternalStyles.scss now sets theme tokens + * on #wc.--light, which overrides values inherited from ::part(editor-root). + * + * Injected via host_styles (must use #root #wc for sufficient specificity). + * Keep in sync with ::part(editor-root) in Editor.scss. + */ + +/* stylelint-disable selector-class-pattern */ +#root #wc.--light { + /* Theme colours */ + --editor-color-layer-1: var(--rpf-navy-100); + --editor-color-layer-2: var(--rpf-white); + --editor-color-layer-3: var(--rpf-white); + --editor-color-outline: var(--rpf-grey-150); + --editor-color-theme: var(--rpf-black); + --editor-color-theme-secondary: var(--rpf-navy-800); + --editor-color-theme-tertiary: var(--rpf-navy-100); + --editor-color-text: var(--rpf-text-primary); + --editor-color-text-secondary: var(--rpf-text-secondary); + + /* File list & tabs */ + --rpf-files-list-item-active: var(--cc-green-200); + --rpf-files-list-item-hover: var(--cc-green-100); + --rpf-tab-button-background: var(--rpf-off-white); + --rpf-tab-button-hover: var(--rpf-grey-100); + --rpf-tab-border-bottom-selected: var(--rpf-black); + + /* Sidebar */ + --sidebar-background-selected: var(--rpf-off-white); + --sidebar-border: var(--rpf-grey-150); + --sidebar-panel-background: var(--rpf-white); + --sidebar-option-hover: var(--rpf-grey-100); + --sidebar-option-selected-border: var(--cc-green-600); + --sidebar-option-selected-background: var(--cc-green-50); + --sidebar-option-selected-background-hover: var(--cc-green-100); + --sidebar-option-selected-icon: var(--cc-green-700); +} + +/* Button tokens are scoped to .btn / .rpf-button in InternalStyles */ +#root #wc.--light .btn, +#root #wc.--light .rpf-button { + --rpf-button-background-color: var(--rpf-black); + --rpf-button-border-radius: var(--space-10); + --rpf-button-primary-background-color: var(--rpf-black); + --rpf-button-primary-background-color-focus: var(--rpf-black); + --rpf-button-primary-background-color-hover: var(--rpf-grey-800); + --rpf-button-primary-background-color-active: var(--rpf-black); + --rpf-button-primary-background-color-disabled: var(--rpf-navy-200); + --rpf-button-primary-text-color: var(--rpf-white); + --rpf-button-secondary-background-color: var(--rpf-white); + --rpf-button-secondary-background-color-focus: var(--rpf-white); + --rpf-button-secondary-background-color-hover: var(--rpf-grey-50); + --rpf-button-secondary-background-color-active: var(--rpf-grey-600); + --rpf-button-secondary-background-color-disabled: var(--rpf-white); + --rpf-button-secondary-border-color-hover: none; + --rpf-button-secondary-text-color: var(--rpf-black); + --rpf-button-tertiary-text-color-hover: var(--rpf-grey-600); +} + +#root #wc.--light .rpf-button { + &:hover { + --rpf-button-background-color-hover: var(--rpf-grey-800); + } +} + +/* + * Optional โ€” only needed if projects-ui ever supports dark mode on editor-wc. + * Adjust values to match your dark theme before enabling. + * +#root #wc.--dark { + --editor-color-theme: var(--cc-green-600); + --sidebar-option-selected-background: var(--cc-green-950); + --sidebar-option-selected-background-hover: var(--cc-green-900); + --sidebar-option-selected-border: var(--cc-green-400); + --sidebar-option-selected-icon: var(--cc-green-300); +} + */ +/* stylelint-enable selector-class-pattern */ diff --git a/web-component.html b/web-component.html index 4d8756389..d4f8fd322 100644 --- a/web-component.html +++ b/web-component.html @@ -84,6 +84,7 @@ python-plotly cool-scratch astro-pi + projects-ui
@@ -103,11 +104,21 @@ return await res.text(); }; + const loadThemeByName = async (projectName) => { + const url = new URL( + `projects/themes/${projectName}.css`, + window.location.href, + ); + const res = await fetch(url, { cache: "no-store" }); + return await res.text(); + }; + document.addEventListener("DOMContentLoaded", async (e) => { const queryParams = new URLSearchParams(window.location.search); const projectName = queryParams.get("project"); const initialProject = projectName && (await loadSampleProjectByName(projectName)); + const themeText = projectName && (await loadThemeByName(projectName)); let webComp; @@ -174,6 +185,22 @@ newWebComp.setAttribute("initial_project", initialProject); } + if (projectName == "projects-ui") { + newWebComp.setAttribute("editable_instructions", "false"); + newWebComp.setAttribute( + "sidebar_options", + JSON.stringify([ + "instructions", + "file", + "images", + "download", + "settings", + "info", + ]), + ); + newWebComp.setAttribute("host_styles", JSON.stringify([themeText])); + } + return newWebComp; }; From 34bb7aa6618175b876adbed96bc3a716ffdcb9bb Mon Sep 17 00:00:00 2001 From: Ram Modhvadia Date: Mon, 17 Aug 2026 08:42:13 +0100 Subject: [PATCH 2/3] clean up and fixes from claude review --- web-component.html | 55 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/web-component.html b/web-component.html index d4f8fd322..b5952bda4 100644 --- a/web-component.html +++ b/web-component.html @@ -7,7 +7,8 @@ Editor Web component