Images 样式调整
This commit is contained in:
parent
44f966e791
commit
a5befaf368
|
@ -0,0 +1,67 @@
|
|||
.#{$ns}Images {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: -$gap-xs;
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
margin: $gap-xs;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}Image {
|
||||
display: inline-block;
|
||||
border: $borderWidth solid $borderColor;
|
||||
padding: $gap-xs;
|
||||
|
||||
&-thumb {
|
||||
width: px2rem(108px);
|
||||
height: px2rem(108px);
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwMCIgaGVpZ2h0PSI0MDAiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CiAgICAgICAgICAgIDxyZWN0IGZpbGw9ImJsYWNrIiB4PSIwIiB5PSIwIiB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIG9wYWNpdHk9IjAuMSIgLz4KICAgICAgICAgICAgPHJlY3QgZmlsbD0id2hpdGUiIHg9IjEwIiB5PSIwIiB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIC8+CiAgICAgICAgICAgIDxyZWN0IGZpbGw9ImJsYWNrIiB4PSIxMCIgeT0iMTAiIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgb3BhY2l0eT0iMC4xIiAvPgogICAgICAgICAgICA8cmVjdCBmaWxsPSJ3aGl0ZSIgeD0iMCIgeT0iMTAiIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgLz4KICAgICAgICA8L3BhdHRlcm4+CiAgICA8L2RlZnM+CiAgICA8cmVjdCBmaWxsPSJ1cmwoI2dyaWQpIiB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiAvPgo8L3N2Zz4=');
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
> img {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
&-thumb--w-full > img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@supports (object-fit: contain) {
|
||||
&-thumb--contain > img {
|
||||
position: static;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translate(0, 0);
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (object-fit: cover) {
|
||||
&-thumb--cover > img {
|
||||
position: static;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translate(0, 0);
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}ImageField {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
|
@ -70,28 +70,19 @@
|
|||
&-item {
|
||||
border: $borderWidth solid $borderColor;
|
||||
vertical-align: top;
|
||||
padding: px2rem(5px);
|
||||
padding: $gap-xs;
|
||||
display: inline-block;
|
||||
margin-right: px2rem(15px);
|
||||
margin-bottom: px2rem(15px);
|
||||
margin-right: $gap-base;
|
||||
margin-bottom: $gap-base;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-itemImageWrap {
|
||||
width: px2rem(108px);
|
||||
height: px2rem(108px);
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwMCIgaGVpZ2h0PSI0MDAiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CiAgICAgICAgICAgIDxyZWN0IGZpbGw9ImJsYWNrIiB4PSIwIiB5PSIwIiB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIG9wYWNpdHk9IjAuMSIgLz4KICAgICAgICAgICAgPHJlY3QgZmlsbD0id2hpdGUiIHg9IjEwIiB5PSIwIiB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIC8+CiAgICAgICAgICAgIDxyZWN0IGZpbGw9ImJsYWNrIiB4PSIxMCIgeT0iMTAiIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgb3BhY2l0eT0iMC4xIiAvPgogICAgICAgICAgICA8cmVjdCBmaWxsPSJ3aGl0ZSIgeD0iMCIgeT0iMTAiIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgLz4KICAgICAgICA8L3BhdHRlcm4+CiAgICA8L2RlZnM+CiAgICA8cmVjdCBmaWxsPSJ1cmwoI2dyaWQpIiB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiAvPgo8L3N2Zz4=');
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
> img {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
&-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&-itemOverlay {
|
||||
|
|
|
@ -534,6 +534,7 @@ $Card-actions-onChecked-onHover-bg: $white;
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
@import '../components/form/group';
|
||||
|
|
|
@ -200,6 +200,7 @@ pre {
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
@import '../components/form/group';
|
||||
|
|
|
@ -65,6 +65,7 @@ $Form-input-borderColor: #cfdadd;
|
|||
@import '../components/wrapper';
|
||||
@import '../components/status';
|
||||
@import '../components/carousel';
|
||||
@import '../components/images';
|
||||
|
||||
@import '../components/form/fieldset';
|
||||
@import '../components/form/group';
|
||||
|
|
|
@ -136,6 +136,7 @@ import './renderers/Grid';
|
|||
import './renderers/HBox';
|
||||
import './renderers/VBox';
|
||||
import './renderers/Image';
|
||||
import './renderers/Images';
|
||||
import './renderers/List';
|
||||
import './renderers/Operation';
|
||||
import './renderers/Page';
|
||||
|
|
|
@ -14,6 +14,7 @@ import Button from '../../components/Button';
|
|||
// @ts-ignore
|
||||
import accepts from 'attr-accept';
|
||||
import {getNameFromUrl} from './File';
|
||||
import ImageComponent from '../Image';
|
||||
|
||||
let preventEvent = (e: any) => e.stopPropagation();
|
||||
|
||||
|
@ -990,19 +991,17 @@ export default class ImageControl extends React.Component<
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
<ImageComponent
|
||||
key="image"
|
||||
className={cx('ImageControl-itemImageWrap')}
|
||||
>
|
||||
<img
|
||||
onLoad={this.handleImageLoaded.bind(
|
||||
this,
|
||||
key
|
||||
)}
|
||||
src={file.preview || file.url}
|
||||
alt={file.name}
|
||||
/>
|
||||
</div>
|
||||
className={cx('ImageControl-image')}
|
||||
onLoad={this.handleImageLoaded.bind(
|
||||
this,
|
||||
key
|
||||
)}
|
||||
src={file.preview || file.url}
|
||||
alt={file.name}
|
||||
thumbMode="contain"
|
||||
/>
|
||||
|
||||
<div
|
||||
key="overlay"
|
||||
|
|
|
@ -1,24 +1,78 @@
|
|||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {ServiceStore, IServiceStore} from '../store/service';
|
||||
import {Api, SchemaNode} from '../types';
|
||||
import {filter} from '../utils/tpl';
|
||||
import cx from 'classnames';
|
||||
import moment from 'moment';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface ImageProps extends RendererProps {
|
||||
export interface ImageProps {
|
||||
src: string;
|
||||
title?: string;
|
||||
alt?: string;
|
||||
className?: string;
|
||||
imageClassName?: string;
|
||||
description?: string;
|
||||
thumbMode?: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
classnames: ClassNamesFn;
|
||||
classPrefix: string;
|
||||
onLoad?: React.EventHandler<any>;
|
||||
}
|
||||
|
||||
export class Image extends React.Component<ImageProps> {
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
className,
|
||||
imageClassName,
|
||||
thumbMode,
|
||||
src,
|
||||
alt,
|
||||
title,
|
||||
description,
|
||||
onLoad
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('Image', className)}>
|
||||
<div
|
||||
className={cx(
|
||||
'Image-thumb',
|
||||
thumbMode ? `Image-thumb--${thumbMode}` : ''
|
||||
)}
|
||||
>
|
||||
<img
|
||||
onLoad={onLoad}
|
||||
className={cx(imageClassName)}
|
||||
src={src}
|
||||
alt={alt}
|
||||
/>
|
||||
</div>
|
||||
{title || description ? (
|
||||
<div key="caption" className={cx('Image-caption')}>
|
||||
{title ? <div className={cx('Image-title')}>{title}</div> : null}
|
||||
{description ? (
|
||||
<div className={cx('Image-description')}>{description}</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
const ThemedImage = themeable(Image);
|
||||
export default ThemedImage;
|
||||
|
||||
export interface ImageFieldProps extends RendererProps {
|
||||
className?: string;
|
||||
imageClassName?: string;
|
||||
placeholder?: string;
|
||||
description?: string;
|
||||
thumbMode: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
}
|
||||
|
||||
export class ImageField extends React.Component<ImageProps, object> {
|
||||
static defaultProps: Partial<ImageProps> = {
|
||||
className: 'thumb-lg',
|
||||
imageClassName: 'r',
|
||||
export class ImageField extends React.Component<ImageFieldProps, object> {
|
||||
static defaultProps: Pick<ImageFieldProps, 'defaultImage' | 'thumbMode'> = {
|
||||
defaultImage:
|
||||
'https://fex.bdstatic.com/n/static/amis/renderers/crud/field/placeholder_cfad9b1.png'
|
||||
'https://fex.bdstatic.com/n/static/amis/renderers/crud/field/placeholder_cfad9b1.png',
|
||||
thumbMode: 'contain'
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -27,11 +81,11 @@ export class ImageField extends React.Component<ImageProps, object> {
|
|||
defaultImage,
|
||||
description,
|
||||
title,
|
||||
render,
|
||||
data,
|
||||
imageClassName,
|
||||
classnames: cx,
|
||||
src
|
||||
src,
|
||||
thumbMode
|
||||
} = this.props;
|
||||
|
||||
const finnalSrc = src ? filter(src, data, '| raw') : '';
|
||||
|
@ -39,18 +93,13 @@ export class ImageField extends React.Component<ImageProps, object> {
|
|||
|
||||
return (
|
||||
<div className={cx('ImageField', className)}>
|
||||
<img
|
||||
className={imageClassName}
|
||||
<ThemedImage
|
||||
imageClassName={imageClassName}
|
||||
src={finnalSrc || value || defaultImage}
|
||||
title={filter(title, data)}
|
||||
description={filter(description, data)}
|
||||
thumbMode={thumbMode}
|
||||
/>
|
||||
{title || description ? (
|
||||
<div key="caption" className={cx('ImageField-caption')}>
|
||||
{title ? (
|
||||
<div className="text-md">{filter(title, data)}</div>
|
||||
) : null}
|
||||
{render('description', description as string)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -61,18 +110,3 @@ export class ImageField extends React.Component<ImageProps, object> {
|
|||
name: 'image'
|
||||
})
|
||||
export class ImageFieldRenderer extends ImageField {}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)images$/
|
||||
})
|
||||
export class ImagesFieldRenderer extends ImageField {
|
||||
static defaultProps: Partial<ImageProps> = {
|
||||
...ImageField.defaultProps,
|
||||
multiple: true,
|
||||
delimiter: ','
|
||||
};
|
||||
|
||||
render() {
|
||||
return <p>Todo</p>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {resolveVariable, isPureVariable} from '../utils/tpl-builtin';
|
||||
import Image from './Image';
|
||||
|
||||
export interface ImagesProps extends RendererProps {
|
||||
className: string;
|
||||
defaultImage: string;
|
||||
placeholder: string;
|
||||
delimiter: string;
|
||||
thumbMode: 'w-full' | 'h-full' | 'contain' | 'cover';
|
||||
name?: string;
|
||||
value?: any;
|
||||
source?: string;
|
||||
}
|
||||
|
||||
export class ImagesField extends React.Component<ImagesProps> {
|
||||
static defaultProps: Pick<
|
||||
ImagesProps,
|
||||
'className' | 'delimiter' | 'defaultImage' | 'placehoder' | 'thumbMode'
|
||||
> = {
|
||||
className: '',
|
||||
delimiter: ',',
|
||||
defaultImage:
|
||||
'https://fex.bdstatic.com/n/static/amis/renderers/crud/field/placeholder_cfad9b1.png',
|
||||
placehoder: '-',
|
||||
thumbMode: 'contain'
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
defaultImage,
|
||||
thumbMode,
|
||||
data,
|
||||
name,
|
||||
value,
|
||||
placeholder,
|
||||
classnames: cx,
|
||||
source,
|
||||
delimiter
|
||||
} = this.props;
|
||||
|
||||
let list: any;
|
||||
|
||||
if (typeof source === 'string' && isPureVariable(source)) {
|
||||
list = resolveVariable(source, data) || undefined;
|
||||
} else if (Array.isArray(value)) {
|
||||
list = value;
|
||||
} else if (name && data[name]) {
|
||||
list = data[name];
|
||||
}
|
||||
|
||||
if (typeof list === 'string') {
|
||||
list = list.split(delimiter);
|
||||
} else if (list && !Array.isArray(list)) {
|
||||
list = [list];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('ImagesField', className)}>
|
||||
{Array.isArray(list) ? (
|
||||
<div className={cx('Images')}>
|
||||
{list.map((item: any, index: number) => (
|
||||
<Image
|
||||
className={cx('Images-item')}
|
||||
key={index}
|
||||
src={(item && item.image) || item}
|
||||
title={item && item.title}
|
||||
description={item && item.description}
|
||||
thumbMode={thumbMode}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : defaultImage ? (
|
||||
<Image
|
||||
className={cx('Images-item')}
|
||||
src={defaultImage}
|
||||
thumbMode={thumbMode}
|
||||
/>
|
||||
) : (
|
||||
placeholder
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)images$/
|
||||
})
|
||||
export class ImagesFieldRenderer extends ImagesField {}
|
|
@ -12,7 +12,7 @@ export function reigsterTplEnginer(name: string, enginer: Enginer) {
|
|||
}
|
||||
|
||||
export function filter(
|
||||
tpl: string,
|
||||
tpl?: string,
|
||||
data: object = {},
|
||||
...rest: Array<any>
|
||||
): string {
|
||||
|
|
Loading…
Reference in New Issue