6.4500 Design for the Web: Languages and User Interfaces

↑ All assignments

Assignment 11

Due

Submitting your homework

We are going to use Github Classroom for this assignment. You need to have an account on GitHub and be logged in. Authorize Github Classroom here and accept the assignment, then follow the instructions there. Please follow the structure and naming of the starter repo, though you can add any additional files if you need them.

To submit the assignment, please visit Canvas and submit the URL to your final commit that you want us to grade. A commit URL looks like https://github.com/designftw-YEAR/hw11-username/commit/b59f14ba05869b3067724aa6d2006667a54c8e7d. You can submit as many times as you want. This is important. Your homework is not submitted and is accruing slack hours until you do this!

To make sure your homework is graded correctly, please follow the following:

If you submit after the deadline, it will count towards your slack hours.

AI Policy

You may use AI for any of the implementations in this assignment. The writeups must be your own.

We have created a markdown "skill" file, graffiti.md, which you can download and feed to your AI agent so that it learns what Graffiti functions it can (and cannot) use.

Exercise 1: Setup Github Pages (10%)

As you work towards completing your chat app, it will be useful to have a live version of the app that you can visit on other devices or share with your friends to test. We will be using Github pages to host your app, which is free and your app will update whenever you push new code to Github.

Follow the Github Pages instructions here. You will need to create a new public repository for your chat app (separate from the homework repository), push your chat app code to that repository, and then enable Github pages for that repository. Once done, you should be able to visit your app at https://<your-github-username>.github.io/<your-repo-name>/.

Note that after the class if you want to continue using your chat app, you could choose to buy a custom domain which you can use instead of Github's domain.

Deliverable: A basic chat-app/index.html file that includes two links, one to your chat app source code, and one to your chat app hosted on Github pages.

Exercise 2: Add client-side routing to your chat app (30%)

Per this week's lecture on single page applications and this week's studio, you will be implementing client-side routing in your app. This should make it possible to build your chat app as one unified application---which is a useful system model for implementation and performance---while still providing an intuitive user model of your app being a website with multiple pages, each of which has its own URL.

Your app should include at least three routes, and one route should be a dyanmic route like the "chat/:chatId" route in studio. Examples of routes you could use include:

Page name Example routes
homepage / or /home
login page / or /login
about page /about
profile page /profile/:actor
profile editor page /profile/edit
chat page /chat/:chatId
chat subpages /chat/:chatId/media, /chat/:chatId/pinned, /chat/:chatId/search, /chat/:chatId/thread/:threadId
new chat page /newchat
message composition page /compose
settings page /settings
contacts page /contacts
explore page /explore
friends page /friends
drafts page /drafts
help page /help

We suggest you finish studio 11 and build off of the studio 11 starter code which sets up Vue Router.

Deliverable: Your chat app linked in chat-app/index.html (same deliverable as Exercise 1) and a brief description of your routes in routes/index.html

Exercise 3: Add a component to your chat app (30%)

Setting up client side routing in exercise 2 involves creating components that represent entire pages. However, components can also be used for more granular features that can be reused within your app. Breaking out features into components will make your code easier to manage and reason about as it gets more complex.

We want you to add at least one such granular component to your app. This component must appear at least twice within your app (it is fine if it only appears once in your code due to the use of a v-for loop). Make a short writeup describing where the component is used and how it works.

Some examples of features that are good candidates for componentization include:

You are allowed to turn a feature you already developed into a dedicated component.

As with exercise 2, see the studio 11 starter code for component boiler plate code.

Deliverable: Your chat app linked in chat-app/index.html (same deliverable as Exercise 1) and your writeup in component/index.html.

Exercise 4: Adding a new feature (30%)

Exercises 1, 2, and 3 are largely about restructuring your code. We want to make sure you are also making progress on your design. For context, you have three homeworks including this one to complete your chat app. Since you started your chat app last week, your work this week is roughly the "halfway point".

This week, make sure you add at least one new feature to your chat app that builds toward your unique design. It is fine if this overlaps with the component/routing exercises, but the feature cannnot be one that was in your submission last week.

As part of your submission you should describe a "user story" that involves your new feature. You should briefly describe a hypothetical user and some task they want to do. Then you should describe the series of steps that the user takes to complete that task, starting from "They open the chat app".

As with your user testing, your high-level task must be non-trivial and should not reference your specific UI. For example, your task for the user might be to "find a message they sent last week to their friend". It should not be for the user to "use the filter feature to query messages by date" - that might be a step they take to complete a task but not their goal itself.

We will be evaluating this exercise based on the usability of the steps described in the user story. We will consider learnability, efficiency, safety, and graphic design. Therefore, the app should feel "complete" within the steps laid out in the story. However, your app can still have incomplete, missing, or placeholder features outside of the user story.

Deliverable: Your chat app linked in chat-app/index.html (same deliverable as Exercise 1) and a write up briefly describing your new feature along with your user story in feature/index.html.

Tip: Uploading files

Some of you may want to add features that involve uploading large files (images, videos, audio, PDFs, etc.). For performance reasons, there is a limit on how large Graffiti objects created with graffiti.post can be. Therefore there is a seperate API for uploading "media":

Media has a max size of 25Mb, which should be fine for most images. For video, you may need to set size limits or compress the video (ask AI how to do this).

The first thing you need to do to upload media is use the browser-native File API to allow the user to select a file from a file picker and store in (local) memory. This can be done with something like:

<!-- template -->
<input type="file" @change="handleFileSelect" accept="image/*">
// setup
const selectedFile = ref(null)
function handleFileSelect(event) {
    const file = event.target.files[0];
    if (file) {
    	selectedFile.value = file;
    }
}

Note that the accept attribute can be used to filter for certain types of files. Here we are accepting all images. You could also accept video (video/*), audio (audio/*), text (text/*), pdf (application/pdf), etc. See here for a list of all "MIME types".

Then you can upload the file with graffiti.postMedia. Importantly, media cannot be assigned to channels so it cannot be "discover"ed like other Graffiti objects. Instead, a link to the media will need to be included in another Graffiti object. For example, to create a profile with a profile picture:

async function createProfile(session) {
	if (!selectedFile.value) {
		return alert("No profile picture!")
	}

	// 1. Upload the picture
    const pictureUrl = await graffiti.postMedia({
        data: selectedFile.value
    }, session);

    // 2. Post a profile object including a link to the picture
    await graffiti.post({
        channels: [session.actor],
        value: {
	            name: "My Full Name",
	            icon: pictureUrl,
	            describes: session.actor
        }
    }, session);
}

In your app, there is a Graffiti component, GraffitiGetMedia, which you can use to display the media, which will correctly display most common types:

<graffiti-get-media
    :url="profile.value.icon"
    :accept="{ types: ['image/*'] }"
></graffiti-get-media>

Alternatively, if you want control over the media you could do:

<graffiti-get-media
	v-slot="{ media }"
    :url="profile.value.icon"
    :accept="{ types: ['image/*'] }"
>
	<img :src="media.dataUrl"/>
</graffiti-get-media>

or use it in your setup with useGraffitiGetMedia:

const { media } = useGraffitiGetMedia(
	profile.value.icon,
	{ types: ['image/*'] }
);
const blob = media.data; // The raw data

Exercise N: HW11 feedback

Since this is a new class, we need your constructive feedback about every aspect of it: lectures, homeworks, labs etc.

Please fill in your feedback about HW11 in this form. You can edit it as many times as you like until the survey closes (48 hours after the homework deadline). Since this is part of your participation grade, it does not affect your slack hours, but failing to submit the form on time, could result in a lower participation grade.

← Assignment 10 Assignment 12 →