Skip to content

Commit

Permalink
Merge pull request #11 from dennispassway/aadgrant-custom-field-support
Browse files Browse the repository at this point in the history
Aadgrant custom field support
  • Loading branch information
dennispassway authored Jan 18, 2021
2 parents a1adcc9 + d66940e commit 31f326c
Show file tree
Hide file tree
Showing 12 changed files with 380 additions and 222 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## 1.0.3

- Add support for `customFields` in config object.
- Add multiple input field options
48 changes: 44 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The missing media library for Sanity. With support for filters per tag and exten
- View/Edit your assets in once single place:
- View asset details
- Add alt tags to your image in a central place
- Easily add custom fields to your assets (like location and attribution)
- Grid view and list view (with more details):
- Sort by latest or alphabetically
- Search by alt, tag, or file name
Expand All @@ -29,6 +30,8 @@ The missing media library for Sanity. With support for filters per tag and exten
- Asset source:
- Use it where it's useful: select images with the media library in your documents
- Quick action: Double click an asset to trigger it's primary action
- Customizable fields
- Define custom fields for your assets (text, number, checkbox, textarea)
- Customizable theme:
- Comes with a dark and light theme, both are fully customizable.

Expand Down Expand Up @@ -113,7 +116,7 @@ export default {
],
};

````
````

See [Sanity Custom Asset Sources](https://www.sanity.io/docs/custom-asset-sources) for more options.

Expand Down Expand Up @@ -142,9 +145,46 @@ Example with themeChanges:
}
```

## Roadmap
Find the roadmap in [Github Projects](https://github.com/dennispassway/sanity-plugin-media-library/projects/1).
Example with asset fields listed and custom fields added:
```json
{
"theme": "dark",
"themeChanges": {},
"customFields": [
{
"label": "Additional description",
"name": "description",
"placeholder": "No description yet...",
"type": "textarea"
},
{
"label": "Decade when photo captured",
"max": 2200,
"min": 1800,
"name": "decade",
"placeholder": "Between 1800 and 2200",
"step": 10,
"type": "number"
},
{
"label": "Is a premium photo",
"name": "premiumPhoto",
"type": "checkbox"
},
{
"label": "Attribution",
"name": "attribution",
"placeholder": "No attribution yet"
},
{
"name": "location",
"label": "Location",
"type": "location"
}
],
}
```

## Contributing
To contribute a theme, add it in `themes/[themename].ts`.
If you run into problems or have feature requests, please create an issue or pull request and I'll look into it as soon as I can.
If you run into problems or have feature requests, please create an issue or pull request and I'll look into it as soon as I can.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sanity-plugin-media-library",
"description": "The missing media library for Sanity. With filters per tag and filtetype. And it's fully themeable.",
"version": "1.0.2",
"version": "1.0.3",
"license": "MIT",
"author": "Dennis Passway",
"main": "lib/index.js",
Expand Down Expand Up @@ -37,15 +37,15 @@
"@babel/cli": "7.12.10",
"@babel/core": "7.12.10",
"@babel/plugin-proposal-object-rest-spread": "7.12.1",
"@babel/preset-env": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "7.12.10",
"@babel/preset-typescript": "7.12.7",
"@types/react": "17.0.0",
"@types/styled-components": "^5.1.5",
"@types/styled-components": "^5.1.7",
"babel-plugin-styled-components": "^1.12.0",
"prettier": "^2.2.1",
"rimraf": "^3.0.2",
"typescript": "4.1.2"
"typescript": "4.1.3"
},
"peerDependencies": {
"@sanity/base": ">= 2.0.2",
Expand Down
38 changes: 27 additions & 11 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { acceptedFileTypes } from './shared/acceptedFileTypes';
import { Asset } from './types/Asset';
import { AssetModal } from './components/AssetModal';
import { customFields } from './config';
import { DeleteModal } from './components/DeleteModal';
import { ErrorNotifications } from './components/ErrorNotifications';
import { MediaLibrary } from './components/MediaLibrary';
Expand Down Expand Up @@ -57,11 +58,10 @@ export const App = ({ onClose, onSelect, selectedAssets, tool }: Props) => {
let newFilteredAssets = [...assets];

if (searchQuery && searchQuery !== '') {
newFilteredAssets = newFilteredAssets.filter(
({ alt, originalFilename, tags }) =>
originalFilename.toUpperCase().indexOf(searchQuery.toUpperCase()) > -1 ||
(alt || '').toUpperCase().indexOf(searchQuery.toUpperCase()) > -1 ||
(tags?.join(',') || '').toUpperCase().indexOf(searchQuery.toUpperCase()) > -1
newFilteredAssets = newFilteredAssets.filter(({ alt = '', originalFilename = '', title = '', tags = [] }) =>
[originalFilename, title, alt, tags.join('')].some(
(value) => value.toUpperCase().indexOf(searchQuery.toUpperCase()) > -1
)
);
}

Expand All @@ -78,11 +78,15 @@ export const App = ({ onClose, onSelect, selectedAssets, tool }: Props) => {
}

if (sort === 'az') {
newFilteredAssets.sort((a, b) => (a.originalFilename.localeCompare(b.originalFilename) ? -1 : 1));
newFilteredAssets.sort((a, b) =>
(a.title || a.originalFilename).localeCompare(b.title || b.originalFilename) ? -1 : 1
);
}

if (sort === 'za') {
newFilteredAssets.sort((a, b) => (a.originalFilename.localeCompare(b.originalFilename) ? 1 : -1));
newFilteredAssets.sort((a, b) =>
(a.title || a.originalFilename).localeCompare(b.title || b.originalFilename) ? 1 : -1
);
}

setFilteredAssets(newFilteredAssets);
Expand Down Expand Up @@ -111,10 +115,22 @@ export const App = ({ onClose, onSelect, selectedAssets, tool }: Props) => {
try {
setLoading(true);
const types = tool ? '"sanity.imageAsset", "sanity.fileAsset"' : '"sanity.imageAsset"';
const newAssets: Array<Asset> = await client.fetch(
`*[_type in [${types}]] { _createdAt, _id, _type, alt, extension, metadata, originalFilename, size, tags, url }`,
{}
);
const includedFields = [
'_createdAt',
'_id',
'_type',
'alt',
'extension',
'metadata',
'originalFilename',
'title',
'size',
'tags',
'url',
...customFields.map(({ name }: { name: string }) => name),
];

const newAssets: Array<Asset> = await client.fetch(`*[_type in [${types}]] { ${includedFields.join(',')} }`, {});
setAssets(newAssets);
} catch (e) {
handleError(e);
Expand Down
64 changes: 42 additions & 22 deletions src/components/AssetModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Asset } from '../types/Asset';
import { Button } from './Button';
import { customFields } from '../config';
import { formatDate, formatSize } from '../shared/utils';
import { Icon } from './Icon';
import { LabelWithInput } from './LabelWithInput';
Expand Down Expand Up @@ -87,6 +88,10 @@ const StyledInfoContainer = styled.div`
`;

const StyledInputsContainer = styled.div`
padding-right: 8px !important;
max-height: 300px;
overflow: hidden scroll;
& > :not(:last-child) {
margin: 0 0 20px;
}
Expand All @@ -102,30 +107,50 @@ const StyledButtonsContainer = styled.div`
`;

