Skip to content

Commit

Permalink
Merge pull request #15 from nih-sparc/feature_distribution-graph
Browse files Browse the repository at this point in the history
Finalize V1 Styles
  • Loading branch information
SamanthaKraft authored Jul 22, 2024
2 parents f65d284 + ac10307 commit bdba289
Show file tree
Hide file tree
Showing 16 changed files with 318 additions and 170 deletions.
212 changes: 131 additions & 81 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The test dashboard is part of the Sparc Portal and is meant to compare various v
View the storybook of working components here
https://nih-sparc.github.io/TestDashboard/?path=/docs/components-biolucidaviewer--docs

Dev version here
https://sparc-app-2-dev-features-2a5a06b8ea5c.herokuapp.com/apps/dashboard

## Recommended IDE Setup

[VSCode](https://code.visualstudio.com/)
Expand Down Expand Up @@ -50,9 +53,8 @@ Yarn run lint

## Dependency Setup

If you are installing this project as a node module dependency you need the following installed in your project.
If you are installing this project as a node module [npm](https://www.npmjs.com/package/sparc-dashboard-beta) dependency you need the following installed in your project.
Vue(^3.3.4), Pinia(^2.1.7), mitt (^3.0.1), sparc-design-system-components-2 (0.0.26)

```sh
yarn add pina
yarn add vue
Expand All @@ -69,15 +71,13 @@ import App from './App.vue'
import { createPinia } from 'pinia';
import 'sparc-dashboard-beta/dist/style.css'
import sparcDesignSystemComponents2Umd from 'sparc-design-system-components-2';
import {default as SparcDashboard, installDashboard as install} from 'sparc-dashboard-beta/dist/index.js'
import {default as SparcDashboard, installDashboard} from 'sparc-dashboard-beta';

const app = createApp(App);
let piniaInstance = createPinia();
app.use(piniaInstance);

installDashboard(app, piniaInstance); //call the install method and pass in the app and pinia instance
installDashboard(app, piniaInstance);//call the install method and pass in the app and pinia instance
app.component("SparcDashboard",SparcDashboard) // add the dashboard component to your vue app

app.use(sparcDesignSystemComponents2Umd);
app.mount('#app');

Expand All @@ -96,40 +96,84 @@ Clone the github repo and navigate to src/components/SampleComponent.vue

Expose Your Custom Component to the Dashboard:
- Add component tag name to the main.ts document
src/main.ts
src/main.ts or src/main.js
```
const componentMap = [
'SubjectNav',
'ImageSelector',
'ImageViewer'
'ImageSelector',
'FlatmapViewer',
'BiolucidaViewer',
'QDBGraph'
]
```

Using the component “SampleComponent”, It would look something like this:
```
const componentMap = [
'SubjectNav',
'ImageSelector',
'ImageViewer',
'ImageSelector',
'FlatmapViewer',
'BiolucidaViewer',
'QDBGraph',
'SampleComponent'
]
```

* component name should align with file name. SampleComponent.vue should be renamed and then that new name should be added in main.ts

### Template

### PROPERTIES
These are passed down to the your component (SampleComponent) from its wrapper via the props value
This is your default template. Customize however you like with html and vue 3 markup. Do not delete the header which is added via the <slot> tag
```
<template>
<!-- slot is for header & user can add icons using childIcons-->
<slot :widgetName="widgetName" :childIcons="childIcons"></slot>
**widgetName**:
name of component tag. Changing this will change the title of the wrapper. If you want a display name that is different from the file name.
Set Display name (widgetName) using emit.
```
const emit = defineEmits(['setTitle']);
emit('setTitle','New Custom Component!'); //replace with component name you want shown
<div ref="instance">
<div class="sample-component">this is a sample component
<div>
<p>more of the component goes here</p>
</div>
</div>
</div>
</template>
```
## Header

### Set Name

This line in your setup script allows you to set the header to your widget name. It does not have to match to file name.
```
const widgetName = ref('New Custom Component!');//replace with component name you want shown
```
DO NOT DELETE SLOT

This is where your header is set. Do not delete or change the name
```
<slot :widgetName="widgetName"></slot>
```

### Set Icons

There are default icons on the header. A download one and a close icon (when in edit mode).
You can add a custom icon to your widget's header and send it a function.

Here we are adding a graph icon that when clicked will alert the user.
js
```
const childIcons=shallowRef([{"comp":GraphIcon,"event":testIcon}]);
function testIcon(){alert("test icon function")};
```
html
```
<slot :widgetName="widgetName" :childIcons="childIcons"></slot>
```
A more practical case will be to open a settings window. Simply have a function that sets your settings visibility to true. See QDBGraph and it's QDBGraphSettings for a working example.

### PROPERTIES
These are passed down to the your component (SampleComponent) from its wrapper via the props value

**there are no properties available at this time


### CUSTOM EMITS/EVENTS:
Expand All @@ -152,81 +196,87 @@ Example:
let payload ={}
emit('SampleComponent-eventName',payload);
```
*see options for events you can emit that are already standard throughout the dashboard.

### OPTIONS

***setTitle:***
component ‘s name defaults to it’s vue tag-name. This allows you override it and add a different name

Example:
```
const emit = defineEmits(['setTitle']);
emit('setTitle','MUSE Image Viewer');
```

**other options to come. Examples might include a standard way of setting a filter that most widgets would find useful (age/sex/metadata for example)**

### EVENTS

***ImageSelector-selectImage***
- Thrown when image selector widget has selected an image
Example:
***ImageSelector-mbfImageSelected***
- Thrown when image selector (ImageSelector.vue) widget has selected an image
Example for use:

```
emitter.on('ImageSelector-selectImage', (value) => {
emitter.on('ImageSelector-mbfImageSelected', (value) => {
//do something
});
```
Here is an example of the SampleComponent.vue file as of 1/26/2024. See github for latest versions

```
<template>
<div ref="instance">
<!-- all markup -->
</div>
</template>
<script setup>
import { ref, defineEmits, inject, watch, onMounted, onUnmounted } from 'vue';
import { useOpenerStore } from '../stores/opener';
//allows you to emit events that can be caught by other components.
const emitter = inject('emitter');
const opener = useOpenerStore();
const props = defineProps({
widgetName:{
type:String,
required:true
}
})
const emit = defineEmits(['setTitle']);
emit('setTitle','New Custom Component!'); //replace with component name you want shown
***FlatmapViewer-selectImage***
- Thrown when user selects segment of Flatmap Viewer (FlatmapViewer.vue)
```
emitter.on('FlatmapViewer-selectImage', (selectedImage) => {
//do something
});
```

//emit and event
let payload ={}
emit('SampleComponent-eventName',payload);
## Sample Component

Here is an example of the SampleComponent.vue file as of 7/17/2024. See github for latest versions

//catch an event
// This catches when Image Selector throws the event when the image selector widget has an image selected
//see Events in documentation for all available events
emitter.on('ImageSelector-selectImage', (imagePath) => {
//do something
});
```
<template>
<!-- slot is for header & user can add icons using childIcons-->
<slot :widgetName="widgetName" :childIcons="childIcons"></slot>
<div ref="instance">
<div class="sample-component">this is a sample component
<div>
<p>more of the component goes here</p>
</div>
</div>
<!-- all markup -->
</div>
</template>
<script setup>
import { ref, defineEmits, inject, watch, onMounted, onUnmounted } from 'vue';
import GraphIcon from './icons/GraphIcon.vue';
//this is included so that your component does not inherit props or attributes that you do not explicitly declare
defineOptions({
inheritAttrs: false
})
const widgetName = ref('New Custom Component!');//replace with component name you want shown
//add icon to header. must import your icon as shown above ex: import GraphIcon from './icons/GraphIcon.vue'
//this is optional and can be deleted
const childIcons=shallowRef([{"comp":GraphIcon,"event":testIcon}]);
function testIcon(){alert("test icon function")};
//emit a custom event that you name
//if you create an event that you want available for other widgets/users, please document it under Events in the README.md
//allows you to emit events that can be caught by other components.
const emitter = inject('emitter');
let payload ={} //can be any type
emitter.emit('SampleComponent-eventName',payload);
//catch an event
// This is an active event that gets called by the ImageSelector component when a user clicks the "open" button on an image.
//see Events in documentation for all available events
emitter.on('ImageSelector-mbfImageSelected', (value) => {
//do something
});
</script>
<style scoped lang="scss">
//import SPARC styles
//import SPARC styles if you want to have access to them.
@import './node_modules/sparc-design-system-components-2/src/assets/_variables.scss';
//example of class styles
.sample-component{
height:500px;
width:400px;
border: solid purple 1px;
background-color: lightgray;
}
</style>
```

15 changes: 9 additions & 6 deletions src/components/BiolucidaViewer.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<template>
<div class="tw-flex tw-flex-col tw-h-full">

<slot :widgetName="widgetName"></slot>

<div v-bind="$attrs" class="tw-flex tw-flex-col tw-h-full">
<div class="bv-metadata tw-text-left tw-p-1 tw-text-sm">
<p><span>Dataset: </span>
<!-- <p><span>Dataset: </span>
Dataset Name Here </p>
<p><span>Metadata: </span>Metadata could go here</p>
<p><span>Metadata: </span>Metadata could go here</p> -->
</div>
<div class="tw-h-screen tw-flex tw-justify-center">
<iframe class="tw-p-1 tw-w-screen" :src="mbfURLSrc" ></iframe>
Expand All @@ -16,7 +19,8 @@
import {Dataset} from '../assets/Model';
import { useOpenerStore } from "../stores/opener";
const emit = defineEmits(['setTitle','selectWidget']);
const widgetName = ref('MBF Image Viewer');
const emit = defineEmits(['selectWidget']);
const props = defineProps({
imageID:0,
Expand All @@ -32,13 +36,12 @@
const opener = useOpenerStore();
onMounted(() => {
emit('setTitle','MBF Image Viewer');
opener.mbfViewerCount++;
});
onUnmounted(()=>{
opener.mbfViewerCount--;
})
emitter.on('mbf-image-selected',(img)=>{
emitter.on('ImageSelector-mbfImageSelected',(img)=>{
if(opener.mbfViewerCount>1 && props.listening || opener.mbfViewerCount==1){
mbfURLSrc.value=img;
}
Expand Down
55 changes: 55 additions & 0 deletions src/components/DashHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<div class="content-header stick-to-top tw-flex tw-flex-row tw-items-center tw-justify-between tw-h-10 tw-p-1">
<div>
<h3>{{ widgetName }}</h3>
</div>
<div>
<slot></slot>
</div>
</div>
</template>
<script setup>
//this component really only has one job, and it's to format the header correctly and make it easier for users to add icons to the header without much markup on their end.
//alternative markup that would be needed on all children >
// <div v-bind="$attrs">
// <slot name="title" :widgetName="widgetName"></slot>
// <div>
// <GraphIcon class="tw-p-1" @click="settingsVisible=true"></GraphIcon>
// <slot></slot>
// </div>
// </div>
import { ref, inject, computed, watch, provide} from 'vue';
const emitter = inject('emitter');
const props = defineProps({
widgetName:{
type:String,
required:true
}
})
</script>
<style scoped lang="scss">
@import './node_modules/sparc-design-system-components-2/src/assets/_variables.scss';
.content-header{
border-bottom: 1px solid $mediumGrey;
h3{
margin:10px;
}
.close-button{
cursor: pointer;
margin-right:3px;
width:20px;
height: 20px;
padding:8px;
}
}
.stick-to-top{
position: sticky;
top: 0;
width: 100%;
}
</style>
Loading

0 comments on commit bdba289

Please sign in to comment.