Compare commits

...

5 Commits

Author SHA1 Message Date
Diego Perez
3912732968 Merge branch 'main' into copilot/bump-chromatic-version 2026-02-13 00:04:20 -06:00
f8c2788d86 feat: exporting to txt again (#733)
* feat: initial functions for exporting to txt

* feat: add save as text to calendar header new export option

* docs: comment for saveAsText()

* feat: generate text line by line for each course

* docs: jsdoc

* chore: lint

* Apply suggestion from @doprz

---------

Co-authored-by: Diego Perez <52579214+doprz@users.noreply.github.com>
2026-02-12 23:52:00 -06:00
copilot-swe-agent[bot]
f240e39419 chore: update pnpm-lock.yaml after chromatic bump
Co-authored-by: Razboy20 <29903962+Razboy20@users.noreply.github.com>
2026-02-12 04:12:06 +00:00
copilot-swe-agent[bot]
1df0116514 chore: bump chromatic from 11.26.0 to 15.1.0
Co-authored-by: Razboy20 <29903962+Razboy20@users.noreply.github.com>
2026-02-12 04:09:17 +00:00
copilot-swe-agent[bot]
dc9984ab61 Initial plan 2026-02-12 04:06:59 +00:00
4 changed files with 79 additions and 13 deletions

View File

@@ -111,7 +111,7 @@
"@vitest/coverage-v8": "^2.1.9", "@vitest/coverage-v8": "^2.1.9",
"@vitest/ui": "^2.1.9", "@vitest/ui": "^2.1.9",
"chalk": "^5.4.1", "chalk": "^5.4.1",
"chromatic": "^11.26.0", "chromatic": "^15.1.0",
"cssnano": "^7.0.6", "cssnano": "^7.0.6",
"cssnano-preset-advanced": "^7.0.6", "cssnano-preset-advanced": "^7.0.6",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",

34
pnpm-lock.yaml generated
View File

@@ -261,8 +261,8 @@ importers:
specifier: ^5.4.1 specifier: ^5.4.1
version: 5.4.1 version: 5.4.1
chromatic: chromatic:
specifier: ^11.26.0 specifier: ^15.1.0
version: 11.26.0 version: 15.1.0
cssnano: cssnano:
specifier: ^7.0.6 specifier: ^7.0.6
version: 7.0.6(postcss@8.5.3) version: 7.0.6(postcss@8.5.3)
@@ -3210,8 +3210,20 @@ packages:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'} engines: {node: '>= 14.16.0'}
chromatic@11.26.0: chromatic@11.29.0:
resolution: {integrity: sha512-3rRiPmdnt5sbYZTlr6Uqd11S/teafQA1Dr6mCddIz/FFKYPv/Yt26nJllixyFd9VUwrILMPTyuracUIgJ77VZA==} resolution: {integrity: sha512-yisBlntp9hHVj19lIQdpTlcYIXuU9H/DbFuu6tyWHmj6hWT2EtukCCcxYXL78XdQt1vm2GfIrtgtKpj/Rzmo4A==}
hasBin: true
peerDependencies:
'@chromatic-com/cypress': ^0.*.* || ^1.0.0
'@chromatic-com/playwright': ^0.*.* || ^1.0.0
peerDependenciesMeta:
'@chromatic-com/cypress':
optional: true
'@chromatic-com/playwright':
optional: true
chromatic@15.1.0:
resolution: {integrity: sha512-XODNgiczeX5SpaWsCQLEwGpXrF2QVPb9bka7nHa8NQssyRRTt9EI8jVH8BRDUPcrQKqQqmXmxOy2Cq4IK1ydFQ==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@chromatic-com/cypress': ^0.*.* || ^1.0.0 '@chromatic-com/cypress': ^0.*.* || ^1.0.0
@@ -6201,8 +6213,8 @@ packages:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true hasBin: true
react-confetti@6.2.3: react-confetti@6.4.0:
resolution: {integrity: sha512-Jt6Fy3jE7FrpKxeDQ3oh36Bz6LoYt4o+vU578ghuF//NxADlcauDYvWr24S8hHKnQ90Uv01XXOngnKVBdZ73zQ==} resolution: {integrity: sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==}
engines: {node: '>=16'} engines: {node: '>=16'}
peerDependencies: peerDependencies:
react: ^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 react: ^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0
@@ -7660,10 +7672,10 @@ snapshots:
'@chromatic-com/storybook@2.0.2(react@18.3.1)': '@chromatic-com/storybook@2.0.2(react@18.3.1)':
dependencies: dependencies:
chromatic: 11.26.0 chromatic: 11.29.0
filesize: 10.1.6 filesize: 10.1.6
jsonfile: 6.1.0 jsonfile: 6.1.0
react-confetti: 6.2.3(react@18.3.1) react-confetti: 6.4.0(react@18.3.1)
strip-ansi: 7.1.0 strip-ansi: 7.1.0
transitivePeerDependencies: transitivePeerDependencies:
- '@chromatic-com/cypress' - '@chromatic-com/cypress'
@@ -10593,7 +10605,9 @@ snapshots:
dependencies: dependencies:
readdirp: 4.1.2 readdirp: 4.1.2
chromatic@11.26.0: {} chromatic@11.29.0: {}
chromatic@15.1.0: {}
chrome-trace-event@1.0.4: {} chrome-trace-event@1.0.4: {}
@@ -14036,7 +14050,7 @@ snapshots:
minimist: 1.2.8 minimist: 1.2.8
strip-json-comments: 2.0.1 strip-json-comments: 2.0.1
react-confetti@6.2.3(react@18.3.1): react-confetti@6.4.0(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
tween-functions: 1.2.0 tween-functions: 1.2.0

View File

@@ -1,5 +1,5 @@
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'; import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react';
import { CalendarDots, Export, FileCode, FilePng, Sidebar } from '@phosphor-icons/react'; import { CalendarDots, Export, FileCode, FilePng, FileText, Sidebar } from '@phosphor-icons/react';
import styles from '@views/components/calendar/CalendarHeader/CalendarHeader.module.scss'; import styles from '@views/components/calendar/CalendarHeader/CalendarHeader.module.scss';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider'; import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
@@ -11,7 +11,7 @@ import useSchedules from '@views/hooks/useSchedules';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { handleExportJson, saveAsCal, saveCalAsPng } from '../utils'; import { handleExportJson, saveAsCal, saveAsText, saveCalAsPng } from '../utils';
interface CalendarHeaderProps { interface CalendarHeaderProps {
sidebarOpen?: boolean; sidebarOpen?: boolean;
@@ -111,6 +111,18 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
Save as .json Save as .json
</Button> </Button>
</MenuItem> </MenuItem>
<MenuItem>
<Button
className='w-full flex justify-start'
onClick={saveAsText}
color='ut-black'
size='small'
variant='minimal'
icon={FileText}
>
Save as .txt
</Button>
</MenuItem>
{/* <MenuItem> {/* <MenuItem>
<Button color='ut-black' size='small' variant='minimal' icon={FileTxt}> <Button color='ut-black' size='small' variant='minimal' icon={FileTxt}>
Export Unique IDs Export Unique IDs

View File

@@ -245,6 +245,27 @@ export const scheduleToIcsString = (schedule: Serialized<UserSchedule>) => {
return icsString; return icsString;
}; };
/**
* Returns the provided schedule in a human readable/copyable text format
* @param schedule - The schedule object
* @returns
*/
export const scheduleToText = (schedule: Serialized<UserSchedule>) => {
const lines: string[] = [];
lines.push(`Schedule: ${schedule.name}`);
lines.push('');
for (const c of schedule.courses) {
lines.push(c.fullName);
lines.push(`${c.creditHours} Credit Hours`);
lines.push(`${c.uniqueId}`);
lines.push('');
}
return lines.join('\n');
};
/** /**
* Saves the current schedule as a calendar file in the iCalendar format (ICS). * Saves the current schedule as a calendar file in the iCalendar format (ICS).
* Fetches the current active schedule and converts it into an ICS string. * Fetches the current active schedule and converts it into an ICS string.
@@ -262,6 +283,25 @@ export const saveAsCal = async () => {
downloadBlob(icsString, 'CALENDAR', 'schedule.ics'); downloadBlob(icsString, 'CALENDAR', 'schedule.ics');
}; };
/**
* Save current schedule as a plain text file consisting of
* Course Name - Course ID
* Course Time
* Unique Number
* Line Break
* Repeat
*/
export const saveAsText = async () => {
const schedule = await getSchedule();
if (!schedule) {
throw new Error('No schedule found');
}
const scheduleText = scheduleToText(schedule);
downloadBlob(scheduleText, 'TEXT', 'schedule.txt');
};
/** /**
* Saves current schedule to JSON that can be imported on other devices. * Saves current schedule to JSON that can be imported on other devices.
* @param id - Provided schedule ID to download * @param id - Provided schedule ID to download