export const AssetModal = ({ asset, loading, handleError, onClose, onSaveComplete, setLoading }: Props) => {
const { _createdAt, _id, _type, alt, extension, metadata, originalFilename, size, tags, url } = asset;
const { _createdAt, _id, _type, alt, extension, metadata, originalFilename, size, tags, title, url } = asset;
const { height, width } = metadata?.dimensions || {};
const [localAlt, setLocalAlt] = useState<string>(alt || '');
const [localTags, setLocalTags] = useState<string>((tags || []).join(',') || '');
const [localValues, setLocalValues] = useState<{ [key: string]: any }>({
alt,
tags: tags?.join(','),
title,
});

const inputFields = [
{ name: 'title', label: 'Title', placeholder: 'No title yet' },
{ name: 'alt', label: 'Alt text', placeholder: 'No alt text yet' },
{ name: 'tags', label: 'Tags', placeholder: 'No tags yet' },
...customFields,
];

const isChanged = Object.entries(localValues).some(([key, newValue]) => {
const currentValue = asset[key];

if (newValue === '' && typeof currentValue === 'undefined') {
return false;
}

const isChanged = localAlt !== (alt || '') || localTags !== (tags?.join(',') || '');
return newValue !== currentValue;
});

async function handleSubmit(e: FormEvent) {
try {
e.preventDefault();

if (loading) {
return;
}

setLoading(true);
e.preventDefault();

if (!isChanged) {
return onClose();
}

const alt = localAlt;
const tags = localTags.split(',').map((v) => v.trim());

await client.patch(_id).set({ alt, tags }).commit();
const tags = localValues.tags?.split(',').map((v: string) => v.trim());
await client
.patch(_id)
.set({ ...localValues, tags })
.commit();
onSaveComplete();
} catch (e) {
handleError(e);
Expand All @@ -148,7 +173,8 @@ export const AssetModal = ({ asset, loading, handleError, onClose, onSaveComplet
)}
</StyledThumbnailContainer>
<StyledInfoContainer>
<strong>{originalFilename}</strong>
<strong>{localValues.title || originalFilename}</strong>
<br />
{formatDate(_createdAt)}
<br />
{width && height && (
Expand All @@ -162,20 +188,14 @@ export const AssetModal = ({ asset, loading, handleError, onClose, onSaveComplet
</StyledImageInfoContainer>

<StyledInputsContainer>
{_type === 'sanity.imageAsset' && (
{inputFields.map(({ name, ...rest }) => (
<LabelWithInput
label="Alt text"
onChange={setLocalAlt}
placeholder={!localAlt ? 'No alt text yet...' : undefined}
value={localAlt}
key={name}
onChange={(value: any) => setLocalValues({ ...localValues, [name]: value })}
value={localValues[name]}
{...rest}
/>
)}
<LabelWithInput
label="Tags"
onChange={setLocalTags}
placeholder={!localTags ? 'No tags yet...' : undefined}
value={localTags}
/>
))}
</StyledInputsContainer>

<StyledButtonsContainer>
Expand Down
Loading

0 comments on commit 31f326c

Please sign in to comment.